1.反射机制概述
(1)reflection反射机制被视为动态语言(运行时改变内部结构的语言)的关键,借助于反射API取得任何累的内部信息,并能直接操作任意对象的内部属性和方法。
(2)加载完类之后,在堆内存的方法中就产生了一个Class类型的对象,这个对象包含了完整的类的结构信息,可以通过这个类看到类的结构。
// 反射: 实例化对象---------》getclass()方法---------------》得到完整的“包类”信息
(3)功能:
在运行时 判断对象所属的类、构造任意一个类的对象、判断任意一个类所具有的成员变量和方法、获取泛型信息 、调用任意一个对象的成员变量和方法、处理注解,生成动态代理
API:java.lang.Class 代表一个类
java.lang.reflect.Method 代表类方法
java.lang.reflect.Field 代表类的成员变量
java.lang.reflect.Construtor 代表类的构造器
package com.qiku.reflection; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 2022/6/1 21:19 * * @author yrc * @version JavaSE */ public class TestReflection { //反射之前 @Test public void test01(){ //创建Person对象 Person p1 = new Person("tom",12); p1.age=10; System.out.println(p1);//Person{name='tom', age=10} p1.show(); //不可调用其私有的成员变量和方法 例如 name 和shownation() } //反射之后 对于Person的操作 @Test public void test02() throws Exception { Class cc= Person.class; // 通过反射 创建 person对象 Constructor cons = cc.getConstructor(String.class, int.class); Object obj = cons.newInstance("Tom", 12); Person p=(Person)obj; System.out.println(p.toString()); //通过反射 获取对象指定的属性和方法 Field age = cc.getDeclaredField("age"); age.set(p,10);// System.out.println(p.toString());//Person{name='Tom', age=10} Method show = cc.getDeclaredMethod("show"); System.out.println(show); //通过反射 可以调用 Person类的私有属性,比如私有的构造器方法和属性 //调用私有的构造器 Constructor cons1 = cc.getDeclaredConstructor(String.class); //值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java // 语言访问检查;实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问 ; //由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的 cons1.setAccessible(true); Person p1 =(Person) cons1.newInstance("Jerry"); System.out.println(p1); //调用私有的属性 Field name = cc.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"Jack"); System.out.println(p1); //调用私有的方法 Method showNation = cc.getDeclaredMethod("showNation",String.class); showNation.setAccessible(true); //相当于 p1.showNation("中国"); 调用完此方法有个返回值 invoke的返回值就是nation String nation = (String)showNation.invoke(p1, "中国"); System.out.println(nation); //通过直接new对象的方式或者反射的方式都能调用公共的结构 ,开始之中到底用哪一个? // 建议直接用new的方式。反射的特征:动态性 //反射机制与面向对象的封装性是否矛盾?如何看待两种技术 // 封装性写一些实体类的时候使用 比如单例模式,提供一个私有的构造器 但是提供了个公开的方法 ,返回的是私有的静态对象 //反射解决的是能不能调的问题 /* java.lang.Class类的理解 1.类加载的过程: 程序经过javac.class命令以后,会生成一个或者多个字节码文件(.class结尾) 接着使用java.exe命令对某个字节码文件进行解析 运行。相当于将字节码文件加载到内存中,此过程就是类的加载加载到内存中的类,我们就称为运行时类此运行时类就作为Class的 一个实例。 2.on The other hand :Class的实例就对应着一个运行时类。 3.加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取运行时类。 */ } //获取Class的实例方式 @Test public void test03() throws ClassNotFoundException { //方式一:调用运行时类的属性:.class 泛型之后就不用强转了 Class<Person> cc1 = Person.class; System.out.println(cc1); // 方式二 通过运行时对象调用 getClass() Person p1= new Person(); Class cc2 = p1.getClass(); System.out.println(cc2); //方式三: 通过嗲用Class的静态方法 forName(String classPath) Class cc3 = Class.forName("com.qiku.reflection.TestReflection"); System.out.println(cc3); System.out.println(cc1==cc2); System.out.println(cc1==cc3); //方式四:类的加载器ClassLoader ClassLoader classLoader = TestReflection.class.getClassLoader(); Class cc4 = classLoader.loadClass("com.qiku.reflection.TestReflection"); System.out.println(cc4); System.out.println(cc1==cc4); //编译不确定 具有动态性 第三种方式最重要 } //class. 看i意识int,String, 数组 枚举类 注解 Class等等 ,还有只要数组的类型和维度一样 就是同一个Class }
package com.qiku.reflection; import org.junit.Test; import java.io.InputStream; import java.util.Properties; /** * 2022/6/6 21:30 * * @author yrc * @version JavaSE */ public class TestClassLoader { @Test public void test01(){ //对于自定义类 调用系统加载器进行加载 ClassLoader classLoader = TestClassLoader.class.getClassLoader(); System.out.println(classLoader); //调用系统加载器的getParent()获取扩展类加载器 ClassLoader parent = classLoader.getParent(); System.out.println(parent); //调用系统加载器的getParent()无法获取扩展类加载器 //引导加载器主要负责加载java的核心类库 无法加载自定义类的 ClassLoader parent1 = parent.getParent(); System.out.println(parent1); } @Test public void test02() throws Exception { // properties 读取配置文件 Properties properties =new Properties(); // FileInputStream fis= new FileInputStream("jdbc.properties"); // properties.load(fis); ClassLoader classLoader = ClassLoader.class.getClassLoader(); InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties"); properties.load(resourceAsStream); String user = properties.getProperty("user"); String password = properties.getProperty("password"); System.out.println("user"+user+"password"+password); } }