我是【envoke】,一个想在编程路上越走越远的人。
热爱技术、热爱开源、热爱编程。
- Stay hungry, stay foolish.(求知若饥,虚心若愚)
- Go big or go home.(要么牛逼,要么滚蛋)
如果您也对Java感兴趣,或者我的文章能帮助到您,给个点赞或关注把!
加入【Go Big】一起探讨、一起吹逼、一起前行。群号:243108249
相关阅读:
反射
反射可谓是设计框架的灵魂
什么是反射 ?
动态获取对象信息(类的名称、类的属性、类的方法
),并且根据对象信息进行对象创建、字符赋值、调用对象方法
的功能称之为反射机制。
反射的原理
在程序运行的时候获取到想要创造实例的类的信息,使用Class类来创建一个对应的实例。避免了使用new关键字,达到在程序运行时动态创建实例的效果。
反射的优点:
可以通过反射机制实现帮助程序实现扩展功能。比如说:实现spring ioc、pring mvc等。
反射的缺点:
- 违背了面向对象的原则,即使是private修饰的也能进行使用
- 性能上存在问题,java反射究竟消耗多少效率
应用场景:
- JDBC驱动加载(Class.forName())
- SpringIOC容器实现(< bean id=“user” class=“类的全路径”> )
- 自定义注解
- mybatis逆向工程、JPA、MybatisPlus等
获取反射的类模板
想要使用反射,我们先要获取类的模板Class,下面提供了三种获取类模板信息的方法
我们这里有一个贫血对象
public class Person {
private String name;
private Long id;
public Person(String name, Long id) {
System.out.println(">>>有参构造执行<<<");
this.name = name;
this.id = id;
}
public Person() {
System.out.println(">>>无参构造执行<<<");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
private void showName(String name){
System.out.println("反射执行方法, name: " + name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
通过类名的方式获取:
Class personClass = Person.class;
通过类的全路径获取:使用最多
Class<?> personClass = Class.forName("com.live.collection.Person");
通过对象的方式获取:基本上不用,我都有对象了,为何还要用反射呢
Person person = new Person();
Class<? extends Person> personClass = person.getClass();
反射创建对象
上一步我们已经拿到了类模板信息,接下来,我们就开始使用类模板信息创建对象了
创建对象主要有两种方式:
类模板直接创建,走的是无参构造:
Class<?> personClass = Class.forName("com.live.collection.Person");
Person person = (Person) personClass.newInstance();
System.out.println(person);
执行结果
>>>无参构造执行<<<
Person{name='null', id=null}
通过构造方法创建:
无参构造创建:
Class<?> personClass = Class.forName("com.live.collection.Person");
// 没有传递参数,获取的是无参构造函数
Constructor<?> pConstructor = personClass.getConstructor();
// 采用无参构造函数创建对象
Person person1 = (Person) pConstructor.newInstance();
System.out.println(person1);
执行结果:
>>>无参构造执行<<<
Person{name='null', id=null}
有参构造创建:
Class<?> personClass = Class.forName("com.live.collection.Person");
Constructor<?> moreConstructor = personClass.getConstructor(String.class, Long.class);
Person person2 = (Person) moreConstructor.newInstance("张三", 18L);
System.out.println(person2);
执行结果:
>>>有参构造执行<<<
Person{name='张三', id=18}
反射给对象的字段赋值
对象创建完成,接下来该给对象的字段赋值。
Class<?> personClass = Class.forName("com.live.collection.Person");
Person person = (Person) personClass.newInstance();
Field nameField = personClass.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(person, "小新");
Field idField = personClass.getDeclaredField("id");
idField.setAccessible(true);
idField.set(person, 9L);
System.out.println(person);
执行结果:
>>>无参构造执行<<<
Person{name='小新', id=9}
反射调用方法
反射如何调用对象的方法呢?
Class<?> personClass = Class.forName("com.live.collection.Person");
Person person = (Person) personClass.newInstance();
// 获取声明的方法,第一个参数为方法名称,第二个至后面都是参数类型列表(即每个参数的类型)
Method showNameMethod = personClass.getDeclaredMethod("showName", String.class);
// 设置权限
showNameMethod.setAccessible(true);
showNameMethod.invoke(person, "张三");
反射权限问题
上面在给对象的属性赋值,或者在调用方法时,我们会看到一个方法
setAccessible();
接下来我们谈论下该方法的作用
当我们的字段、方法、构造方法都是private修饰时,我们对对象进行的赋值、方法调用等都会触发权限不足的异常。
解决方案:在调用之前将权限设置为true
示例:
nameField.setAccessible(true);
showNameMethod.setAccessible(true);
反射的性能分析
相关阅读: Java反射性能问题,你真的需要考虑吗?