反射入门篇幅有点长,但我不想打散了,因为只看其中一部分也没啥意义,所以分为了上中下3篇,写的不好的方面,希望大家指出
简介
反射能干什么?你只需要给我一个类的地址,我就能知道类的全部信息(类名称、父类、继承的接口、方法、属性、甚至实例化并赋值),那么下面我们就来看看它怎么办到的吧!
预备工作
这次我们准备用了一个Customer类,我们把它当成反射的对象,我们希望通过反射获取它的全部信息,我们先来看看这个类吧!
- Customer类,(包名有点随意了):
- (注意,下面要用)有一个无参数构造方法和一个private的构造方法
- 为了方便后面测试效果,实现了Person接口,但是Person接口没有抽象方法
package com.bridge.security.util.bean;
/**
* @创建人 zhangtaiyuan
* @创建时间 2020/7/2
* @描述
*/
public class Customer implements Person{
private String name;
private String email;
private int age;
public Customer() { }
private Customer(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", age='" + age + '\'' +
'}';
}
}
- 什么也没做的Person接口
package com.bridge.security.util.bean;
public interface Person { }
上面准备好了,我们就可以通过反射获取Customer类信息了
获得Class信息
获得对象信息之前,我们必须获得Class信息,然后从Class中获取类对应的信息,获取Clss有3种方法,如下:
- 通过实体类获得
Customer customer = new Customer() ; // 已经存在有指定类的实例化对象
Class<? extends Customer> cls = customer.getClass() ;
System.out.println(cls.getName()); //输出结果:com.bridge.security.util.bean.Customer
- 直接从XXX.class获得
Class<? extends Customer> cls = Customer.class;
System.out.println(cls.getName()); //输出结果:com.bridge.security.util.bean.Customer
- 从类的路径获得
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(cls.getName());//输出结果:com.bridge.security.util.bean.Customer
上面3个方式获得的Class都一样,最后一个通过传入String就能获得Class对象,是不是让我们想起了JDBC,哈哈
通过Class获得各种属性
通过Class实例化对象
- 在JDK9之前:
class.newInstance()
(jDK9开始不建议使用这个方法了) - 在JDK9之后:
clazz.getDeclaredConstructor().newInstance()
- 大部分公司还在用jdk8,所以例子用的9之前的方式:
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
Object obj = cls.newInstance() ; // 实例化对象,JDK 9后被废除了
//Object obj = cls.getDeclaredConstructor().newInstance() ; JDK 9之后才能用
System.out.println(obj); // 由于没有赋值:输出的都是null 输出结果:Customer{name='null', email='null', age='0'}
- 看着上面,你是不是明白了,如果没有反射,那么工厂模式创建实现类时,就会出现很多判断语句,并且当有新的工厂的实现类时,你就得修改代码并且升级版本,所以,没有反射,这种设计模式几乎不可能实现的(维护太麻烦)
通过Class获取属性
- 获得包路径:public Package getPackage();//比下面多一个“package”
- 获得包路径:public Package getPackageName();
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(cls.getPackage()); // package com.bridge.security.util.bean
System.out.println(cls.getPackageName()); // com.bridge.security.util.bean
- 获得父类:public Class<? super T> getSuperclass()
Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
Class superclass = cls.getSuperclass();// 返回的是class
System.out.println(superclass);// class java.lang.Object
- 获得接口:public Class<?>[] getInterfaces()
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Class<?> inter:clazz.getInterfaces()){ //获得接口,是一个class数组
System.out.println(inter.getName()); //com.bridge.security.util.bean.Person
}
- 构造方法
-
获取所有构造方法:public Constructor<?>[] getDeclaredConstructors()
-
获取指定的构造方法:public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
-
获取所有公开的构造方法:public Constructor<?>[] getConstructors()
-
获取公开的指定构造方法:public Constructor getConstructor(Class<?>… parameterTypes)
- 全部构造方法
-
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Constructor<?> constructor:clazz.getDeclaredConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法
System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
}
/**
* 下面是输出结果
* com.bridge.security.util.bean.Customer[]
* com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
*/
- 指定构成方法
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(clazz.getDeclaredConstructor().getName() + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes()));
//下面是获得private 的够着方法
System.out.println(clazz.getDeclaredConstructor(String.class,String.class,int.class).getName() + Arrays.toString(clazz.getDeclaredConstructor(String.class,String.class,int.class).getParameterTypes()));
/**
* 输出结果:
* com.bridge.security.util.bean.Customer[]
* com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
*/
- 公开的构造方法,下面就没有private构造方法了
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
for (Constructor<?> constructor:clazz.getConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法
System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
}
/**
* 下面是输出结果
* com.bridge.security.util.bean.Customer[]
*/
- 指定的公开的构造方法,下面尝试去获得private的构造方法,就会直接报错
Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
System.out.println(clazz.getConstructor().getName() + Arrays.toString(clazz.getConstructor().getParameterTypes()));
//下面是获得private 的够着方法
System.out.println(clazz.getConstructor(String.class,String.class,int.class));
/**
* 输出结果:
* com.bridge.security.util.bean.Customer[]
* Exception in thread "main" java.lang.NoSuchMethodException: com.bridge.security.util.bean.Customer.<init>(java.lang.String, java.lang.String, int)
* at java.base/java.lang.Class.getConstructor0(Class.java:3322)
* at java.base/java.lang.Class.getConstructor(Class.java:2108)
* at com.bridge.security.util.bean.TestDemo.main(TestDemo.java:16)
*/
总结
反射提供了另外一种设计思路,比如工厂模式,很多框架软件里都能看到它应用场景,比如:JDBC
未完…… 还有反射入门(中、下)