黑马程序员_高新技术_1_Java反射

------- android培训java培训、期待与您交流! ----------

0.反射知识体系


下图为反射整体的知识体系,把握住此图也就全局上掌握住反射所有内容。
黑马程序员_高新技术_1_Java反射

1.反射概论


1)反射概念

其实字面上可以这么理解反射,平时使用类时都是由类new出对象,而反射则是通过对象“反射”出类的信息,好比一个人照镜子可以看到人类的特征,而看出机制就是镜子反射。

2)Java对象两种类型

Java程序中的许多对象在运行时会出现两种类型:编译时类型运行时类型如下代码:
Person p = new Student();
这行代码将会生成p变量,该变量编译时的类型为Person,运行时的类型为Student;更极端情况是程序在运行时接收到外部传入的一个对象,该对象的编译时类型为Object,但程序又要调用该对象运行时的类型的方法,造成严重错误。
解决上述问题有两种方法:
       (1)假设在编译时和运行时都完全知道类型的具体信息,在这种情况下,可以直接使用instanceof运算符进行判断,再利用强制类型转换将其转换成
                 运行时类型的变量即可。
       (2)编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,必须使用用到反射。
以下为详细代码:
import java.lang.reflect.Method;

class Person{
	public void speak(){
		System.out.println("I am a person");
	}
}
class Student extends Person{
	public void speak(){
		//覆盖父类方法
		System.out.println("I am a student");
	}
	//子类新添加方法
	public void study(){
		System.out.println("Student can study");
	}
}
public class PSTest {
	public static void main(String[] args) throws Exception{
		Person p = new Student();
		//直接调用报错,因为Person中没有study()方法
		//p.study();
		
		//第1种解决方法:判断并强制转换类型
		if(p instanceof Student){
			Student s = (Student)p;
			s.study();	
		}
		
		//第2种解决方法:运行得到该对象及类信息
		Class<?> clazz = p.getClass();
		//得到类名
		System.out.println(clazz.getName());
		//甚至直接调用方法
		Method m = clazz.getMethod("study");
		m.invoke(p);	
	}
}


2.反射框架

Java任何技术都离不开包、接口、类、枚举、异常、错误、注解,下面介绍反射用到的上述所有东西,我把它们的集合称为反射框架。以下只会全局性说明,不会涉及细节,以求对反射框架整体把握,但是此处开始要对每个类型都进行深入学习,尤其是类和接口部分(具体参见JavaSE在线API(英文版)

1)lang包中的反射类

(1)Class<T>

类是对同一类事物的相同属性和方法抽象,如Person类是对所有人具有属性和方法的抽象,而Class则是对所有Java相同属性和方法的抽象,如每个类都可有所属的包、名称、字段、方法、构造器等特征,而把这些特征抽象出来就是Class。官方解释如下:Instances of the class Class represent classes and interfaces in a running Java application.
Class类的对象对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的的字节码等等。

(2)Package         

Package 对象包含有关 Java 包的实现和规范的版本信息。

2)反射包-java.lang.reflect(基于JavaSE 6)


(1)接口摘要(共9个)

a. AnnotatedElement  表示目前正在此 VM 中运行的程序的一个已注释元素。
b. GenericArrayType  GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。
c. GenericDeclaration  声明类型变量的所有实体的公共接口。
d. InvocationHandler  InvocationHandler 是代理实例的调用处理程序 实现的接口。
e. Member  成员是一种接口,反映有关单个成员(字段或方法)或构造方法的标识信息。
f. ParameterizedType  ParameterizedType 表示参数化类型,如 Collection<String>。
g. Type  Type 是 Java 编程语言中所有类型的公共高级接口。
h. TypeVariable<D extends GenericDeclaration>  TypeVariable 是各种类型变量的公共高级接口。
i. WildcardType  WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。

(2)类摘要(共8个)

a. AccessibleObject  AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。
b. Array  Array 类提供了动态创建和访问 Java 数组的方法。
c. Constructor<T>  Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。
d. Field  Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
e. Method  Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
f. Modifier  Modifier 类提供了 static 方法和常量,对类和成员访问修饰符进行解码。
g. Proxy  Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
h. ReflectPermission  反射操作的 Permission 类。

(3)异常摘要(共3个)

a. InvocationTargetException  InvocationTargetException 是一种包装由调用方法或构造方法所抛出异常的经过检查的异常。
b. MalformedParameterizedTypeException  当反射方法遇到语义错误的参数化类型,而反射方法需要实例化该类型时,抛出该异常。
c. UndeclaredThrowableException  如果代理实例的调用处理程序的 invoke 方法抛出一个经过检查的异常(不可分配给 RuntimeException 或 Error 的 Throwable),且该异常不可分配给该方法(在代理实例上调用该方法,并将其指派到调用处理程序)的 throws 子句中声明的任何异常类,则由代理实例上的方法调用抛出此异常。

(4)错误摘要(共1个)

GenericSignatureFormatError  当需要解释类型、方法或构造方法的一般签名信息的反射方法遇到语法错误的签名属性时,抛出该错误。

3.  反射操作-查看类信息


1)获得Class对象

每个类加载之后,系统就会为该类生成对应的Class对象,通过该Class对象就可以访问到JVM中的这个类,Java程序中获取Class对象有如下3种方式:

(1)Class类的静态方法forName(String clazzName),字符串参数的值是某个类的全限定类名,必须添加完整包名,注:此方法还有另一种重载形式。

(2)调用某个类的class属性来获取该类对应的Class对象,如Person.class将会返回Person类对应的Class对象。
(3)调用某个对象的getClass()方法。该方法是java.lang.Object类中的方法,所有对象都可调用该方法,将返回对象所属类对应的Class对象。
第1种方式与第2种方式都是通过类直接取得该类的Class对象,相比第2种方式有如下两种优势:
(1)代码更加安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。
(2)程序性能更好,无须调用方法。

如果只有类的字符串如“java.lang.String”获取该字符串对应的Class对象,只能使用第1种方式,此方法可能抛出ClassNotFoundException异常。一旦获得某个类对应的Class对象,就可以调用Class对象的方法来获得该对象和该类的真实信息。


2)获得Class信息

Class类提供了大量的实例方法来获取Class对象所对应类的详细信息,大致包含如下方法,每个方法又包含多种重载版本:

(1)获取Class对象对应类包含的构造器

a. Constructor<?>[] getConstructors():返回此Class对象对应类的所有public构造器。 

b.Constructor<T> getConstructor(Class<?>... parameterTypes):返回此Class对象对应类的指定public构造器。

c. Constructor<?>[] getDeclaredConstructors():返回此Class对象对应类的所有构造器,与构造器的访问权限无关。  

d.Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes):返回此对象对应类的指定构造器,与构造器的访问权限无关。

import java.lang.reflect.Constructor;

class Person{
	public Person(){
		System.out.println("TestTarget");
	}
	public Person(String name){
		System.out.println(name);
	}
	protected Person(String stuName,String className){
		System.out.println(stuName + " - " + className);
	}
	private Person(String name, int age){
		System.out.println(name + " - " + age);
	}
}
public class GetConstructorsTest {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException{
		//1.获得Class对象(共3种方式)
		//1)Class.forName(String clazzName);
		//Class<?> clazz = Class.forName("tad.blog.reflect.Person");
		//2)类的class属性
		Class<Person> clazz = Person.class;
		//3)对象getClass()方法
		//Class<?> clazz = new Person().getClass();
		//System.out.println(clazz.getName());
		//2.1.获取所有public构造器
		Constructor<?>[] publicCons = clazz.getConstructors();
		System.out.println("所有public构造器");
		for(Constructor<?> c : publicCons){
			System.out.println(c.getName());
		}
		//2.2.获取特定public构造器
		Constructor<Person> certainCons = clazz.getConstructor(String.class);
		System.out.println("特定public构造器");
		System.out.println("名称:" + certainCons.getName() + ";修饰符: " + certainCons.getModifiers());
		//2.3.获取所有构造器
		Constructor<?>[] allCons = clazz.getDeclaredConstructors();
		System.out.println("所有构造器");
		for(Constructor<?> c : allCons){
			System.out.println(c.getName());
		}
		//2.4.获取特定构造器,访问修饰符无关
		Constructor<Person> certainConsPro = clazz.getDeclaredConstructor(String.class,int.class);
		System.out.println("特定构造器");
		System.out.println("名称:" + certainConsPro.getName() + " ;修饰符: " + certainConsPro.getModifiers());
	}
}

(2)获取Class对象对应类包含的方法

a. Method[] getMethods():返回此Class对象所表示的类的所有public方法。

b. Method getMethod(String name,Class<?>... parameterTypes):返回此Class对象对应类的指定public方法。

c.Method[] getDeclaredMethods():返回此Class对象对应类的全部方法,与方法的访问权限无关。 

d. Method getDeclaredMethod(String name,Class<?>... parameterTypes):返回此对象对应类的指定方法,与方法的访问权限无关。

import java.lang.reflect.Method;

class Fruit{
	public void show(){
	}
	public void show(String info){
	}
	void getWater(){
	}
	protected void grow(){
	}
	private void deep(){
		
	}
	private void deep(int length){
		
	}
}
public class GetMethodsTest {
	public static void main(String[] args) throws NoSuchMethodException {
		//1.获得Class对象
		Class<Fruit> clazz = Fruit.class;
		//2.1.获得所有public Method
		System.out.println("所有public方法");
		Method[] publicMethods = clazz.getMethods();
		for(Method m : publicMethods){
			System.out.println(m.getName());
		}
		//2.2.获得特定public Method
		System.out.println("特定public方法");
		Method certainMethod = clazz.getMethod("show",String.class);
		System.out.println(certainMethod.getName());
		//2.3.获得所有Method,修饰符无关
		System.out.println("所有方法");
		Method[] allMethods = clazz.getDeclaredMethods();
		for(Method m : allMethods){
			System.out.println(m.getName());
		}
		//2.4.获得特定Method,修饰符无关
		System.out.println("特定方法");
		Method certainMethodDeep = clazz.getDeclaredMethod("deep", int.class);
		System.out.println(certainMethodDeep.getName());
	}
}


(3)访问Class对象对应类包含的字段

a. Field[] getFields():返回此Class对象对应类的所有public字段。 
b. Field getField(String name):返回此Class对象对应类的指定public 字段。
c. Field[] getDeclaredFields():返回此Class对象对应类的全部字段,与访问权限无关。 
d. Field getDeclaredField(String name):返回此Class对象对应类的指定字段,与访问权限无关。
import java.lang.reflect.Field;

class Animal{
	public String name;
	public int age;
	private String secrets;
}
public class GetFieldsTest {
	public static void main(String[] args) throws NoSuchFieldException {
		//1.获得Class对象
		Class<Animal> clazz = Animal.class;
		//2.1.获得所有public字段
		Field[] fields = clazz.getFields();
		System.out.println("所有public字段");
		for(Field f : fields){
			System.out.println(f.getName());
		}
		//2.2.获得特定public字段
		Field f = clazz.getField("name");
		System.out.println("特定public字段");
		System.out.println(f.getName());
		//2.3.获得所有字段,访问修饰符无关
		Field[] allFields = clazz.getDeclaredFields();
		System.out.println("获得所有字段");
		for(Field af : allFields){
			System.out.println(af.getName());
		}
		//2.4.获得特定字段,访问修饰符无关
		Field certainField = clazz.getDeclaredField("secrets");
		System.out.println("获得特定字段");
		System.out.println(certainField.getName());
	}
}

(4)访问Class对象对应类包含的Annotation

a. <A extends Annotation>A getAnnotation(Class<A> annotationClass):试图获取该Class对象对应类上指定类型的Annotation;如果该类型注释不存在,则返回null。
b. Annotation[] getAnnotation():返回该Class对象对应类上所有Annotation。
c. Annotation[] getDeclaredAnnotations():返回直接修饰该Class对应类的所有Annotation。
@Deprecated
@Addressing
@SuppressWarnings(value="unchecked")
class Building{
	@Override
	public String toString(){
		return "Building";
	}
}

public class GetAnnotationsTest {
	public static void main(String[] args) {
		//1.获得Class对象
		Class<Building> clazz = Building.class;
		//2.1.获得所有Annotation
		System.out.println("获得所有Annotation");
		Annotation[] as = clazz.getAnnotations();
		for(Annotation a : as){
			System.out.println(a);
		}
		//2.2.获得特定Annotation
		System.out.println("获得特定Annotation");
		Annotation a = clazz.getAnnotation(Addressing.class);
		System.out.println(a);
		//2.3.获得直接修饰的所有Annotation
		System.out.println("获得所有Annotation");
		Annotation[] ass = clazz.getDeclaredAnnotations();
		for(Annotation ann : ass){
			System.out.println(ann);
		}
	}
}

(5)访问Class对象对应类包含的内部类

a. Class<?>[] getDeclaredClasses():返回该Class对象对应类的所有内部类。       

(6)访问Class对象对应类所在的外部类

a. Class<?> getDeclaringClass():返回该Class对象对应类所在的外部类。           

(7)访问Class对象对应类所实现的接口、继承的父类

a. Class<?>[] getInterfaces():返回该Class对象对应类所实现的全部接口。

b. Class<? super T> getSuperClass():返回该Class对象对应类的超类的Class对象。

(8)获取Class对象对应类的修饰符、所在包、类名等基本信息

a. int getModifiers():返回此类或接口的所有修饰符,修饰符由public、protected、private、final、static、abstract等对应的常量组成,返回的整数应使用Modifier工具类的方法解码获取真实的修饰符。
b. Package getPackage():返回此类的包
c. String getName():以字符串形式返回此Class对象所表示的类的名称。
d. String getSimpleName():以字符串形式返回此Class对象所表示的类的简称。

(9)判断该Class对象对应类是否为接口、枚举、注释类型等

a. boolean isAnnotation():返回此Class对象是否表示一个注释类型(由@interface定义)。
b. boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断此Class对象是否使用了Annotation注释修饰。
c. boolean isAnonymousClass():返回此Class对象是否是一个匿名类。
d. boolean isArray():返回此Class对象是否表示一个数组类。
e. boolean isEnum():返回此Class对象是否表示一个枚举类(由enum关键字定义)。
f.  boolean isInterface():返回此Class对象是否表示一个接口(由interface关键字定义)。
g. boolean isInstance(Object obj):判断obj是否是此Class对象的实例,该方法可以完全代码instanceof操作符。
interface Interfa{
	
}
interface Interfa2{
	
}
final class SuperClass implements Interfa,Interfa2{
	public static class InnerClass{
		public static void declaringClass() {
			Class<InnerClass> clazz = InnerClass.class;
			System.out.println("外部类");
			System.out.println(clazz.getDeclaringClass());
		}
	}
}
public class TestAll{
	public static void main(String[] args) {
		Class<SuperClass> clazz = SuperClass.class;
		//获得所有内部类
		System.out.println("所有内部类");
		Class<?>[] inners = clazz.getDeclaredClasses();
		for(Class<?> inner : inners){
			System.out.println(inner);
		}
		//获得外部类
		SuperClass.InnerClass.declaringClass();
		//获得继承父类
		System.out.println("继承父类");
		System.out.println(clazz.getSuperclass());
		//获得实现接口
		System.out.println("实现接口");
		Class<?>[] inters = clazz.getInterfaces();
		for(Class<?> i : inters){
			System.out.println(i);
		}
		//获得修饰符
		System.out.println("获得修饰符");
		int modifier = clazz.getModifiers();
		System.out.println(modifier);
		//获得包
		System.out.println("获得包");
		Package p = clazz.getPackage();
		System.out.println(p.getName());
		//获得全类名及简单类名
		System.out.println("全类名及简单类名");
		System.out.println(clazz.getName());
		System.out.println(clazz.getSimpleName());
		//自我判断API
		System.out.println("注解? " + clazz.isAnnotation());
		System.out.println("数组? " + clazz.isArray());
		SuperClass sc = new SuperClass();
		System.out.println("实例? " + clazz.isInstance(sc));
	}
}

4.反射操作-生成并操作对象

Class对象可以获得该类里的方法(由Method对象表示)、构造器(由Constructor对象表示)、字段(由Field对象表示),这3个类都位于java.lang.reflect包下,并实现java.lang.reflect.Member接口。程序可以通过Method对象执行对应方法,通过Constructor对象调用对应构造器创建实例,能通过Field对象直接访问并修改对象的属性值。

1)创建对象

通过反射创建对象有以下两种方式:
(1)使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法实际上利用默认构造器来创建该类的实例。
(2)先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择指定的构造器来创建实例。


通过第一种方式来创建对象是比较常见的情形,在很多JavaEE框架中都需要根据配置文件信息来创建Java对象,从配置文件读取的只是某个类的字符串类名,程序需要根据字符串来创建对应的实例,就必须使用反射。

如果不想利用默认构造器创建Java对象,可以利用指定的构造器来创建Java对象,需要利用Constructor对象,每个Constructor对应一个构造器,需要以下3个步骤:
(1)获取该类的Class对象。
(2)利用Class对象的getConstructor()方法来获取指定的构造器。

(3)调用Constructor的newInstance()方法创建Java对象。

import java.lang.reflect.Constructor;

class Computer{
	public Computer(String name){
		show(name);
	}
	public void show(){
		System.out.println("Computer");
	}
	public void show(String name){
		System.out.println("My name is " + name);
	}
}
public class ObjFactory {
	public static void main(String[] args) throws Exception {
		//Class<Computer> clazz = Computer.class;
		//1.第1种方式创建对象
		//Computer com = clazz.newInstance();
		//System.out.println(com);
		//com.show();
		//2.第2种方式创建对象
		//2.1.获取Class对象
		Class<?> comClazz = Class.forName("tad.blog.reflect.Computer");
		//2.2.获得指定构造器
		Constructor<?> c = comClazz.getConstructor(String.class);
		//2.3.创建Java对象
		c.newInstance("Tad");
	}
}

2)访问属性值

通过Class对象的getFields()或getField()方法可以获取该类所包括的全部Field或指定Field。Field提供如下两组方法读取或设置字段的值。
(1)getXxx(Object obj):获取obj对象该字段的属性值。此处的Xxx对应的8个基本类型,如果该属性是引用类型,则取消get后面的Xxx。
(2)setXxx(Object obj,Xxx val):将obj对象的字段设置成val值,此处的Xxx对应8个基本类型,如果该属性的类型是引用类型,则取消set后面的Xxx。

import java.lang.reflect.Field;

class Dog
{
	private String name;
	private int age;
	public String toString(){
		return "Dog[name:"+name+",age:"+age+"]";
	}
}
public class FieldTest 
{
	public static void main(String[] args) throws Exception
	{
		//创建Person对象
		Dog p = new Dog();
		//Person对应Class对象
		Class<Dog> clazz = Dog.class;
		//获取Person名为name的Field
		Field nameField = clazz.getDeclaredField("name");
		//取消访问权限
		nameField.setAccessible(true);
		//调用set方法为p对象的name字段值设置值
		nameField.set(p,"Tad");//引用类型,没有Xxx,可能是因为引用类型的地址是一样的吧!
		Field ageField = clazz.getDeclaredField("age");
		ageField.setAccessible(true);
		ageField.setInt(p,23);//8个基本数据类型,setXxx()
		System.out.println(p);
	}
}

3)调用方法

当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或getMethod()方法来获得全部方法或指定方法--两个方法的返回值是Method数组或者是Method对象。

每个Method对象对应一个方法,获得Method对象后,程序就可以通过该Method来调用它对应的方法。在Method里包含一个invoke()方法,方法签名如下:

Object invoke(Object obj, Object...args):该方法中的obj是执行该方法的主调,后面的args是执行该方法时传入该方法的实参。

import java.lang.reflect.Method;

public class MethodTest {
	public static void main(String[] args) throws Exception {
		//1.获得Class对象
		Class<MethodTest> clazz = MethodTest.class;
		//2.获得Method对象
		Method m = clazz.getMethod("show", String.class);
		//3.调用invoke()方法
		m.invoke(new MethodTest(), "Tad is a great person in the world.");
	}
	public void show(String info){
		System.out.println(info);
	}
}

5.反射操作-数组操作

在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以使用Array来动态创建数组,操作数组元素等。
(1)static Object newInstance(Class<?> componentType, int length):创建一个具有指定的元素类型、指定维度的新数组。
(2)static xxx getXxx(Object array, int index):返回array数组中第index个元素。其中xxx是各种基本数据类型,如果数组元素是引用类型,则该方法变为get(Object array, int index)。
(3)static void setXxx(Object array, int index, xxx val):将array数组中第index个元素的值设为val,其中xxx是各种基本数据类型,如果数组元素是引用类型,则该方法变成set(Object array, int index, Object val)。

 
import java.lang.reflect.Array;

public class ArrayTest {
	public static void main(String[] args) {
		Object arr = Array.newInstance(String.class, 3);
		Array.set(arr, 0, "Tad");
		Array.set(arr, 1, "great");
		Array.set(arr, 2, "person");
		System.out.println(Array.get(arr, 0));
		System.out.println(Array.get(arr, 1));
		System.out.println(Array.get(arr, 2));
		System.out.println("长度:" + Array.getLength(arr));
	}
}


6.利用反射生成JDK动态代理


1)利用Proxy和InvocationHandler创建动态代理

在java的java.lang.reflect包下提供了Proxy类和InvocationHandler接口,通过两者可以生成JDK动态代理类或动态代理对象。
Proxy提供了用于创建动态代理类和代理对象的静态方法,也是所有动态代理类的父类。如果在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类,如果需要为一个或多个接口动态地创建实例,也可以使用Proxy来创建动态代理实例。
Proxy提供了如下两个方法来创建动态代理类和动态代理实例。
(1)static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces):创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口。第一个ClassLoader参数指定生成动态代理类的类加载器。
(2)static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):直接创建一个动态代理对象,该代理对象的实例类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler对象的invoke方法。

实际上,即使采用第一个方法获取了一个动态代理类之后,当程序需要通过该代理类来创建对象时一样需要传入InvocationHandler对象,也就是说,系统生成的每个代理对象都有一个与之关联的InvocationHandler对象。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Skills{
	public void bark();
	public void run();
}
/**
 * 委托类,业务执行者
 */
class Dog implements Skills{
	public void bark() {
		System.out.println("Dog can bark.");
	}
	public void run(){
		System.out.println("Dog can run");
	}
}
/**
 * 调用处理类,完成代理与委托绑定
 */
class InvocationHandlerImpl implements InvocationHandler {  
    private Object target;  
    public InvocationHandlerImpl(Object target){
    	this.target = target;
    }
    /** 
     * 方法调用,调用代理到调用委托的转换
     */  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {     
        return method.invoke(target, args);    
    }  
}  
public class DynamicProxy {
	public static void main(String[] args) {
		InvocationHandler h = new InvocationHandlerImpl(new Dog());
		Skills o = (Skills)Proxy.newProxyInstance(Dog.class.getClassLoader(), Dog.class.getInterfaces(), h);
		o.bark();
		o.run();
	}
}

2)动态代理与AOP

待补充...

7.反射和泛型

JDK1.5以后,Java的Class类增加泛型功能,从而允许使用泛型来限制Class类,例如String.class类型实际是Class<String>。如果Class对应的类暂时未知,则使用Class<?>。通过在反射中使用泛型,可以避免使用反射生成的对象需要强制类型转换。

1)泛型和Class类

使用Class<T>泛型可以避免强制类型转换。

2)利用反射获取泛型信息

通过指定类对应的Class对象,可以获得该类包含的所有字段,不管该字段使用private修饰还是使用public修饰,获得Field对象后,就可以很容易地获得该Field的数据类型,即使用如下代码获得指定字段的类型。
Class<?> a = f.getType();

但这种方式只对普通类型的字段有效,如果该字段的类型是有泛型的类型,如Map<String,Integer>类型,则不能准确地得到该字段的泛型参数。
为了获得指定字段的泛型类型,应先使用如下方法来获取指定Field的泛型类型。
Type gType = f.getGenericType();
然后将Type对象强制类型转换为ParameterizedType对象,ParameterizedType代表参数化的类型,也就是增加了泛型限制的类型。ParameterizedType类提供了如下两个方法:
(1)getRawType():返回没有泛型信息的原始类型。

(2)getActualTypeArguments():返回泛型参数的类型。

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

public class ReflectGenericTest {
	public int num;
	public Map<String,Integer> kv;
	public static void main(String[] args) throws NoSuchFieldException {
		Class<ReflectGenericTest> c = ReflectGenericTest.class;
		Field fNum = c.getField("num");
		System.out.println(fNum.getType());
		//只能输出Map
		Field f = c.getField("kv");
		System.out.println(f.getType());
		//获得实际类型参数
		Type type = f.getGenericType();
		ParameterizedType p = (ParameterizedType) type;
		System.out.println("原始类型:" + p.getRawType());
		Type[] types = p.getActualTypeArguments();
		for(Type t : types){
			System.out.println(t);
		}
	}
}

------- android培训java培训、期待与您交流! ----------

黑马程序员_高新技术_1_Java反射,布布扣,bubuko.com

黑马程序员_高新技术_1_Java反射

上一篇:OpenCV3.4两种立体匹配算法效果对比


下一篇:python学习笔记三---segmaphore信号量学习