15_Java反射机制——1.Java反射机制概述
1、反射的概述
- 反射的概念:是指程序在运行时,
1、确定操作的类
2、获取类的完整结构
3、调用对应的方法
- Java反射机制提供的功能
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时获取泛型信息
5、在运行时调用任意一个对象的成员变量和方法
6、在运行时处理注解
7、生成动态代理
2、反射之前,类的实例化等操作
Person 类用于测试
public class Person {
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age + '}';
}
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 Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
System.out.println("Person()");
}
public void show() {
System.out.println("你好, 我是一个好人。");
}
private String showNation(String nation) {
System.out.println("我的国籍是: " + nation);
return nation;
}
}
class PersonTest {
// 反射之前, 对于 Person 的操作
@Test
void testPerson1() {
// 1、创建 Person 类的对象
Person person = new Person("p1", 10);
// 2、通用对象, 调用其内部的属性、方法
person.age = 20; // 注意其声明为 public int age;
System.out.println(person);
// 在 Person 类外部, 不可以通过 Person 类的对象调用其内部私有结构
// 比如: name、showNation() 以及私有的构造器
person.show();
}
}
output
Person{name='p1', age=20}
你好, 我是一个人。
3、使用反射,实现类的实例化等操作
@Test
void testPerson2() throws Exception {
Class clazz = Person.class;
// 1、通过反射, 创建 Person 类的对象
// 注意这里的 int 不能改成 Integer
// 因为会报异常
// java.lang.NoSuchMethodException:
// main.java.com.atzwx.reflection.Person.<init>(java.lang.String, java.lang.Integer)
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object object = constructor.newInstance("personName", 10);
Person person = (Person) object;
System.out.println("object: " + object + " ----- " + "person: " + person);
// 2、通过反射, 调用对象指定的属性、方法
// 调用属性
Field age = clazz.getDeclaredField("age");
age.set(person, 20);
System.out.println("改变 person 的 age 属性之后");
System.out.println("object: " + object + " ----- " + "person: " + person);
// 调用方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(person);
}
output
object: Person{name='personName', age=10} ----- person: Person{name='personName', age=10}
改变 person 的 age 属性之后
object: Person{name='personName', age=20} ----- person: Person{name='personName', age=20}
你好, 我是一个人。
4、反射的强大,调用类的私有结构
System.out.println("*************调用类的私有结构***************");
// 通过反射,可以调用类的私有结构。比如: 私有的构造器、方法、属性
// 调用私有构造器
// 在调用私有构造器时, 使用 clazz.getConstructor 会报如下异常
// java.lang.NoSuchMethodException: main.java.com.atzwx.reflection.Person.<init>(java.lang.String)
// Constructor privatedConstructor = clazz.getConstructor(String.class);
// 注意一定要加 privatedConstructor.setAccessible(true), 否则会报如下异常
// java.lang.IllegalAccessException:
// Class test.java.com.atzwx.reflection.PersonTest
// can not access a member of class main.java.com.atzwx.reflection.Person with modifiers "private"
Constructor privatedConstructor = clazz.getDeclaredConstructor(String.class);
privatedConstructor.setAccessible(true);
Person person1 = (Person) privatedConstructor.newInstance("privatedConstructor");
System.out.println(person1);
// 调用私有属性
Field privatedField = clazz.getDeclaredField("name");
privatedField.setAccessible(true);
privatedField.set(person1, "privatedField");
System.out.println(person1);
// 调用私有方法
Method privatedMethod = clazz.getDeclaredMethod("showNation", String.class);
privatedMethod.setAccessible(true);
// 相当于 String nation = person1.showNathon("中国")
String nation = (String) privatedMethod.invoke(person1, "中国");
System.out.println("nation: " + nation);
// 小总结
// 在调用类的私有结构前,必须加上 xxx.setAccessible(true), 获取权限。
output
*************调用类的私有结构***************
Person{name='privatedConstructor', age=0}
Person{name='privatedField', age=0}
我的国籍是: 中国
nation: 中国
5、如何看待反射和封装性两个技术
- 疑问1:通过直接 new 的方式或反射的方式都可以调用类的公共结构,开发中到底用哪个?
在编译时,就可以确定类的结构
建议:直接 new 的方式
什么时候会使用:反射的方式。
在运行时,不确定创建哪个类。
反射的特征:动态性
- 疑问2:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?
不矛盾。
封装性:关注的是调用类的哪些结构
反射机制:关注的是能不能调用