`
- 浏览:
17696 次
- 性别:
- 来自:
北京
-
JAVA反射机制入门(二)--getMethods()系列方法特例详解
昨天在研究getDeclaredMethod(String name,Class<?>... parameterTypes)API时,发现这么一段话:
The name parameter is a String that specifies the simple name of the desired method, and the parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order. If more than one method with the same parameter types is declared in a class, and one of these methods has a return type that is [color=blue]more specific than any of the others, that method is returned; otherwise one of the methods is chosen arbitrarily[/color]. If the name is "<init>"or "<clinit>" a NoSuchMethodException is raised.
就此产生了疑问,如果指定了方法的名字和参数的类型,为什么还可能会得到多个方法,java中不是不允许同名同参的overloaded吗?接着在getMethod()的API中找到了答案:
Note that there may be more than one matching method in a class because while the Java language forbids a class to declare multiple methods with the same signature but different return types, the Java virtual machine does not. This increased flexibility in the virtual machine can be used to implement various language features. For example, covariant returns can be implemented with bridge methods ; the bridge method and the method being overridden would have the same signature but different return types.
java语言本身规定同名同参即使返回值不同,不能构成重载,但是JVM不这么认为,它认为返回值的不同可以构成重载。
这里介绍两个概念:
一.convariant return type:
当导出类中的'overriding'方法的返回类型是基类的'overrided'方法的返回类型的导出类,即如下关系:
package classTest;
class A {
A(){System.out.println("A");}
}
class B extends A {
B(){System.out.println("B");}
}
// Classes demonstrating method overriding:
class C<T extends A> {
T a;
public void setFoo(T t){
this.a = t;
}
public T getFoo() {
return a;
}
}
class D extends C<B> {
public void setFoo(B b){
super.a = b;
}
public B getFoo() {
return super.getFoo();
}
}
你可能会认为D中的getFoo()会overrideC中的getFoo(),但是在正常情况下,JAVA语言认为这个构成了override,但是JVM会认为这个仅构成了overload。也就是说对于JVM这个相当于在D中包含了两个getFoo(),仅靠返回类型来区分。因此当执行下面代码时:
D dd = new D();
Class d = dd.getClass();
Class<?>[] p = null;
Method m = d.getMethod("getFoo");
System.out.println(m.getReturnType().getName());
getMehod(“getFoo”)由于方法名和参数完全相同会得到两个getFoo,因此只能根据更精确的返回类型(上面提示的more specific)来找到那个方法。
这里需要说明一下对于泛型只是针对编译器的,JVM是不支持泛型的。JVM中的类都是raw type的,即没有类型参数的。编译器会将所有的类型进行擦除,擦除规则:如果仅仅是<?>,将所有的<?>对应的类型替换为java.lang.Object;如果有<T extends SuperClass>,则将所有的<T>替换为SuperClass;对于方法泛型方法调用处,会将Object换成具体对应的类。如上面的类C,经过编译器擦除后为:
class classTest.C extends java.lang.Object{
//域
classTest.A a;
//构造器
C( );
//方法
public void setFoo(classTest.A);
public classTest.A getFoo( );
}
可以看到所有的T被classTest.A替换
二.bridge methods
对D做进一步分析,得到编译对D的翻译结果如下:
class classTest.D extends classTest.C{
//域
//构造器
D( );
//方法
public void setFoo(classTest.B);
public volatile void setFoo(classTest.A);
public classTest.B getFoo( );
public volatile classTest.A getFoo( );
可以看到增加了一个public volatile的方法。这个方法是我们没有定义的,是由编译器增加的,这个就是bridge method。当你调用dd.getFoo()时,实际调用的是这个增加的方法,而在这个方法中调用D中的getFoo方法:
public volatile classTest.A getFoo( ){
return this.getFoo();
}
因此,从外部看来仿佛就是D中的getFoo()重写了C中的getFoo()。
如果不信,可以在D中增加一个方法如下:
public void setFoo(A a){
this.setFoo((B)a);
}
编译器会提示有冲突。
Name clash: The method setFoo(A) of type D has the same erasure as setFoo(T) of type C<T> but does not override it
从JDK1.5开始,在一个方法覆盖另一个方法时可以指定一个更严格的返回类型,它的机制也是同样使用的桥方法。子类在覆盖父类的方法可以指定更为严格的返回类型,如例中C中返回的是A,D中返回的是B,编译器增加桥方法来间接的完成override。
还是重申一点对于D中和C的重名方法事实上在JVM中是overload的方法,是依靠返回值区分的。编译器动态增加了一个‘桥方法’对C中的getFoo()进行override,而在该函数内部间接调用了D的getFoo()方法。而用户实际调用的是这个‘桥方法’,因此看起来D的getFoo()对C的getFoo()进行了override。
分享到:
Global site tag (gtag.js) - Google Analytics
相关推荐
### Java反射机制详解 #### 一、反射机制是什么 反射机制是Java编程语言的一个核心特性,它允许程序在运行时动态地获取类的信息,并且能够动态地创建对象和调用对象的方法。简单来说,反射机制使得Java程序可以...
Java反射机制是Java语言提供的一种强大的工具,它允许程序在运行时检查类、接口、字段和方法的信息,甚至能够在运行时动态地创建和修改对象。本文将深入探讨反射机制的概念、用途、优缺点以及如何使用反射来获取类的...
总的来说,"JAVA反射机制的入门代码"是初学者理解Java反射机制的好教材,通过它,你可以学习如何动态地操作Java类,提高代码的灵活性,并掌握处理`properties`文件的基础方法。在深入学习和实践中,你将进一步理解...
"Java 反射机制详解" Java 反射机制是在运⾏状态中,对于任意⼀个类,都能够知道这个类的所有属性和⽅法;对于任意⼀个对象,都能够调⽤它的任意⼀个⽅法和属性;这种动态获取的信息以及动态调⽤对象的⽅法的功能...
Java反射机制是Java语言的一项强大功能,它允许程序在运行时动态地获取类的信息并操作类的对象。这一特性使得Java具有高度的灵活性和强大的扩展性,尤其是在开发框架和库时,反射机制起到了至关重要的作用。本文将...
### JAVA反射机制详解 #### 一、Java反射机制概述 Java反射机制是在运行时动态获取类的信息,并且能够调用对象方法的一种强大的功能。通过Java反射机制,可以在运行时完成以下任务: - 判断任意一个对象所属的类...
Java 反射机制详解 Java 反射机制是 Java 语言提供的一种强大的工具,它允许程序在运行时动态地获取类的信息(如类名、属性、方法等)并进行操作。这种能力使得 Java 应用程序更加灵活,能够在运行时发现和修改自身...
### Java反射机制详解 #### 一、反射的基本概念与历史背景 反射的概念最早由Smith在1982年提出,其核心思想是程序有能力访问、检测甚至修改自身的状态和行为。这种能力一经提出,迅速成为了计算机科学领域的研究...
Java反射机制是Java语言提供的一种强大功能,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类是java.lang.Class,它代表了运行时的类信息。通过Class对象,我们...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查并操作类、接口、字段和方法的信息,打破了通常编译时静态绑定的限制。通过反射,我们可以动态地创建对象,调用方法,访问和修改字段值,甚至...
### Java反射机制详解 #### 一、引言 Java反射机制是Java语言中一项重要的功能,使得Java在一定程度上具备了动态语言的特性。通过Java反射机制,可以在运行时获取类的信息并操作类的对象,这为Java应用开发带来了...
通过Java反射机制,开发者可以在不知道具体类名的情况下创建对象,调用方法,访问和修改私有成员变量,以及执行其他动态操作。这一机制为Java提供了高度的灵活性和强大的元数据访问能力,尤其是在框架、插件系统和...
Java反射机制是Java编程语言中的一个强大特性,它允许程序在运行时检查和操作类、接口、对象等的内部结构。通过反射,开发者可以动态地获取类的信息并调用其方法,创建对象,访问私有成员,甚至改变类的行为。在深入...
Java 反射机制实例详解是一种动态语言机制,允许在程序运行时加载、探知和使用编译期间完全不知道的类、生成其对象实体,调用其方法或者对属性设值。下面是 Java 反射机制实例详解的知识点: 1. 反射机制的概念 ...
Java反射机制是Java编程语言中的一个重要特性,它允许程序在运行时获取和操作任何已知名称的类的内部信息。这一机制使得Java具备了一定的动态性,虽然在传统的分类中Java被视为静态类型语言。通过反射,开发者可以在...
### Java反射机制详解 #### 一、什么是Java的反射机制 Java反射机制是Java语言的一种重要特性,使得Java成为了一种动态性很强的语言。通过反射,可以在程序运行时获取类的信息,包括类名、父类、接口、字段、方法...
Java反射机制是Java语言中的一种强大的工具,它允许程序在运行时动态地获取类的信息并操作类的对象。以下是对Java反射机制的详细解析: 1. 获取对象建模类的类型: - `getclass()`方法:每个Java对象都有`getclass...
Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...