程序员人生 网站导航

JAVA 反射

栏目:php教程时间:2015-05-27 08:17:10

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


1. Class对象:

1.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运行时创建的。

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

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 访问类属性 1般用来修改源码中类成员的值

<pre name="code" class="java">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 调用函数

<pre name="code" class="java">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。










------分隔线----------------------------
------分隔线----------------------------

最新技术推荐