【Java基础】反射与泛型
能够分析类能力的程序称之为反射()。
反射库( )提供了一个丰富且精巧的工具集boolean java lang,可以用来编写能够动态操控Java代码的程序。
主要作用有:
获取类对象的三种方式
实例.getClass();
Class.forName("java.lang.Object");
类.class;
利用反射分析类的能力Class
所有类运行时的抽象。
Field[] getFields():返回这个类与超类的公共字段;
Field[] getDeclaredFields():返回这个类的所有字段,否则返回一个长度为0的数组;
Method[] getMethods():返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有公共方法,包括由类或接口声明的方法以及从超类和超接口继承的方法;
Method[] getDeclaredMethods():返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有声明方法,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法;
Constructor[] getConstructors():返回一个包含构造函数对象的数组,该构造函数对象反映由此class对象表示的类的所有公共构造函数;
Constructor[] getDeclaredConstructors():全部构造器函数;
String getPackageName():得到包含这个类型的所有包名;如果是一个基本类型,则返回 "java.lang";
...
Field
类的字段。
Object get(Object obj):返回obj这个类此字段的值;
void set(Object obj, Object newValue):修改此对象该字段的值;
类的方法。
Object invoke(Object obj, Object... args);
类的构造器。
Object newInstance(Object... params);
分析修饰符。
public static boolean isPublic(int mod);
public static boolean isPrivate(int mod);
public static boolean isAbstract(int mod);
public static boolean isNative(int mod);
public static boolean isVolatile(int mod);
public static boolean isSynchronized(int mod);
public static boolean isStrict(int mod);
...
此外反射包下还有Array、等类,也有很强的能力。
利用反射获取泛型java.lang.Class
TypeVariable<Class>[] getTypeParameters():如果这个类型声明为泛型类型,则获得泛型类型变量,否则获得一个长度为为0的数组;
Type getGenericSuperclass():获得这个类型所声明超类的泛型类型;如果这个类型是Obejct或不是类类型(class type),则返回null;
Type[] getGenericInterfaces():获得这个类型所声明接口的泛型类型(按照声明的顺序),否则,如果这个类型没有实现接口,返回长度为0的数组;
java.lang..
TypeVariable[] getTypeParameters():如果这个方法被声明为一个泛型方法,则获得泛型类型变量,否则返回长度为0的数组;
Type getGenericReturnType():获得这个方法声明的泛型返回类型;
Type[] getGenericParameterTypes():获得这个方法声明的泛型参数类型,如果这个方法没有参数,则返回一个长度为0的数组;
java.lang..
String getName():获得这个类型变量的名字;
Type[] getBounds():获得这个类型变量的子类限定,否则,如果该类没有子类限定,返回长度为0的数组;
java.lang..
Type[] getUpperBounds():获得这个类型变量的子类限定,否则,如果没有子类限定,返回长度为0的数组;
Type[] getLowerBounds():获得这个类型变量的超类限定,否则,如果没有超类限定,返回长度为0的数组;
java.lang..
Type getRawType():获得这个参数化类型的原始类型;
Type[] getActualTypeArguments():获得这个参数化类型声明的类型参数;
Type getOwnerType():如果是内部类型,则返回外部类类型;如果是一个顶级类型,则返回null;
java.lang..
Type getGenericComponentType():获得这个数组类型所声明的泛型元素类型;

Java的泛型的本质是参数化类型( Type)或者参数化多态( )的应用,即一种既可以将操作数据类型指定为方法签名中的一种特殊参数,这种参数类型能够用在类、接口和方法的创建中,分别构成泛型类、泛型接口、泛型方法,以增强语言类型系统以及抽象能力。也是一种语法糖。
这种泛型实现方式称之为“类型擦除式泛型(Type )”,与C#的”具现化式泛型( )”相对。
类型擦除
编译期间Java编译器会将类型参数替换为其上界(类型参数中子句的类型),如果上界没有定义,则默认为boolean java lang,这就叫做类型擦除。
裸类型
裸类型被视为所有类型泛型化的共同父类型。
泛型擦除前:
Map map = new HashMap();
map.put("a", "b");
System.out.println(map.get(a));
泛型擦除后:
Map map = new HashMap();
map.put("a", "b");
System.out.println(map.get(a));
类型擦除的利弊
弊:
利:
桥方法
Java中的桥接方法( )是一种为了实现某些Java语言特性而由编译器自动生成的方法。
我们可以通过类的方法来判断一个方法是否是桥接方法。
在字节码文件中,桥接方法会被标记为和:
什么时候生成桥方法?
为了实现哪些Java语言特性会生成桥接方法?最常见的两种情况就是协变返回值类型和类型擦除【Java基础】反射与泛型,因为它们导致了父类方法的参数和实际调用的方法参数类型不一致。下面我们通过两个例子更好地理解一下。
注意:静态方法与升级修饰符不会生成桥接方法。
协变返回类型
协变返回类型是指子类方法的返回值类型不必严格等同于父类中被重写的方法的返回值类型,而可以是更 “具体” 的类型。
在Java 1.5添加了对协变返回类型的支持,即子类重写父类方法时,返回的类型可以是子类方法返回类型的子类。下面看一个例子:
public class Parent {
Number get() {
return 1;
}
}
public class Child extends Parent {
@Override
Integer get() {
return 1;
}
}

Child类重写其父类的get方法,的get方法返回类型为,而Child类中get方法返回类型为。
将这段代码进行编译,再反编译:
javac Child.java
javap -v -c Child.class
结果如下:
public class Child extends Parent
......省略部分结果......
java.lang.Integer get();
descriptor: ()Ljava/lang/Integer;
flags:
Code:
stack=1, locals=1, args_size=1
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: areturn
LineNumberTable:
line 5: 0
java.lang.Number get();
descriptor: ()Ljava/lang/Number;
flags: ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokevirtual #3 // Method get:()Ljava/lang/Integer;
4: areturn
LineNumberTable:
line 1: 0
从上面的结果可以看到,有一个方法java.lang. get(), 在源码中是没有出现过的,是由编译器自动生成的,该方法被标记为和,就是我们前面所说的桥接方法。
这个方法就起了一个桥接的作用,它所做的就是把对自身的调用通过指令再调用方法java.lang. get()。
**编译器这么做的原因是什么呢?**因为在JVM方法中,返回类型也是方法签名的一部分【Java基础】反射与泛型,而桥接方法的签名和其父类的方法签名一致,以此就实现了协变返回值类型。
类型擦除
泛型是Java 1.5才引进的概念,在这之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容,这是为什么呢?
这是因为,在编译期间Java编译器会将类型参数替换为其上界(类型参数中子句的类型),如果上界没有定义,则默认为,这就叫做类型擦除。
当一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法,例如:
public class Parent {
void set(T t) {
}
}
public class Child extends Parent {
@Override
void set(String str) {
}
}
Child类在继承其父类的泛型方法时,明确指定了泛型类型为,将这段代码进行编译,再反编译:
public class Child extends Parent
......省略部分结果......
void set(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags:
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 5: 0
void set(java.lang.Object);
descriptor: (Ljava/lang/Object;)V
flags: ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #2 // class java/lang/String
5: invokevirtual #3 // Method set:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 1: 0
从上面的结果可以看到,有一个方法void set(java.lang.), 在源码中是没有出现过的,是由编译器自动生成的,该方法被标记为和,就是我们前面所说的桥接方法。
这个方法就起了一个桥接的作用,它所做的就是把对自身的调用通过指令再调用方法void set(java.lang.)。
**编译器这么做的原因是什么呢?**因为类在类型擦除之后boolean java lang,变成这样:
public class Parent {
void set(Object t) {
}
}
编译器为了让子类有一个与父类的方法签名一致的方法,就在子类自动生成一个与父类的方法签名一致的桥接方法。
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299
资源库 - 资源分享下载网 » 【Java基础】反射与泛型
常见问题FAQ
- 关于资源售价和售后服务的说明?
- 代码有没有售后服务和技术支持?
- 有没有搭建服务?
- 链接地址失效了怎么办?
- 关于解压密码

