反射
一、反射机制
程序在执行期间用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类型的对象cls
Class 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.Car
System.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.forName
String 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 9
System.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>
## 七、反射创建对象
```java
public 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;
}
@Override
public 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
// 反射得到name
Field 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() {
}
@Override
public 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 方法私有 也能传入null
System.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);
}
@Override
public String toString() {
return "U1{" +
"age=" + age + ",name=" + name +
'}';
}
}