反射理解
简单理解
按照传统写法,想要调用一个方法,就需要new一个对象,再通过对象去.这个方法。而反射则是先通过外部的配置文件,去获取到该类和方法名,再调用他的invoke()方法来执行该方法。如下代码
//不使用反射:
Cat cat = new Cat();
cat.hello();
//使用配置文件和反射
配置文件内容:
method=hello
classfullpath=com.sky.llx.Cat
//读取配置文件调用 , 最终只能读取到字符串类型,不能创建对象
Properties properties = new Properties();
properties.load(new FileInputStream("src/main/java/re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String method = properties.get("method").toString();
System.out.println(classfullpath + "===" + method);
//使用反射机制来解决
//通过类路径来加载这个类
Class cla = Class.forName(classfullpath);
//获得类加载的对象实例
Object o = cla.newInstance();
System.out.println(o.getClass());
//可以直接强转、但是这样和直接new并没有区别
// Cat cat2 = (Cat) o;
// cat2.hello();
//通过方法名来获取到当前类中对应的方法
Method method1 = cla.getMethod(method);
//执行该方法'
System.out.println("===================");
method1.invoke(o);
单纯从这方面来看,反射相对传统方法来说十分麻烦。
但是,如果想要更改调用的方法,反射的好处就体现出来了
假设上述代码为源码,如刚刚的调用的为hello方法,如果下次想调用hi 方法,传统的方法中是写死的,不是动态的,想要调用只能修改源码。而通过反射来操作的话,只需要修改配置文件,就可以成功换方法。因为源代码的使用的反射,是动态获取的。
许多的框架的原理也就是反射,通过外部的配置文件来在不修改源代码的情况下,符合设计模式ocp(开闭原则,不修改源代码,扩容功能)。
反射的缺点:对执行速度有影响,耗时较高。。。
Class类
Class cla = Class.forName(classfullpath);
//代码原理
//Class类也是类,因此也会去继承Object类
//Class类最后会根据类路径来调用类加载器来创建对象
//对于某个类的Class类对象,在内存中只有一份,因此类只加载一次。
//每个类的实例都会记得自己是由哪个Class实例生成
//可以通过调用Class来得到一个完整的类的结构
//Class对象也是放在堆中的
=====Class调用的方法======
//获取 路径类 对应的 Class 对象
System.out.println(Class.forName(classfullpath));
//获取 运行类型
System.out.println(Class.forName(classfullpath).getClass());
// 获取包名
System.out.println(Class.forName(classfullpath).getPackage());
// 获取类名
System.out.println(Class.forName(classfullpath).getName());
// 创建 路径类 对应的 对象实例
System.out.println(Class.forName(classfullpath).newInstance());
// 获取属性 此时获取的属性不能是私有的否则会报错
System.out.println(Class.forName(classfullpath).getField("属性名"));
// 给对应的属性赋值
Class.forName(classfullpath).getField("属性名").set("属性名","值");
// 遍历获取所有的属性
Field[] fields = Class.forName(classfullpath).getFields();
Arrays.stream(fields).forEach(System.out::println);
传统的New一个对象属于静态加载,即只要代码中有new对象的代码,无论该对象代码是否执行,都会进行加载,如果没有该类就会报错。
反射创建对象则属于动态加载,只有当执行到改代码时才会加载,如果没有该类,并且未执行该代码,则不会报错,只有当执行该代码且没有对应的类时才会报错。