反射
一、反射机制
程序在执行期间用Reflection获得类的内部信息,操作对象的属性及方法
加载完类之后,在堆中产生了一个Class类型的对象,这个对象包含了完整的类结构信息,通过类的对象得到类的结构
反射的优缺点:
- 优点:动态的创建和使用对象
- 缺点:基本是解释实行,对执行速度有影响
二、反射相关的主要类
Class:类,其对象表示某个类加载后在堆中的对象
Method:方法
Field:成员变量
Constructor:构造方法public class Reflection1 {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {// Properties类读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String method = properties.get("method").toString();String classfullpath = properties.get("classfullpath").toString();System.out.println(classfullpath + " " + method);// 使用反射机制解决// (1) 加载类,返回Class类型的对象clsClass cls = Class.forName(classfullpath);// (2) 通过cls得到加载的类java30.reflection.Cat的对象Object o = cls.newInstance();System.out.println(o.getClass()); // class java30.reflection.Cat// (3) 通过cls得到加载的类的java30.reflection.Cat的此时为"hi"方法的对象// 即在反射中,把方法视为对象Method method1 = cls.getMethod(method);// (4) 通过method1调用方法:即通过方法对象来实现调用方法method1.invoke(o); // 反射机制 方法.invoke(对象)// java.lang.reflect.Field代表类的成员变量,Field对象表示某个类的成员变量// getField不能得到私有的属性Field nameField = cls.getField("age");System.out.println(nameField.get(o)); // 反射:成员变量对象.get(对象)//Constructor constructor = cls.getConstructor(); // ()中可以指定构造器参数类型,返回无参构造器System.out.println(constructor); // public java30.reflection.Cat()Constructor constructor1 = cls.getConstructor(String.class);//String.class是String类的Class对象System.out.println(constructor1); // public java30.reflection.Cat(java.lang.String)}}
三、反射调用优化
关闭访问检查
Method、Field和Constructor对象都有setAccessible()方法,作用是启动和禁用访问安全检查的开关,true表示使用反射的对象时取消访问检查,提高反射的效率,false表示反射的对象执行访问检查四、Class类
![%YLNTUAS_VVE68I0FLLZ17.png4.1 简介
Class类继承Object类,不是new创建的,是系统创建的
某个类的Class类对象,在内存中只有一份,类只加载一次
通过Class对象可以得到一个类的完成结构
Class对象存放在堆中
类的字节码二进制数据放在方法区
外部类、内部类、接口、数组、枚举、注解(annotation)、基本数据类型和void都有Classs对象4.2 常用方法
其它方法:public class Class02 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {String classAllPath = "java30.reflection.Car";// 获取到Car类的Class对象// <?>表示不确定的Java类型 可以去掉Class<?> cls = Class.forName(classAllPath);System.out.println(cls); // class java30.reflection.CarSystem.out.println(cls.getClass()); // 运行类型 class java.lang.Class// 得到包名System.out.println(cls.getPackage().getName()); // 包名// 类名System.out.println(cls.getName());// 用cls创建对象实例Car car = (Car) cls.newInstance();System.out.println(car);// 通过反射获取属性Field brand = cls.getField("brand"); // 不能是私有属性System.out.println(brand.get(car));// 给属性赋值brand.set(car, "che");System.out.println(brand.get(car));// 所有属性Field[] fields = cls.getFields();for (Field f: fields) {System.out.println(f.getName());}}}
Class[] getInterfaces() 获取当前Class对象的接口
- ClassLoader getClassLoader() 返回该类的类加载器
- Class getSuperclass() 超类的Class
- Constructor[] getConstructors() 某些Constructor对象的数组
- Field[] getDeclaredFields() Field对象的一个数组
- Method getMethod(String name, Class paramTypes) 返回一个Method对象
4.3 获取Class类对象
- 编译阶段 Class.forName() 多用于配置文件,读取类全路径,加载类
- Class类阶段 类.class
- 运行阶段 对象.getClass()
- 类加载器得到Class对象
- 基本数据(int, char, boolean, float…) 基本数据类型.class
基本数据类型对应的包装类 包装类.TYPE
public class GetClass {public static void main(String[] args) throws ClassNotFoundException {// 1. Class.forNameString classAllPath = "java30.reflection.Car"; // 通过配置文件读取Class<?> aClass = Class.forName(classAllPath);System.out.println(aClass);// 2. 类.class 用于参数传递System.out.println(Car.class);// 3. 对象.getClass() 有对象实例Car car = new Car();Class aClass1 = car.getClass();System.out.println(aClass1);// 4. 通过类加载器获取到类的Class对象// 4.1 先得到类加载器ClassLoader classLoader = car.getClass().getClassLoader();// 4.2 通过类加载器得到Class对象Class aClass2 = classLoader.loadClass(classAllPath);System.out.println(aClass2);// 5. 基本数据得到Class对象Class<Integer> integerClass = int.class;Class<Character> characterClass = char.class;Class<Boolean> booleanClass = boolean.class;System.out.println(integerClass); // int// 6. 包装类 .TYPE得到Class类对象Class<Integer> type1 = Integer.TYPE;Class<Character> type2 = Character.TYPE;System.out.println(type1); // int}}
五、类加载
5.1 简介
静态加载:编译时加载相关的类 依赖性强 当创建对象(new)、子类被加载,父类也加载、调用类中的静态成员时
动态加载:运行时需要加载的类 依赖性低 通过反射
- 类加载过程图
5.2 类加载各阶段
5.2.1 加载
由类加载器完成,将字节码从class文件,jar包等数据源转化为二进制字节流加载到内存中,并生成一个Class对象
5.2.2 连接
5.2.2.1 验证
- 确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机安全
- 包括文件格式验证、元数据验证、字节码验证和符号引用验证
-Xverify:none参数关闭大部分的类验证措施,缩短虚拟机类加载的时间
5.2.2.2 准备
JVM对静态变量分配内存并默认初始化(默认为0,0L,null等)。这些变量使用的内存都在方法区中分配
5.2.2.3 解析
5.2.3 初始化
JVM对类进行初始化,主要针对静态成员
初始化阶段,才真正开始执行类中定义的Java程序,此阶段是执行
()方法的过程 ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值和静态代码块中的语句,并进行合并 public class ClassLoad {public static void main(String[] args) {/*clinit() {System.out.println("B静态代码块被执行");num = 300;num = 100; //这里会合并}*/// B b = new B();System.out.println(B.num);}}class B {static {System.out.println("B静态代码块被执行");num = 300;}static int num = 100;public B() {System.out.println("B() 构造器被执行");}}
六、通过反射获取类的结构信息
```java public class ReflectionUtils { public static void main(String[] args) {
} @Test public void method1() throws ClassNotFoundException, NoSuchMethodException {
// Class对象Class<?> personClass = Class.forName("java30.reflection.Person");// 全类名System.out.println(personClass.getName()); // java30.reflection.Person// 简单类名System.out.println(personClass.getSimpleName()); // Person// public修饰的属性,包括本类和父类的Field[] fields = personClass.getFields();for (Field field : fields) {System.out.println(field.getName()); // name a}// 本类中所有属性Field[] declaredFields = personClass.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println(declaredField.getName()); // name age josalary}// public修饰的方法 本类+父类 父类的父类..Method[] methods = personClass.getMethods();for (Method method : methods) {System.out.println(method.getName());}// 本类所有方法Method[] declaredMethods = personClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod.getName());}// public修饰的构造器Constructor<?>[] constructors = personClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor.getName());}// 本类中所有构造器Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor.getName()); // 只有名字,没有参数列表// 返回修饰符int modifiers = declaredConstructor.getModifiers();// 返回参数类型数组Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();}// 包信息System.out.println(personClass.getPackage()); // package java30.reflection// 父类class对象Class<?> superclass = personClass.getSuperclass();System.out.println(superclass); // class java30.reflection.A// 返回接口信息Class<?>[] interfaces = personClass.getInterfaces();for (Class<?> anInterface : interfaces) {System.out.println(anInterface);}// 形式返回注解信息Annotation[] annotations = personClass.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation); // @java.lang.Deprecated()}// 获取所有public修饰的方法,包括本类以及父类的Method[] declaredMethods1 = personClass.getDeclaredMethods();for (Method method : declaredMethods1) {System.out.println(method.getName());// 该方法的访问修饰符System.out.println(method.getModifiers());// 该方法返回类型System.out.println(method.getReturnType());// 形参数组Class<?>[] parameterTypes = method.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println(parameterType);}}
} @Test public void method2() throws ClassNotFoundException {
// Class对象Class<?> personClass = Class.forName("java30.reflection.Person");// 本类中所有属性Field[] declaredFields = personClass.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println(declaredField.getName()); // name age josalary// int形式返回修饰符 默认0,public 1,private 2,protected 4 static 8 final 16 public static 9System.out.println(declaredField.getModifiers());// 属性的类型System.out.println(declaredField.getType());}
} } class A { public String a; public void m5() {} public A() {} public A(String name) {} } interface IA {} interface IB {}
@Deprecated class Person extends A implements IA, IB { public String name; protected int age; String job;//默认 private double salary;
public Person() {}public Person(String name, int age, String job, double salary) {this.name = name;this.age = age;this.job = job;this.salary = salary;}public void m1() {}protected void m2() {}void m3() {}private void m4() {}
}
<a name="PbkAY"></a>## 七、反射创建对象```javapublic class ReflectCreateInstance {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class<?> uClass = Class.forName("java30.reflection.U");// 无参构造器创建实例Object o = uClass.newInstance();System.out.println(o);// public有参构造器创建实例Constructor<?> constructor = uClass.getConstructor(String.class);Object aaa = constructor.newInstance("aaa");System.out.println(aaa);// 非public有参构造器创建实例Constructor<?> declaredConstructor = uClass.getDeclaredConstructor(int.class, String.class);// 爆破 使用反射访问private的构造器、方法、属性declaredConstructor.setAccessible(true);Object c = declaredConstructor.newInstance(11, "c");System.out.println(c); // U{age=11, name='c'}}}class U {private int age = 10;private String name = "名字";public U() {}public U(String name) {this.name = name;}private U(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "U{" +"age=" + age +", name='" + name + '\'' +'}';}}
八、反射访问类中的成员
8.1 访问属性
public class ReflectAccessProperty {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {Class<?> u1Class = Class.forName("java30.reflection.U1");Object o = u1Class.newInstance();System.out.println(o.getClass()); // class java30.reflection.U1// 反射得到age对象Field age = u1Class.getField("age");age.set(o,20);System.out.println(o); // U1{age=20,name=null}System.out.println(age.get(o)); // 返回age属性的值 20// 反射得到nameField name = u1Class.getDeclaredField("name");// 爆破name.setAccessible(true);name.set(o,"d");System.out.println(o); // U1{age=20,name=d}}}class U1 {public int age = 10;private static String name;public U1() {}@Overridepublic String toString() {return "U1{" +"age=" + age + ",name=" + name +'}';}}
8.2 访问方法
public class ReflectAccessMethod {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class<?> u2Class = Class.forName("java30.reflection.U2");Object o = u2Class.newInstance();Method h = u2Class.getDeclaredMethod("h", String.class);h.invoke(o,"ddd");Method s = u2Class.getDeclaredMethod("s", int.class, String.class, char.class);s.setAccessible(true); //s是private的System.out.println(s.invoke(o,30,"sss",'d'));// s 方法私有 也能传入nullSystem.out.println(s.invoke(null,30,"sss",'d'));}}class M {}class U2 {public int age = 10;private static String name;public U2() {}public M m1() {return new M();}public static String s(int n, String s, char c) {return n+" "+s+" "+c;}public void h(String s) {System.out.println(s);}@Overridepublic String toString() {return "U1{" +"age=" + age + ",name=" + name +'}';}}
