反射

0.反光知识


下面是体现知识的整体机身,这个数字也掌握在把握生活的全球反思的全部内容。


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对象是否表示一个枚举类(由enumkeyword定义)。

f.  boolean isInterface():返回此Class对象是否表示一个接口(由interfacekeyword定义)。

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对象后。就能够非常easy地获得该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);
		}
	}
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/zfyouxi/p/4725100.html