一、什么是反射?
用光的反射来说明,光在遇到玻璃、水面等其他介质的时候,在分界面上又返回原来物质的一种现象。
二、应用场景
在Java的业务开发中,平常很少用到反射原理,也就不怎么接触到反射机制。但是,因为反射我们才能使用各种框架。例如Spring/Spring Boot 、MyBatis等许多框架中都用到了反射机制。
三、优点和缺点
优点:能够让代码更加的灵活,同时也为各种框架提供了便利。 缺点:我们都知道Java 的特性包括封装,恰巧反射机制就破坏了这种封装机制。同时也增加了一些安全问题。同时,反射的性能也稍微的差一点。不过在框架中这种性能差异显得微乎其微。
四、反射示例
4.1、获取Class对象的方式
通过前面的说明,我们知道一定要通过一种介质才能得到想要的对象。而这个介质就是Class类。 根据官网文档的解释,Class 类的实例表示正在运行的 Java 应用程序中的类和接口。Class 类的实例表示正在运行的 Java 应用程序中的类和接口。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
4.1.1 知道具体类
Class clazz = TargetClass.class ;
我们已知一个类,通过.class 这种方式就能获取到对应的Class 实例。 但是我们一般是不知道具体的类,通过遍历包下面的类来获取对象,通过此方式获取的Class 对象不会进行初始化。
4.1.2 通过Class.forName() 传入类的路径
Class clazz = Class.forName(" com.test.TargetClass");
例如在Jdbc的连接中,我们要获取驱动,一般就用这种方式来获取相应的Class 实例。
4.1.3 通过对象实例instance.getClass() 获取
TargetClass object = new TargetClass();
Class clazz = object.getClass();
4.1.4 通过类加载器传入路径
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class clazz = loader.loadClass("com.base.TargetClass");
通过类加载器加载一个类获取Class对象时不会进行初始化。也就意味着构造方法和类初始化器都不会被执行。只有new对象时,这些才会执行。
五、反射的基本操作
5.1、创建一个用来反射操作的类。
public class Apple {
private String name ;
public Apple(){
name = "苹果";
}
public void show( String s ){
System.out.println( "我最喜欢:" + s );
}
private void otherShow(){
System.out.println( "我是:" + name );
}
}
5.2 使用反射
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectApple {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class<?> clazz = Apple.class;
Class<?> clazz2 = Class.forName("com.base.Apple");
Apple apple1 = new Apple();
Class<?> clazz3 = apple1.getClass();
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> clazz4 = loader.loadClass("com.base.Apple");
Apple apple = (Apple)clazz.newInstance();
Method[] methods = clazz2.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
Field[] fields = clazz3.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
Method showMethod = clazz4.getDeclaredMethod("show" , String.class );
showMethod.invoke( apple , "水果");
Field field = clazz.getDeclaredField("name");
field.setAccessible( true );
field.set( apple , "柠檬");
Method otherShowMethod = clazz.getDeclaredMethod("otherShow" );
otherShowMethod.setAccessible( true );
otherShowMethod.invoke( apple );
}
}
输出的内容如下 show wait wait wait equals toString hashCode getClass notify notifyAll 我最喜欢:水果 我是:柠檬
如输出的结果所示,这里的show方法是我们自己定义的。其他的方法则是继承Object 。 在遍历方法的时候,并不会获取到私有方法,所以遍历时并不会显示otherShow 这个方法。 注意在getDeclaredMethod 获取指定方法的时候,如果要操作的方法中带有参数,则要加入相应的参数类型Class 实例。
以上内容是参考了书集和官方文档以及自己测试结果所写,全部为个人理解。如果有错误请批评指正。 转载请注明出处,谢谢。
|