Java反射机制是肥肠重要的概念,它的原理以及如何使用,一起来探讨吧!
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
上面说的是反射的官方概念,其意思也就是,正常实例化对象的方式是:1、首先引入需要的包 2、new实例化 3、取得实例化对象 。而反射机制是“反”过来,通过实例化对象,可以获得此对象的属性,方法,所属类包的名称。反射是被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。可以降低程序的耦合度,很多框架都运用了反射。
上面提到了反射是动态语言的关键,那么,上面是“动态语言”呢?
动态语言是指程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。C++,Java,C#都不是动态语言。尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
Java的反射机制有什么功能?
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理
反射机制的相关类
类名 | 用途 |
Class | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field | 代表类的成员变量 |
Method | 代表类的方法 |
Constructor | 代表类的构造方法 |
Class类
1、创建Person类的对象
//Person.class 代表Person类
Class c = Person.class;
//创建Person类的实例p,相当于不使用反射创建的实例:Person p = new Person();
Person p = (Person)c.newInstance();
2、通过运行时类的对象,调用其getClass()方法,返回其运行时类。
Person per = new Person();
Class clazz = per.getClass();
System.out.println(clazz);
3、获取Class类的四种方式:
//1、调用运行时类本身的 .class 属性
Class c1 = Person.class;
//打印TestReflection.Person
System.out.println(clazz.getName());
Class c2= String.class;
//打印java.lang.String
System.out.println(c2.getName());
//2、 通过运行时类的对象获取
Person person = new Person();
Class c3 = person.getClass();
//打印TestReflection.Person
System.out.println(c3.getName());
//3、通过 class 的静态方法获取
String className = "TestReflection.Person";
Class c4 = Class.forName(className);
//打印TestReflection.Person
System.out.println(c4.getName());
//4、类的加载器
String className = "TestReflection.Person";
ClassLoader classLoader = this.getClass().getClassLoader();
Class c5 = classLoader.loadClass(className);
//打印TestReflection.Person
System.out.println(c5.getName());
Field类
1、获取Person类的访问控制符为public的指定成员变量
//Person.class 代表Person类
Class c = Person.class;
//创建Person类的实例p,相当于不使用反射创建的实例:Person p = new Person();
Person p = (Person)c.newInstance();
//获取类Person的public属性 name
Field f1 = c.getField("name");
//设定 Person类的对象 p 的 name 属性为 "Nikita",当Person的name属性的访问控制符为 public 时才可设定属性值。
f1.set(p,"Nikita");
//打印Nikita
System.out.println(p.name);
2、获取Person类的访问控制符为private的指定成员变量
//获取声明的Person类的private属性 age
Field f2 = c.getDeclaredField("age");
//使用反射机制访问私有变量时必须调用 setAccessible方法设置属性为true,否则会报 IllegalAccessException异常
f2.setAccessible(true);
//设置Person类的对象p的age属性值为 34
f2.set(p,34);
//打印 34
System.out.println(p.getAge());
3、获取Person类的所有 public属性
Class cla = Person.class;
//getFields():获取运行时类中及其父类中所有public属性
Field[] fields = cla.getFields();
for(int i =0;i<fields.length;i++) {
//打印:public java.lang.String TestReflection.Person.name
System.out.println(fields[i]);
}
4、获取 Person类的所有属性(包括private)
Class cla = Person.class;
//getDeclaredFields():获取运行时类本身的所有属性(包括private)
Field[] fields1 = cla.getDeclaredFields();
for(Field f:fields1){
System.out.println(f.getName());
}
Method类
1、获取Person类的 getAge()方法
Class c = Person.class;
Person p = (Person)c.newInstance();
//获取Person类的 getAge方法
Method m1 = c.getMethod("getAge");
//Person类的对象p调用获取的 getAge 方法,如果此方法有参数,invoke第二个参数是 调用getAge方法需要的参数。
m1.invoke(p);
2、获取Person类的 display()方法
Class c = Person.class;
Person p = (Person)c.newInstance();
//获取 Person 类的 display方法,第二个参数为 display方法的参数类型
Method m2 = c.getMethod("display", String.class);
//调用display方法,参数为"CHN is very good!"
m2.invoke(p,"CHN is very good!");
3、getMethods():获取运行时类及其父类中所有声明为 public 的方法
Class ccc = Person.class;
Method[] method1 = ccc.getMethods();
for(Method m :method1) {
System.out.println(m);
}
4、getDeclareMethods():获取运行时类的所有方法(包括 private)
Class ccc = Person.class;
Method[] method2 = ccc.getDeclareMethods();
for(Method m :method2) {
System.out.println(m);
}
Constructor类
获取类中所有构造函数
String className = "TestReflection.Person";
Class c = Class.forName(className);
Constructor[] cons = c.getDeclaredConstructors();
for(Constructor con : cons){
System.out.println(con);
}
}
获取类的完整结构
包括:注解、权限修饰符、返回值类型、方法名、形参列表、异常类型
public void test3() throws Exception{
//获取类中方法的完整结构
Class c = Person.class;
Method[] method = c.getDeclaredMethods();
for(Method m : method) {
//1、注解
Annotation[] ann = m.getAnnotations();
for(Annotation a:ann){
System.out.print(a);
}
//2、权限修饰符
String str = Modifier.toString(m.getModifiers());
System.out.print(str+" ");
//3、返回值类型
Class returnType = m.getReturnType();
System.out.println(returnType.getName()+" ");
//4、方法名
System.out.println(m.getName());
//5、形参列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(int i = 0;i<params.length;i++){
System.out.print(params[i].getName()+" args-"+i+" ");
}
System.out.println(")");
//6、异常类型
Class [] exps = m.getExceptionTypes();
if(exps.length != 0){
System.out.print("throws ");
}
for(int i = 0;i < exps.length;i++) {
System.out.print(exps[i].getName() + "");
}
}
}