学Java的时候,老师都会告诉我们一句很经典的话: 万事万物皆对象。
在Java的世界里每一个对象都是一个类的实例。同样的,类也是某一个类的对象,换句话说,是某一个类的实例。 所有的类,都是Class类的实例。
明确上一段话的内容,就可以开始试着理解 反射 的概念了。
JAVA反射(Reflection): 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
在没有利用反射机制的程序中,对于类的属性和方法我们需要通过创建对象调用;有了反射,我们就可以利用Field、Method、Constructor等类来调用类中的属性、方法、构造器。(小白浅见,期待指正)
明确了反射的概念,就可一开始着手学习反射的一些操作了。
反射和之前学习的new对象有什么差别呢?让我们先看一个实例: 先创建一个Person类:
/** * @author ☂࿈秋鹜࿈ ️ * @create 2020/3/9 12:20 */ public class Person { private String name; public int age; public int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public Person(String name, int age) { this.name = name; this.age = age; } private Person(String name) { this.name = name; } public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void show(){ System.out.println("你好,我是一个人。"); } public String showName(String name){ System.out.println("我的名字是:" + name); return name; } private static void showDesc(){ System.out.println("我是一个可爱的人"); } } 复制代码
然后分别动态和静态的创建对象:
/** * @author ☂࿈秋鹜࿈ ️ * @create 2020/3/9 12:28 */ public class ReflectionTest { /** * 静态创建 */ public void test1(){ //创建Person类的对象 Person p1 = new Person("Tom",12); } /** * 动态创建 */ public void test2() throws Exception{ Class clazz = Person.class; //通过反,创建Person类的对象 Constructor cons = clazz.getConstructor(String.class,int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person) obj; } 复制代码
值得注意的是,在静态调用时,我们只需要new类的构造器就可以了。当我们想静态调用Person类时,需要先获取Person类的Class类对象(“类”的类),然后用getConstructor()方法获取Person类的构造器,最后用获取到的构造器对象调用newInstance()方法完成了 对象的创建 。他的基本原理就是通过反射 获取构造器来创建对象 。
如何获取运行时类的实例?==方法有四==。
/** * 获取Class的实例对象 */ public void test3() throws ClassNotFoundException { //方法一:调用运行时类的属性:.class Class clazz1 = Person.class; System.out.println(clazz1); //方法二:通过运行时类的对象,调用getClass() Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(p1); //方法三:调用Class的静态方法:forName(String classPath) Class clazz3 = Class.forName("com.langsin.java.Person"); System.out.println(clazz3); //方法四:使用类加载器:ClassLoader ClassLoader classLoader = ReentrantLock.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.langsin.java.Person"); System.out.println(clazz4); //结果为true,证明都是同一个对象 System.out.println(clazz1 == clazz2); System.out.println(clazz1 == clazz3); System.out.println(clazz1 == clazz4); } 复制代码
通过上述四种方法,我们就可以获取到运行时类的Class的对象。对于这四种方法,最能体现“动态”的方法是方法三。因为在运行前并不确定是有这个类,只是根据指定的类路径寻找类,所以最为动态。
通过Class的实例,我们可以利用Field、Method、Constructor来调用类中的属性、方法和构造器。
/** * @author ☂࿈秋鹜࿈ ️ * @create 2020/3/9 12:28 */ public class ReflectionTest { /** * 调用属性、方法、构造器 */ public void test2() throws Exception{ Class clazz = Person.class; //调用构造器,创建Person实例 Constructor cons = clazz.getConstructor(String.class,int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person) obj; System.out.println(obj.toString()); //通过反射,调用兑现指定的属性、方法 //调用属性 Field age = clazz.getDeclaredField("age"); age.set(p,10); System.out.println(obj.toString()); System.out.println("***************"); //调用方法 Method show = clazz.getDeclaredMethod("show"); show.invoke(p); //通过反射,可以调用Person类的私有构造的。比如:私有的构造器、方法、属性 //调用私有的构造器 Constructor cons1 = clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1 = (Person) cons1.newInstance("jerry"); System.out.println(p1); //调用私有的属性 Field name = clazz.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"HanMeimei"); System.out.println(p1); //调用私有的方法 Method showNation = clazz.getDeclaredMethod("showName",String.class); showNation.setAccessible(true); showNation.invoke(p1,"中国"); } 复制代码
反射机制不仅仅能利用在获取运行时类,还能获取Java的配置文件。
配置文件:
user=老吴 password=123 复制代码
反射获取配置文件:
/** * Properties:用来读取配置文件 */ public void propertiesTest() throws IOException { Properties pros = new Properties(); //读取配置文件方式一:IO+Properties // FileInputStream fis = new FileInputStream("ReflectTest/jdbc.properties"); // pros.load(fis); //读取文件方式二:使用ClassLoader(配置文件默认识别为 当前module的src下) ClassLoader classLoader = ReflectionTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc1.properties"); pros.load(is); String user = pros.getProperty("user"); String password = pros.getProperty("password"); System.out.println("user=" + user + ",password=" + password); } 复制代码