反射
在不修改源码的情况下来控制程序
ocp原则(开闭原则:不修改源码,扩容功能)
快速入门
修改properties的method 即可实现功能的修改
package reflect;
public class A {
public String name = "Superman";
public A() {
}
public A(String name) {
this.name = name;
}
public void f(){
System.out.println("hello,world");
}
public void f2(){
System.out.println("今天你好!");
}
}
/*
a.properties
classfullpath=reflect.A
method=f
*/
public class test {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\a.properties"));
String classfullpath = properties.getProperty("classfullpath");
String methodName = properties.getProperty("method");
//加载类 返回
Class<?> aClass = Class.forName(classfullpath);
System.out.println(aClass); //class reflect.A 哪个类的class对象
System.out.println(aClass.getClasses()); //运行时态 [Ljava.lang.Class;@5cad8086
System.out.println(aClass.getPackage().getName());//包名
System.out.println(aClass.getName());//全类名
//通过class 得到加载的类
Object o = aClass.newInstance();
//得到加载的类的 方法对象
Method method = aClass.getMethod(methodName);
//通过方法对象 来调用方法
method.invoke(o);
//获取成员变量 name
Field field = aClass.getField("name"); //不能获取私有的变量
System.out.println(field.get(o));
//获取构造器
Constructor<?> constructor = aClass.getConstructor();
System.out.println(constructor);
//获取带形参的构造器 形参的class对象
Constructor<?> constructor1 = aClass.getConstructor(String.class);
System.out.println(constructor1);
}
}
反射机制 java reflection
1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(成员变量,构造器,成员方法等)
2.加载玩类之后,在堆中就产生了一个Class对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到的类结构。
反射原理图
反射访问优化
setAccessible(false)
Class
传统 new A();
Class.forName
Class对象不是new 出来的是系统创建的
ClassLoader
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
某个类的class类对象,在内存中只有一份,类只能加载一次
每个类的实例都会记得是由那个Class实例所生的
Class对象放在堆中,类的字节码二进制数据是放在方法区的。类的元数据(包括 方法代码,变量名,方法名,访问权限等等)
获取Class对象
Properties properties = new Properties();
properties.load(new FileInputStream("src\\a.properties"));
String classfullpath = properties.getProperty("classfullpath");
String methodName = properties.getProperty("method");
// forName多用于配置文件,读取类的全路径 加载类
Class<?> aClass = forName(classfullpath);
System.out.println(aClass);
//类名.class 多用于参数传递
Class<A> aClass1 = A.class;
System.out.println(aClass1);
//有对象实例 直接getclass() 运行类型 就是这个类关联的Class对象
A a = new A();
System.out.println(a.getClass());
//通过类加载器来获取
ClassLoader classLoader = a.getClass().getClassLoader();
System.out.println(classLoader.loadClass(classfullpath));
//基本数据类型.class
Class<Integer> integerClass = int.class;
System.out.println(integerClass);
//包装类
Class<Integer> type = Integer.TYPE;
System.out.println(type);
有Class对象的类型
类加载
静态加载:编译就加载相关的类(new)
动态加载:运行需要加载时才加载相关的类(forName)
加载
连接
//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存
//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是 20
//3. n3 是 static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30
public int n1 = 10;
public static int n2 = 20;
public static final int n3 = 30;
初始化
通过反射获取类结构信息
使用反射修改类的私有属性(爆破)
public class ReflectCreatInstance {
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("reflect.User");
//无参构造器
Object user = aClass.newInstance();
//爆破属性
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(user,"mary");
//如果是static属性 Object 可以填null
Field salary = aClass.getDeclaredField("salary");
salary.setAccessible(true);
salary.set(null,4999.9);
System.out.println(user);
//方法
Method hello = aClass.getDeclaredMethod("hello",String.class);
hello.setAccessible(true);
hello.invoke(user,"jack");
Method hi = aClass.getDeclaredMethod("hi");
hi.setAccessible(true);
hi.invoke(null);
//有参构造器
Constructor<?> constructor = aClass.getConstructor(int.class);
Object user1 = constructor.newInstance(10);
System.out.println(user1);
//私有的构造器
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);
declaredConstructor.setAccessible(true);//爆破
Object user2 = declaredConstructor.newInstance(20, "rose");
System.out.println(user2);
}
}
class User{
private int age = 1;
private String name ="jack";
private static double salary = 999.9;
public User() {
}
public User(int age) {
this.age = age;
}
private User(int age, String name) {
this.age = age;
this.name = name;
}
private void hello(String name){
System.out.println("hello"+name);
}
private static void hi(){
System.out.println("hi");
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' + ", salary='" + salary + '\'' +
'}';
}
}