反射机制
指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.
反射机制常用的类:
Java.lang.Class; //代表一个类
Java.lang.reflect.Constructor; //代表类的构造器
Java.lang.reflect.Field; //代表类的成员变量
Java.lang.reflect.Method; //代表类的方法
Java.lang.reflect.Modifier;
反射的基本使用:
不使用反射的处理:
1 public class Person { 2 private String name; 3 public int age; 4 5 public String getName() { 6 return name; 7 } 8 9 public void setName(String name) { 10 this.name = name; 11 } 12 13 public int getAge() { 14 return age; 15 } 16 17 public void setAge(int age) { 18 this.age = age; 19 } 20 21 public Person(String name, int age) { 22 this.name = name; 23 this.age = age; 24 } 25 26 private Person(String name) { 27 this.name = name; 28 } 29 public Person(){ 30 31 } 32 33 @Override 34 public String toString() { 35 return "Person{" + 36 "name='" + name + '\'' + 37 ", age=" + age + 38 '}'; 39 } 40 public void show(){ 41 System.out.println("hello"); 42 } 43 private String showNation(String nation){ 44 System.out.println("中国"); 45 return nation; 46 } 47 }
使用反射机制:
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 public class ReflectTest { 6 /** 7 * 不使用反射的情况 8 */ 9 @Test 10 public void test01(){ 11 Person person = new Person("jack",20); 12 person.age=15; 13 System.out.println(person.toString()); 14 person.show(); 15 //在Person类的外部,不可以通过Person类的对象调用其内部私有的结构。 16 //比如:name、showNation以及私有的构造器。 17 } 18 19 /** 20 * 使用反射的情况 21 */ 22 @Test 23 public void test02() throws Exception { 24 //1.通过反射,创建Person类的对象 25 Class clazz = Person.class; 26 Constructor cons = clazz.getConstructor(String.class,int.class); 27 Object obj = cons.newInstance("john",21); 28 Person person = (Person) obj; 29 System.out.println(person.toString()); 30 //2.通过反射,调用对象指定的属性和方法 31 //调用属性 32 Field age = clazz.getDeclaredField("age"); 33 age.set(person,11); 34 System.out.println(person.toString()); 35 //调用方法 36 Method show = clazz.getDeclaredMethod("show"); 37 show.invoke(person); 38 System.out.println("============"); 39 //通过反射,是可以调用Person类的私有结构的。比如:私有的构造器、方法、属性 40 //调用私有的构造器 41 Constructor constructor = clazz.getDeclaredConstructor(String.class); 42 constructor.setAccessible(true); 43 Person p = (Person) constructor.newInstance("kk"); 44 System.out.println(p); 45 //调用私有的属性 46 Field name = clazz.getDeclaredField("name"); 47 name.setAccessible(true); 48 name.set(p,"zz"); 49 System.out.println(p); 50 51 //调用私有的方法 52 Method showNation = clazz.getDeclaredMethod("showNation",String.class); 53 showNation.setAccessible(true); 54 String nation = (String) showNation.invoke(p,"china"); 55 // 相当于String nation = p1.showNation("FaceBook") 56 System.out.println(nation); 57 58 } 59 60 }
理解Class类并获取Class实例
关于java.lang.Class类的理解
类的加载过程:
1.程序经过Javac.exe命令后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
2.换句话说,Class的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的个时间。在此时间内,我们可以通过不同的方式来获取此运行时类。
获取class实例的方式
1 import org.junit.Test; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Field; 6 import java.lang.reflect.Method; 7 8 public class ReflectionTest { 9 10 @Test 11 public void test3() throws ClassNotFoundException { 12 //方式一:调用运行时类的属性 13 Class c1 = Person.class; 14 System.out.println(c1); 15 16 //方式二:通过运行时类的对象,调用getClass() 17 Person p1 = new Person(); 18 Class c2 = p1.getClass(); 19 System.out.println(c2); 20 21 //方式三:调用Class的静态方法:forName(String classPath) 22 Class c3 = Class.forName("java.lang.String"); 23 System.out.println(c3); 24 25 System.out.println(c1 == c2); 26 System.out.println(c1 == c3); 27 28 //方式四:使用类的加载器:ClassLoader (了解) 29 ClassLoader classLoader = ReflectionTest.class.getClassLoader(); 30 Class c4 = classLoader.loadClass("java.lang.String"); 31 System.out.println(c4); 32 33 System.out.println(c1 == c4); 34 } 35 }
哪些类型可以有Class对象
class
:外部类, 成员(成员内部类, 静态内部类), 局部内部类, 匿名内部类interface
: 接口[]
:数组enum
:枚举annotation
:注解@interface
primitive type
:基本数据类型void
使用ClassLoader加载配置文件
1 import org.junit.Test; 2 3 import java.io.FileInputStream; 4 import java.io.InputStream; 5 import java.util.Properties; 6 7 public class PropertiesTest { 8 @Test 9 public void test01() throws Exception{ 10 Properties properties = new Properties(); 11 //读取配置文件的方式一,此时文件路径默认在当前的module下 12 //FileInputStream fileInputStream = new FileInputStream("jdbc.properties"); 13 //FileInputStream fileInputStream = new FileInputStream("src/jdbc1.properties"); 14 //properties.load(fileInputStream); 15 16 //读取配置文件的方式2,此时文件路径默认识别为当前module下的src 17 ClassLoader classLoader = ClassLoadingTest.class.getClassLoader(); 18 InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc1.properties"); 19 properties.load(resourceAsStream); 20 21 String user = properties.getProperty("user"); 22 String password = properties.getProperty("password"); 23 System.out.println("user=:"+user+";passward:"+password); 24 } 25 }
通过Class对象,创建运行时类的对象,通过调用Class对象的newInstance()方法
1 import org.junit.Test; 2 import pers.chh3213.reflectionDemo.Person; 3 4 public class NewInstanceTest { 5 6 @Test 7 public void test() throws Exception{ 8 Class<Person> clazz = Person.class; 9 /** 10 * newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。 11 * 12 * 要想此方法正常的创建运行时类的对象,要求: 13 * 1.运行时类必须提供空参的构造器 14 * 2.空参的构造器的访问权限得够。通常,设置为public。 15 * 16 * 在javabean中要求提供一个public的空参构造器。原因: 17 * 1.便于通过反射,创建运行时类的对象 18 * 2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器 19 */ 20 Person obj = clazz.newInstance(); 21 System.out.println(obj); 22 } 23 24 }
反射机制的动态性体现
1 import org.junit.Test; 2 3 import java.util.Random; 4 5 public class NewInstanceTest2 { 6 @Test 7 public void test2(){ 8 for (int i = 0; i < 100; i++) { 9 int num = new Random().nextInt(3); 10 String classpath = ""; 11 switch (num){ 12 case 0: 13 classpath = "java.util.Date"; 14 break; 15 case 1: 16 classpath = "java.lang.Object"; 17 break; 18 case 2: 19 classpath = "pers.chh3213.reflectionDemo.Person"; 20 break; 21 } 22 try { 23 Object obj = getInstance(classpath); 24 System.out.println(obj); 25 }catch (Exception e){ 26 e.printStackTrace(); 27 } 28 } 29 30 } 31 /** 32 * 创建一个指定类的对象。 33 * classPath:指定类的全类名 34 * 35 * @param classPath 36 * @return 37 * @throws Exception 38 */ 39 public Object getInstance(String classPath) throws Exception { 40 Class clazz = Class.forName(classPath); 41 return clazz.newInstance(); 42 } 43 }
具体创建哪个类的对象,直到运行时才能确定
参考博客:https://blog.csdn.net/weixin_42301220/article/details/122639224
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)