Java Reflection
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方
Class 类:
在Object类中定义了以下的方法,此方法将被所有子类继承: public final Class getClass()
Class 类的常用方法:
实例:
import java.lang.reflect.Field; import java.lang.reflect.Method; public class TestReflection { //有了反射,可以通过反射创建一个类的对象,并调用其中的属性、方法 public void test3(){ Person p=new Person(); Class cla=p.getClass();//通过运行时类的对象,调用其getClass方法,返回其运行时类 System.out.println(cla); } public void test2() throws Exception{ Class cla=Person.class; //1.创建cla对应的运行时类Person类的对象 Person p=(Person)cla.newInstance(); System.out.println(p); //2.通过反射调用运行时类的指定的属性 //2.1 Field f1=cla.getField("name"); f1.set(p, "LiMing"); System.out.println(p); //2.2 Field f2=cla.getDeclaredField("age"); f2.setAccessible(true); f2.set(p, 20); System.out.println(p); //3.通过反射调用运行时类的指定的方法 Method m1=cla.getMethod("show"); m1.invoke(p); Method m2=cla.getMethod("display", String.class); m2.invoke(p, "China"); } //不使用反射的情况下,创建一个对象,并调用其中的属性、方法 public void test1(){ Person person=new Person(); person.setName("LiMing"); person.setAge(20); person.show(); person.display("HK"); } } public class Person { private String name; private int age; public Person(){ super(); } public Person(String name){ super(); this.name=name; } public Person(String name,int age){ super(); this.name=name; this.age=age; } public void setName(String name){ this.name=name; } public String getName(){ return name; } public void setAge(int age){ this.age=age; } public int getAge(){ return age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public void show(){ System.out.println("我是一个人!"); } public void display(String nation){ System.out.println("我的国籍是:"+nation); } }
java.lang.Class:是反射的源头
我们创建了一个类,通过编译(javac.exe)生成相应的.class文件。之后我们使用java.exe加载(JVM的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓冲区,那么这个运行时类本身就是一个Class实例。
1.一个运行时类只加载一次。
2.有了Class类的实例以后,我们才可以进行如下的操作:
1)创建对应的运行时类的对象
2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解...)
3)调用对应的运行时类的指定的结构(属性、方法、构造器)
4)反射的应用:动态代理
实例化Class类对象(四种方法):
1.若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2.已知某个类的实例,调用该实例的getClass()方法获取Class对象
实例:Class clazz = “www.atguigu.com”.getClass();
3.已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4.通过类的加载器(类加载器是用来把类(class)装载进内存的)(了解)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
public void test4() throws ClassNotFoundException{ //调用运行时类本身的.class属性 Class cla1=Person.class; System.out.println(cla1.getName());//返回com.atguigu.java.Person Class cla2=String.class; System.out.println(cla2.getName());//返回java.lang.String //通过运行时类的对象获取 Person p=new Person(); Class cla3=p.getClass(); System.out.println(cla3.getName());//返回com.atguigu.java.Person //通过运行时类的静态方法forName获取 Class cla4=Class.forName("com.atguigu.java.Person"); System.out.println(cla4.getName());//返回com.atguigu.java.Person }
创建类对象并获取类的完整结构:
创建类的对象:调用Class对象的newInstance()方法
要求:1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
//1.根据全类名获取对应的Class对象
String name = “atguigu.java.Person";
Class clazz = Class.forName(name);
//2.调用指定参数结构的构造器,生成Constructor的实例
Constructor con = clazz.getConstructor(String.class,Integer.class);
//3.通过Constructor的实例创建对应类的对象,并初始化类属性
Person p2 = (Person) con.newInstance("Peter",20);
System.out.println(p2);
通过反射调用类中的指定方法、指定属性:
1.调用指定属性
先获取属性
public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)访问私有属性时,让这个属性可见。
2.调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
1).通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
2).之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
//调用运行时类中指定的属性 public void test5() throws Exception{ Class cla=Person.class; //1.获取指定的属性 Field name=cla.getField("name"); //2.创建运行时类的对象 Person p=(Person)cla.newInstance(); //3.将运行时类的指定的属性赋值 name.set(p, "LiMing"); System.out.println(p); Field age=cla.getDeclaredField("age"); age.setAccessible(true); age.set(p, 20); System.out.println(p); } //调用运行时类中指定的方法 public void test6() throws Exception{ Class cla=Person.class; //获取运行时类中声明为public的指定的方法 Method m1=cla.getMethod("show"); Person p=(Person)cla.newInstance(); //调用指定的方法 Object returnVal=m1.invoke(p); //对于运行时类中静态方法的调用,无需创建运行时类的对象,直接使用类调用对象 Method m2=cla.getMethod("info"); m2.invoke(Person.class); }