11、反射
11.1、反射的概念
Java在编译过程中是把 Java 代码编成 class 文件。编译期做了一些翻译功能,并没有把代码放在内存中运行起来,运行期是把编译后的文件交给计算机执行,直到程序运行结束。
而Java 反射机制 (Reflection) 就是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性
;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。也就是说反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。(我们所写类中的属性和方法都有对应的类来描述,反射就是获取这些组成类的不同成分的对象)
-
动态语言:在运行时代码可以根据某些条件改变自身结构。如:JavaScript、Python
-
静态语言:运行时结构不可变的语言就是静态语言。如:C、C++
Java因为反射机制的存在,使它有一定的动态性,所以算是半个动态语言
反射同样是很多框架设计和中间件程序中得到了广泛运用。
java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解、数组、基本数据类型和 void。Class 没有公有的构造方法,是由 JVM 在类加载时自动创建的。
在知道类全限定名的情况下,使用Class 的静态方法forName(String)
创建某个类的运行时对象。
反射中常用的类有:
Constructor 类:提供类的构造方法信息。
Field 类:提供类或接口中成员变量信息。
Method 类:提供类或接口成员方法信息。
Array 类:提供了动态创建和访问 Java 数组的方法。
Modifier 类:提供类和成员访问修饰符信息。
Class类:代表一个类,获取对象
11.2、获取Class类
我们知道Object 是所有类的直接 或间接的父类,那内部定义了一个方法 getClass(),它返回就是一个Class,而Class可以用来描述所有的类,这就是反射机制的根源。
JVM在加载类时,会为类生成一个Class类型的对象,这个对象包含了该类的所有结构及其相关的信息,所以可以通过Class完整地得到一个类中的所有被加载的结构
class(外部类,内部类)、接口、数组、枚举、注解@interface等都可以获取Class对象。
获取Class对象的几种方式
1、在知道类的情况下,通过类的class
2、在知道类的实例时,通过getClass()方法
3、知道类的全路径时,通过Class.forName("路径+类名")
try {
Class c1 = Class.forName("JavaSE.serialization.Student");
System.out.println("类全限定名:"+c1.getName());
System.out.println("类名"+c1.getSimpleName());
Class c2 = String.class;
System.out.println("类全限定名:"+c2.getName());
System.out.println("类名"+c2.getSimpleName());
Persion persion = new Persion();
Class c3 = persion.getClass();
System.out.println("类全限定名:"+c3.getName());
System.out.println("类名"+c3.getSimpleName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
11.3、反射创建对象
Class类中提供了一个方法 newInstance() ,这个方法可用用来创建对象,类最好要有一个无参构造,因为对象的创建需要明确构造方法,如果没有无参构造,还必须先获取构造器,知道参数类型后,才能明确怎么创建对象。
-
创建一个类
interface ReflectionTestInterface{ } abstract class ReflectionTestAbstract{ } public class Persion implements ReflectionTest{ private String name; private int age; public int height; //public修饰的含参构造 public Persion(String name, int age, int height) { this.name = name; this.age = age; this.height = height; } //public修饰的含参构造 public Persion(String name, int age) { this.name = name; this.age = age; } //private修饰的含参构造 private Persion(String name) { this.name = name; } //无参构造 public Persion() { } //私有方法 private void hidden(){ System.out.println("私有方法"); } //public方法 public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
-
通过反射获取构造方法
-
getConstructors():获取public修饰的构造方法
try { System.out.println("===获取public修饰的构造方法==="); Constructor[] constructors = clazz.getConstructors(); for(Constructor c : constructors){ System.out.println(c); } } catch (Exception e) { e.printStackTrace(); }
-
getDeclaredConstructors():所有的构造方法(含private修饰的)
try { System.out.println("===所有的构造方法(含private修饰的)==="); Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for(Constructor c : declaredConstructors){ System.out.println(c); } } catch (Exception e) { e.printStackTrace(); }
-
getConstructor(null):获取无参构造
try { System.out.println("===获取无参构造方法==="); Constructor constructor = clazz.getConstructor(null); System.out.println(constructor); } catch (Exception e) { e.printStackTrace(); }
-
根据参数类型获取构造方法
//获取有一个参数为String的构造方法。 System.out.println("===根据参数类型获取构造方法==="); Constructor declaredConstructor = null; try { System.out.println("===含有一个String参数的构造方法==="); declaredConstructor = clazz.getDeclaredConstructor(String.class); System.out.println(declaredConstructor); } catch (Exception e) { e.printStackTrace(); }
-
-
根据构造方法创建对象
try { System.out.println("===调用构造方法创建对象==="); System.out.println("===使用无参的构造创建对象==="); Constructor constructor = clazz.getConstructor(null); Persion persion = (Persion) constructor.newInstance(); System.out.println(persion); System.out.println("===根据参数类型获取构造方法并创建对象==="); Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class); System.out.println("参数为String类型的构造方法:"+declaredConstructor); //获取权限,可直接调用private修饰的方法 declaredConstructor.setAccessible(true); //创建对象 Persion p = (Persion)declaredConstructor.newInstance("张三"); System.out.println(p.getName()); } catch (Exception e) { e.printStackTrace(); }
11.4、获取类其他结构
11.4.1、获取接口
通过反射获取类实现的接口的Class对象
System.out.println("===获取实现的接口===");
Class[] interfaces = clazz.getInterfaces();
for (Class c:interfaces){
System.out.println(c);
}
11.4.2、获取父类
通过反射获取类继承的父类的Class对象
System.out.println("===获取继承的父类===");
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
11.4.3、获取属性
通过反射获取属性
-
clazz.getFields():获取非private修饰的属性
System.out.println("===获取public的属性==="); Field[] fields = clazz.getFields(); for(Field f :fields){ System.out.println(f); }
-
clazz.getDeclaredFields():获取所有的属性
System.out.println("===获取所有的属性==="); Field[] declaredFields = clazz.getDeclaredFields(); for(Field f : declaredFields){ System.out.println(f); }
-
获取指定属性,并修改、获取值
System.out.println("===获取指定属性,并修改、获取值==="); try { Field f = clazz.getDeclaredField("name"); //("属性名") System.out.println(f); f.setAccessible(true); //可以获取private的使用权限 Object o = clazz.getConstructor().newInstance(); //反射创建对象 f.set(o ,"张三"); //反射修改值 System.out.println( f.get(o)); //反射获取值 } catch (Exception e) { e.printStackTrace(); }
-
获取属性的权限、类型、名字
System.out.println("===获取属性的权限、类型、名字==="); for(Field f : declaredFields){ System.out.print(Modifier.toString(f.getModifiers())+" "); //权限 System.out.print(f.getType().getSimpleName()+" "); //类型 System.out.print(f.getName()); //名字 System.out.println(";"); }
-
修改、获取属性值
System.out.println("===修改、获取属性值==="); try { Field f = clazz.getDeclaredField("age"); //("属性名") f.setAccessible(true); //可以获取private的使用权限 Persion p = (Persion)clazz.getConstructor().newInstance(); f.set(p ,18);//修改值 System.out.println( f.get(p)); //获取值 } catch (Exception e) { e.printStackTrace(); }
11.4.4、获取方法
通过反射获取方法
-
获取所有public方法,包括父类继承的
System.out.println("===获取所有public方法,包括父类继承的==="); Method[] methods = clazz.getMethods(); for(Method m : methods){ System.out.println(m); }
-
获取自定义的所有方法
System.out.println("===获取自定义的所有方法==="); Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m : declaredMethods){ System.out.println(m); }
-
获取方法的权限修饰符、返回值、方法名、参数类型
System.out.println("===获取方法的权限修饰符、返回值、方法名、参数类型==="); for(Method m : declaredMethods){ System.out.print(Modifier.toString(m.getModifiers())+" "); //权限修饰符 System.out.print(m.getReturnType().getSimpleName()+" "); //返回值 System.out.print(m.getName()); //方法名 Parameter[] parameters = m.getParameters(); //参数类型数组,需遍历 System.out.print("("); for(Parameter p : parameters){ System.out.print(p.getType().getSimpleName()+","); } System.out.println(");"); }
-
获取指定方法并调用
System.out.println("===获取指定方法并调用==="); try { //获取名为getName的方法,无参数传递 Method getName = clazz.getMethod("getName", null); System.out.println(getName); getName.setAccessible(true); //可以获取private的使用权限 //获取名为setName的方法,传递的参数类型为String Method setName = clazz.getMethod("setName", String.class); System.out.println(setName); setName.setAccessible(true); //可以获取private的使用权限 //创建一个对象 Object o = clazz.getConstructor().newInstance(); //反射调用setName方法 setName.invoke(o,"张三"); //反射调用getName方法 System.out.println(getName.invoke(o)); } catch (Exception e) { e.printStackTrace(); }