Java基础关键_031_反射(一)
目 录
一、概述
二、获取 Class 的三种方式
1.Class.forName("完整全限定类名")
2.getClass()
3.class 属性
三、通过反射机制实例化对象
1.newInstance()(已过时)
2.配置文件利用反射机制实例化对象
四、反射 Class 的 Field
1.获取 Person 的属性
2.反编译 String 类的属性
3.通过反射为对象属性赋值
一、概述
- 反射机制是 JDK 中的一套类库,可以帮助操作或读取字节码文件;
- 很多 Java 框架底层都是基于反射机制实现的;
- 部分核心类:
- java.lang.Class:实例代表某个 class 文件 或 某一类型;
- java.lang.reflect.Field:实例代表类中的属性或字段;
- java.lang.reflect.Constructor:实例代表类中的构造方法;
- java.lang.reflect.Method:实例代表类中的方法。
二、获取 Class 的三种方式
1.Class.forName("完整全限定类名")
- 全限定类名含有包名,是 lang 包下的,【 java.lang 】也不可省略;
- 参数是字符串类型;
- 若类不存在,则会报 【 java.lang.ClassNotFoundException】异常;
- 此方法的执行,会导致类加载。
public class ReflectTest {
static {
System.out.println("static block");
}
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass1 = Class.forName("reflecttest.ReflectTest");
System.out.println(aClass1);
Class<?> aClass2 = Class.forName("java.lang.Integer");
System.out.println(aClass2);
}
}
2.getClass()
- 该方法通过引用去调用;
- 某类型的字节码文件在内存中仅存储一份。
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass1 = Class.forName("java.lang.String");
System.out.println(aClass1);
String str = "hello";
Class<?> aClass2 = str.getClass();
System.out.println(aClass2);
System.out.println(aClass1 == aClass2);
Class<?> aClass3 = Class.forName("reflecttest.ReflectTest");
System.out.println(aClass3);
ReflectTest reflectTest = new ReflectTest();
Class<? extends ReflectTest> aClass4 = reflectTest.getClass();
System.out.println(aClass4);
System.out.println(aClass3 == aClass4);
}
}
3.class 属性
在 Java 中,任何类型(包括基本数据类型)都有 class 属性,可以通过这个属性获取 Class 实例。
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException {
Class<Integer> intClass = int.class;
Class<Integer> integerClass = Integer.class;
System.out.println(intClass); // int
System.out.println(integerClass); // java.lang.Integer
}
}
三、通过反射机制实例化对象
那么,获取到 Class 有什么用处呢?
这就是通过反射机制实例化对象。
1.newInstance()(已过时)
public class Person {
private String name;
private int age;
public Person() {
System.out.println("Person 无参构造方法");
}
public Person(String name, int age) {
System.out.println("Person 有参构造方法");
this.name = name;
this.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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> personClass = Class.forName("reflecttest.Person");
System.out.println(personClass);
Person person = (Person) personClass.newInstance();
System.out.println(person);
}
}
- 以上代码通过 personClass 实例化 Person 类型对象;
- 原理:调用 Person 的无参构造方法实例化对象;
- 使用此方法实现对象实例化,必须保证该类存在无参构造方法,否则会报【java.lang.InstantiationException】异常;
- 从 jdk 9 开始,该方法被标注已过时。
2.配置文件利用反射机制实例化对象
# classInfo.properties 文件
className=reflecttest.Person
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
ResourceBundle resourceBundle = ResourceBundle.getBundle("reflecttest\\classInfo"); // 加载classInfo.properties文件
String className = resourceBundle.getString("className"); // 获取className的值
Class<?> aClass = Class.forName(className);
Object o = aClass.newInstance();
System.out.println(o);
}
}
那么,在想要灵活实例化其他对象时,无需修改 java 文件,只需要修改配置文件即可。例如:将实例化 Person 对象改为 实例化 Date 对象。
# classInfo.properties 文件
className=java.util.Date
四、反射 Class 的 Field
1.获取 Person 的属性
public class Person {
public String name;
private int age;
protected String sex;
public static String country;
public static final String job = "程序员";
}
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 反射获取类信息
Class<?> aClass = Class.forName("reflecttest.Person");
// 获取类中的所有被 public 修饰的属性
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.print(field.getName() + " "); // name country job
}
System.out.println();
// 获取类中的所有属性
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
// 获取属性名
System.out.print(declaredField.getName() + " "); // name age sex country job
}
System.out.println();
for (Field declaredField : declaredFields) {
// 获取属性类型
System.out.print(declaredField.getType().getName() + " "); // java.lang.String int java.lang.String java.lang.String java.lang.String
}
System.out.println();
for (Field declaredField : declaredFields) {
// 获取属性类型简单名称
System.out.print(declaredField.getType().getSimpleName() + " "); // String int String String String
}
System.out.println();
for (Field declaredField : declaredFields) {
// 获取属性的修饰符
System.out.print(declaredField.getModifiers() + " "); // 1 2 4 9 25
}
System.out.println();
for (Field declaredField : declaredFields) {
// 获取属性的修饰符名称
System.out.print(Modifier.toString(declaredField.getModifiers()) + " "); // public private protected public static public static final
}
}
}
2.反编译 String 类的属性
public class ReflectTest {
public static void main(String[] args) {
String str = new String();
// 获取类信息
Class<? extends String> aClass = str.getClass();
// 获取类修饰符
String classMod = Modifier.toString(aClass.getModifiers());
// 获取简单类名
String className = aClass.getSimpleName();
// 获取简单父类名
String classSupName = aClass.getSuperclass().getSimpleName();
// 获取父类接口
Class<?>[] classInterfaces = aClass.getInterfaces();
// 获取所有属性
Field[] declaredFields = aClass.getDeclaredFields();
// 字符串拼接
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(classMod);
stringBuilder.append(" class ");
stringBuilder.append(className);
stringBuilder.append(" extends ");
stringBuilder.append(classSupName);
if (classInterfaces.length > 0) {
stringBuilder.append(" implements ");
for (int i = 0; i < classInterfaces.length; i++) {
stringBuilder.append(classInterfaces[i].getSimpleName());
if (i != classInterfaces.length - 1) {
stringBuilder.append(", ");
}
}
}
stringBuilder.append(" {\n");
for (Field declaredField : declaredFields) {
stringBuilder.append("\t");
// 获取属性修饰符
stringBuilder.append(Modifier.toString(declaredField.getModifiers()));
stringBuilder.append(" ");
// 获取属性类型
stringBuilder.append(declaredField.getType().getSimpleName());
stringBuilder.append(" ");
// 获取属性名
stringBuilder.append(declaredField.getName());
stringBuilder.append(";\n");
}
stringBuilder.append("}");
System.out.println(stringBuilder);
}
}
3.通过反射为对象属性赋值
- 三要素:对象、属性、值。缺一不可;
- 若属性不是 public 的,运行会报【java.lang.IllegalAccessException】异常,需要通过 setAccessible(true) 打破封装;
public class Person {
public String name;
private int age;
protected String sex;
public static String country;
public static final String job = "程序员";
}
public class FieldTest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person();
// 获取Person类
Class<? extends Person> aClass = person.getClass();
// 获取属性
Field name = aClass.getDeclaredField("name");
Field age = aClass.getDeclaredField("age");
Field sex = aClass.getDeclaredField("sex");
Field country = aClass.getDeclaredField("country");
Field job = aClass.getDeclaredField("job");
// 设置属性可访问
age.setAccessible(true);
sex.setAccessible(true);
// 设置属性值
name.set(person, "小明");
age.set(person, 23);
sex.set(person, "男");
country.set(person, "中国");
// 获取属性值
System.out.println("姓名:" + name.get(person));
System.out.println("年龄:" + age.get(person));
System.out.println("性别:" + sex.get(person));
System.out.println("国籍:" + country.get(person));
System.out.println("职业:" + job.get(person));
}
}