文章目录
java反射技术
什么是反射技术
1.java反射机制的核心是在程序运行时动态加载类并获取类的的详细信息,从而获取对象的各种信息.
2.java属于先编译后运行的语言,程序中对象的类型在编译时期就定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以就没有被加载到jvm,通过反射,可以在运行时动态的创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁.
- java单设机制l可以动态方式获取class相关信息,class中成员方法,属性,反射技术灵活调用方法,或者给我们的成员属性赋值.class.forName 初始化对象(创建对象)
- 图解
简单回顾双亲委派机制
当一个类加载器收到了类加载的请求时,他不会直接去加载指定的类,而是把这个请求委托给自己的父类加载器去加载,只有当父类加载器无法加载这个类的时候,才会由当前这个加载器来负责类的加载.
- 启动(Bootstrap) ClassLoader(启动类加载器):主要负责加载java核心类库,%JRE_HOME%\bin下的rt.jar,resources.jar,charsets.jar和class等.
- Extention ClassLoader(扩展类加载器):主要负责加载java核心类库,%JRE_HOME%\lib\ext目录下的jar包和class文件.
- Application ClassLoader(应用程序类加载器):主要负责加载当前应用的classpath下的所有类
- User ClassLoader(应用程序类加载器):主要负责当前应用的classpath下的所有类
- 这四种类加载器存在如下关系,当进行类加载器的时候,虽然用户自定义类不会由bootstrap classloader或是extention classloader加载(由类加载器的加载范围决定),但是代码实现还是会一直委托到bootstrap classloader,上层无法加载,再由下层决定是否可以加载,如果都无法加载,就会触发findclass,抛出classNotFoundException
- 意义:
1.通过双亲委派的方式,可以避免类的重复加载,当父类加载器已经加载过某一个子类时,只会加载JAVA_HOME中的jar包里的类,如java.long.integer,那么这个类是不会被随意替换的,除非有人抛到你的机器上,破坏你的JDK.那么就可以避免有人自定义一个有破坏功能的java.long.Integer被加载.这样可以有效防止核心Java API被篡改.
反射的优缺点
- 优点:在运行时获取类的各种内容,进行反编译,对于java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象.
- 缺点:
1.反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要反射.
2.反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题.
反射机制应用场景
- JDBC中的Class.forName(“包名.类名”)
- Spring底层基于反射初始化对象
- 第三方框架扩展功能
反射机制核心类
- java.lang.Class :代表正在运行的java类或接口
- java.lang.reflect.Constructor
- java.lang.reflect.Field
- java.lang.reflrct.Method
- java.lang.reflect.Modifier
反射机制API使用
获取Class
1.获取Class:三种方式:
1)Object---->getClass
2)任何数据类型(包括基本的数据类型)都有一个"静态"的class属性
3)通过class类的静态方法:forName(String className)常用
参数:全限定名称
public class ReflexTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//反射技术创建对象
Class<?> aClass = Class.forName("com.Reflex");
//创建对象
Reflex r = (Reflex) aClass.newInstance();
System.out.println(r);
//通过反射走有参构造方法
Constructor<?> constructor = aClass.getConstructor(String.class,int.class);
Reflex r1= (Reflex) constructor.newInstance("蔡徐坤", 23);//获取所有共有构造方法
System.out.println(r1);
}
}
获取成员属性
- 批量的
1.Field[ ] getFields():获取所有"公开子段"
2.Field[] getDeclaerDield():获取所有子段,包括:私有,保护,默认,公有; - 单个的
1.public Field getField(String fieldName):获取某个"公有的"子段
2.public Field getDeclaredField(String fieldName):获取某个子段(可以是私有的) - 设置子段的值
1.Field---->public void set(Object obj,Object value):
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchFieldException, InstantiationException, IllegalAccessException {
//获取class成员属性(反射给成员属性赋值,反射调用方法)
//反射技术创建对象
Class<?> aClass = Class.forName("com.Reflex");
Field[] fields = aClass.getFields();//获取所有共有字段
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = aClass.getDeclaredFields();//获取所有字段
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//给成员属性赋值
Reflex reflex = (Reflex) aClass.newInstance();
Field name = aClass.getDeclaredField("name");
//通过反射给成员属性赋值,先设置权限
//抑制java语言检查功能
name.setAccessible(true);
name.set(reflex,"蔡训坤");
System.out.println(reflex.getName());
}
}
反射获取成员方法
- 所有的方法
1.public Method[] getMethods()获取所有"公有方法"(包含父类Object类)
2.获取单个方法:
1.public Method getMethod(String name.Class)<?>...parameter(Types): 参数: name 方法名 Class...:形参的Class类型对象 public Method getDeclaerdMethod(String name,Class<?>…parameterTypes)
public class Test1 {
private static Object Reflex;
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<?> aClass = Class.forName("com.Reflex");
//输出所有共有方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取所有方法不能获取Object
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//给私有方法赋值
Method show = aClass.getDeclaredMethod("show", String.class, int.class);
//创建实例
Reflex reflex = (Reflex) aClass.newInstance();
show.setAccessible(true);
String str=(String) show.invoke(reflex,"蔡训坤",23);
System.out.println(str);
}
}
反射的应用
1.ArraryList里面如何添加字符串
2.读取.properties文件的方式,让程序更加灵活