JAVA 反射

每个类都会有一个Class对象,所有的类都是在首次使用时动态加载到JVM中。类加载器首先会检查该类的Class对象是否已经被加载,如果尚未被夹在。默认的类加载器就会根据类名查找.class文件,然后加载该类到内存。他就用来创建这个类的所有对象。

1. Class对象:

1.1 获取一个类的Class对象: Class.forName();或使用类字面常量,这样做在编译期会接受检查,不需要捕获异常。不仅普通的类,接口、数组及基本数据类型都有字面常量。类名.class

1.2  Class类。Class对象总是指向某个Class对象,可以制造类的实例,包含该类的静态成员,作用于这些事例的所有方法代码。JAVA 1.5之前使用的是普通类引用,1.5之后将类引用使用泛型语法变得更加具体。使用泛型语法的类之后,会让编译器强制执行额外的类型检查。为了使用泛化的Class引用时放松限制,可以使用通配符“?”,表示任何事物。使用普通的Class引用时若果犯错,直到运行的时候才会被发现。创建Class引用,被限定为某种类型或该类型的任何子类型,可以使用<? extends >

注:Class<?>和Class是等价的,Class<?>的好处是表示程序员就是自己选择使用非具体的版本而不是由于疏忽。

public class TestReflection {
	public static void main(String[] args) {
		Class intClass1 = int.class;
		Class doubleClass1 = double.class;
		Class<Integer> intClass2 = int.class;// Class<Integer> intClass2 = Integer.class;
		Class<Double> doubleClass2 = double.class;
		// intClass2 = double.class; // error
		
		Class<?> intClass3 = int.class;
		
		Class<? extends Number> int_double_class;
		int_double_class = int.class;
		int_double_class = double.class;
	}
}

1.3  普通的Class和泛化的Class还有个区别,在使用泛型语法的Class时使用newInstance()返回该对象的确切类型,而普通的Class返回的是Object

class A{
	public void print(){
		System.out.println("AAA");
	}
}
public class TestReflection {

	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		Class aClass1 = A.class;
		Object obj = aClass1.newInstance();
		((A)obj).print();
		Class<A> aClass2 = A.class;
		A a2 = aClass2.newInstance();
		a2.print();
	}
}

1.4  使用泛型语法获得父类的Class引用

class A{}
class B extends A{}
public class TestReflection {

	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		Class<B> bClass = B.class;
		Class<? super B> aClass1 = bClass.getSuperclass();
		
		// 不能写成下面的形式,尽管在编译的时候在编译起见就知道B的父类是A
		// Class<A> aClass2 = bClass.getSuperclass(); // error
		
		// 正由于上面的到的 aClass1 的含糊性,下面得到的返回值也不是精确类型而是Object
		Object aClassObj = aClass1.newInstance();
	}
}


2. 反射相关类 : java.lang.reflect包 包括了Field、Method、Constructor类,每个类都实现了Menber接口。这些类对象都是在JVM运行时创建的。

反射机制提供了足够的支持,使得能够创建一个在编译时完全未知的对象,并调用此对象的方法。

2.1 获取类的构造函数、属性和方法

class A{
	private int i;
	public A (int x) {
		i = x;
	}
	public void print() {
		System.out.println("AAA");
	}
	
}
public class TestReflection {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		Class<?> aClass = null;
		try {
			aClass = Class.forName("reflection.A");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println("------------类所有方法------------");
		Method [] methods = aClass.getDeclaredMethods();
		
		for (Method method : methods) {
			System.out.println(method.toString());
		}
		System.out.println("------------类构造方法------------");
		Constructor [] constructors = aClass.getDeclaredConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor.toString());
		}
		System.out.println("------------类属性------------");
//		Field [] fields = aClass.getFields();//获取public的
		Field [] fields = aClass.getDeclaredFields();  //获取public的
		for (Field field : fields) {
			System.out.println(field.toString());
		}
	}
}
//getFields()与getDeclaredFields()区别:
//getFields()只能访问类中声明为公有的字段,getDeclaredFields()能访问类中所有的字段
//getMethods()与getDeclaredMethods()区别:
//getMethods()只能访问类中声明为公有的方法,能访问从其它类继承来的公有方法,getDeclaredFields()能访问类中所有的字段,不能访问从其它类继承来的方法
//getConstructors()只能访问类中声明为public的构造函数,getDeclaredConstructors()能访问类中所有的构造函数

2.2 创建对象

class A{
	private int i;
	public A(){}
	private A (int x) {
		i = x;
	}
	public void print() {
		System.out.println("AAA");
	}
	public int getI() {
		return i;
	}
	public void setI(int i) {
		this.i = i;
	}
}
public class TestReflection {
	public static void main(String[] args){
		try {
			Class<A> aClass = A.class;
			//创建对象的两种方式
			// 1. Class.newInstance
			 aClass.newInstance();// 必须有默认的构造函数
			// 2. Constructor.newInstance
			Constructor<A> intConstructors = aClass.getDeclaredConstructor(int.class); // new Class<?> []{int.class}
			intConstructors.setAccessible(true);
			A a = intConstructors.newInstance(100);
			System.out.println(a.getI());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

2.3 访问类属性 一般用来修改源码中类成员的值

class A{
	private static boolean isOpen = false;
	public static boolean isOpen() {
		return isOpen;
	}
}
public class TestReflection {
	public static void main(String[] args){
		try {
			System.out.println(A.isOpen());
			Field openField = A.class.getDeclaredField("isOpen");
			openField.setAccessible(true);
			openField.setBoolean(new A(), true);
			System.out.println(A.isOpen());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

2.4 调用函数

class A{
	private void print() {
		System.out.println("AAA");
	}
}
public class TestReflection {
	public static void main(String[] args){
		try {
			A a = new A();
			Class<A> aClass = (Class<A>) a.getClass();
			aClass.getDeclaredMethod("print");
			Method printMethod = aClass.getDeclaredMethod("print");//Method printMethod = aClass.getDeclaredMethod("print", new Class<?>[]{});
			printMethod.setAccessible(true);
			printMethod.invoke(a);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

注:利用反射调用私有属性、构造函数或者方法时要设置Accessible属性为true。

posted @ 2015-04-29 22:40  浩荡乾坤  阅读(145)  评论(0编辑  收藏  举报