目录:
反射
学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实例
如何获取运行时类的实例?==方法有四==。
/**
* 获取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);
}