- 使用Propertier 类,可以读写配置文件
Propertier properties = new Properties(); properties.load(new FileInputStream("src\\re.properties"))//原路径 String classfullPath = properties.get("classfullpath").toString();//得到类信息 String method = properties.get("method").toString();//得到方法信息 System.out.println("classfullpath="+ classfulllpath); System,out.println("method="+ method);
- 创建对象,传统的方法,行不通 ====> 反射机制
- 使用反射机制解决
//(1)加载类,返回Class类型的对象cls Class acalss = Class.forName(classfullpath); //(2)通过 cls 得到你加载的类 Cat 的对象实例 Object o = cls.newInstance(); System.out.println(o.getClass());// 运行类型 //(3)通过 cls 得到你加载的类 Cat 的methodName "hi" 的方法对象 // 即:在反射中,可以把方法视为对象(万物皆对象) Method method1 = cls.getMethod(methodName); //(4)通过method1 调用方法: 即通过方法对象来实现调用方法 method1.invoke(o); //传统方法 对象.方法(), 反射机制 方法.invoke(对象) 说明:即通过外部文件配置,在不修改源码情况下,来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)
- 反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
- 加载完类之后,在堆中就产生了一个Class 类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过一个镜子看见类的结构,所以,形象的称之为:反射。
- Java反射机制原理示意图
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时的得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
- java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
- 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
- 缺点:使用反射基本是解释执行,对执行速度有影响。
- Method和Field、Constructor对象都有setAccessible() 方法
- setAccessible作用和禁用访问安全检查的开关
- 参数值为true表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为fasle则表示反射的对象执行访问检查
- Class类也是类,因此也继承Object类
- Class类对象不是new出来的,而是系统创建的
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由哪个Class实例所生成的
- 通过Class对象可以完整地得到一个类的完成结构,通过一系列API
- Class对象时存放在堆的
- 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码, 变量名, 方法名, 请求权限等等)
String classAllPath = "reflection.Car";
//获取到Car 类对应的 Class 对象
// 表示不确定的java 类型
Class<?> aClass = Class.forName(classAllPath);
//输出cls
System.out.println(aClass); //显示aClass 对象,是哪个类的Class reflection.Car
System.out.println(Class.class); //输出aClass 运行类型 java.lang.Class
//3. 得到包名
System.out.println(aClass.getPackage().getName());
//4.全类名
System.out.println(aClass.getName());
//5.通过aClass 创建一个对象实例
Car car =(Car) aClass.getConstructor().newInstance();
System.out.println(car);
//6. 通过反射获取属性 brand
Field color = aClass.getField("color");
System.out.println(color.get(car));
//7. 通过反射给属性赋值
color.set(car,"黄色");
System.out.println(color.get(car));
//8. 遍历所有属性
System.out.println("====================");
Field[] fields = aClass.getFields();
for( Field n : fields){
System.out.println(n.getName());
}
public static void main(String[] args) throws Exception { //1.Class.forName String classAllPath = "reflection.Car"; Class<?> aClass1 = Class.forName(classAllPath); Object o = aClass1.getConstructor().newInstance(); Field color = aClass1.getField("color"); System.out.println(color.get(o)); //2. 类名.class Class carClass2 = Car.class; System.out.println(carClass2); //3.对象.getClass(),应用场景,有对象实例 Car car = new Car(); Class aClass3 = car.getClass(); System.out.println(aClass3); //4.通过类的加载器(4中类加载器)来获取到类的Class 对象 // (1)先得到类加载器 car ClassLoader classLoader = car.getClass().getClassLoader(); // (2) 通过类加载器得到Class 对象 Class<?> aClass4 = classLoader.loadClass(classAllPath); System.out.println(aClass4); // 上四个均为同一个对象 System.out.println(aClass1.hashCode()); System.out.println(carClass2.hashCode()); System.out.println(aClass3.hashCode()); System.out.println(aClass4.hashCode()); //5.基本数据类型(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象 //Class aClass = 基本数据类型.class Class<Integer> integerClass = int.class; System.out.println(integerClass); Class<Character> characterClass = char.class; //6.基本数据类型对应的包装类,可以通过.type得到Class类对象 //Class aClass = 包装类.TYPE; Class<Integer> integerClass1 = Integer.class; System.out.println(integerClass1); Class<Boolean> booleanClass = Boolean.class; }
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface: 接口
- 数组
- enum: 枚举
- annotation : 注解
- 基本数据类型
- void
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载.
- 静态加载:编译时加载相关的类, 如果没有则报错,依赖性太强
- 动态加载: 运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性 ( 反射动态加载)
- 当创建对象时(new) //静态加载
- 当子类被加载时 //静态加载
- 调用类中的静态成员时 //静态加载
- 通过反射 //动态加载
JVM 在该阶段的主要目的是将字节码从不同的数据源(可能是class 文件、也可能是jar包,甚至网络) 转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class 对象
public int n1 = 10; public static int n2 = 20; public static final int n3 = 30; // n1 是实例属性,不是静态变量,因此在准备阶段,是不会分配内存 // n2 是静态变量,分配内存 n2 是默认初始化 0,而不是20 // n3 是static final 是常量,他和静态变量不一样,因为一旦赋值就不变 n3 = 30
虚拟机将常量池内的符号引用替换为直接引用的过程
- 到初始化阶段,才真正开始执行类中定义的java 程序代码,此阶段是执行 () 方法的过程
- () 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并.
- 虚拟机会保证一个类的() 方法在多线程环境中被正确地加锁、同步、如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的() 方法,其他线程都需要阻塞等待,知道活动线程执行() 方法完毕
- getName:获取全类名
- getSimpleName:获取简单类名
- getFields: 获取所有public 修饰的属性, 包含本类一级父类的
- getDeclaredFields: 获取本类中所有属性
- getMethods: 获取所有public 修饰的方法,包含本类以及父类的
- getDeclaredMethods: 获取本类中所有方法
- getConstructors: 获取所有public 修饰的构造器,包含本类所有public
- getDeclaredConstructors: 获取本类中 所有的构造器
- getPackage: 以Package 形式返回 包信息
- getSuperClass: 以Class 形式返回父类信息
- getInterfaces: 以Class[] 形式返回接口信息
- getAnnotations: 以Annotation[] 形式返回注解信息
getModfiers:以int 形式返回修饰符
[说明: 默认修饰符 是0, public 是1 ,private 是 2, protected 是4, static 是8 ,final 是 16]
getType:
以Class 形式返回类型
getName: 返回属性名
- 方式一: 调用类中的public 修饰的无参构造器
- 方式二: 调用类中的指定构造器
- Class类相关方法
- newInstance : 调用类中的无参构造器, 获取对应类的对象
- getConstructor(Class…cls): 根据参数列表,获取对应的public 构造器对象
- getDecalaredConstructor(Class…cls ): 根据参数列表,获取对应的构造器对象
- Constructor 类相关方法
- setAccessible: 暴破
- newInstance(Object…obj): 调用构造器
- 根据属性名获取Field对象
Field f = cls 对象.getDeclareField(属性名);
- 暴力破解: f.setAccseeible(true); //f 是Field
- 访问 f.set(o, 值); syso(f.get(o)); //o表示对象
- 注意: 如果是静态属性,则set 和 get中的参数o, 可以写成null
Class<?> aClass = Class.forName("reflection.Student"); Object o = aClass.getConstructor().newInstance(); System.out.println(o.getClass()); //3.使用反射得到 age 属性 Field age = aClass.getField("age"); age.set(o,100); System.out.println(o); //4.使用反射操作name 属性 Field name = aClass.getDeclaredField("name"); // name.setAccessible(true); name.set(o,"Pink");// 因为name是static 属性,因此 o 也可以写出null System.out.println(o);
- 根据方法名和参数列表获取Method方法对象 : Method m = cls.getDeclaredMethod(方法名, xx.class);
- 获取对象 : Object o = clazz.newInstance();
- 暴破: m.setAccessible(true);
- 访问: Object returnValue = m.invlke(o, 实参列表);
- 注意: 如果是静态方法, 则invoke 的参数o, 也可以写成null;
//1.得到Boss类对应的Class对象 Class<?> aClass = Class.forName("reflection.Boss"); //2.创建对象 Object o = aClass.getConstructor().newInstance(); //3. 得到hi方法对象 Method hi = aClass.getMethod("hi", String.class); //4. 调用 System.out.println(hi.invoke(o,"Tom")); //5.调用private static 方法 Method declaredMethod = aClass.getDeclaredMethod("say", int.class, String.class,char.class); declaredMethod.setAccessible(true); System.out.println(declaredMethod.invoke(o,20,"Jack",'w')); //在反射中,如果方法有返回值,统一按照 Object 返回
Class<?> aClass = Class.forName("java.io.File");
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("File类中的构造器为=" + declaredConstructor);
}
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class);
String FilePath ="E:\\myNew.txt";
Object file = declaredConstructor.newInstance(FilePath);
Method createNewFile = aClass.getMethod("createNewFile");//得到方法的对象
createNewFile.invoke(file);