你觉得反射好不好?好,有两个方向
第一个方向:无视修饰符访问类中的内容。但是这种操作在开发中一般不用,都是框架底层来用的。
第二个方向:反射可以跟配置文件结合起来使用,动态的创建对象,动态的调用方法。
理解:(掌握)
集合中的泛型只在java文件中存在,当编译成class文件之后,就没有泛型了。
代码示例:(了解)
- package com.itheima.reflectdemo;
-
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
-
- public class ReflectDemo8 {
- public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- //1.创建集合对象
- ArrayList
list = new ArrayList<>(); - list.add(123);
- // list.add("aaa");
-
- //2.利用反射运行add方法去添加字符串
- //因为反射使用的是class字节码文件
-
- //获取class对象
- Class clazz = list.getClass();
-
- //获取add方法对象
- Method method = clazz.getMethod("add", Object.class);
-
- //运行方法
- method.invoke(list,"aaa");
-
- //打印集合
- System.out.println(list);
- }
- }
-
在这个练习中,我需要你掌握的是字符串不能修改的真正原因。
字符串,在底层是一个byte类型的字节数组,名字叫做value
private final byte[] value;
真正不能被修改的原因:final和private
final修饰value表示value记录的地址值不能修改。
private修饰value而且没有对外提供getvalue和setvalue的方法。所以,在外界不能获取或修改value记录的地址值。
如果要强行修改可以用反射:
代码示例:(了解)
- String s = "abc";
- String ss = "abc";
- // private final byte[] value= {97,98,99};
- // 没有对外提供getvalue和setvalue的方法,不能修改value记录的地址值
- // 如果我们利用反射获取了value的地址值。
- // 也是可以修改的,final修饰的value
- // 真正不可变的value数组的地址值,里面的内容利用反射还是可以修改的,比较危险
-
- //1.获取class对象
- Class clazz = s.getClass();
-
- //2.获取value成员变量(private)
- Field field = clazz.getDeclaredField("value");
- //但是这种操作非常危险
- //JDK高版本已经屏蔽了这种操作,低版本还是可以的
- //临时修改权限
- field.setAccessible(true);
-
- //3.获取value记录的地址值
- byte[] bytes = (byte[]) field.get(s);
- bytes[0] = 100;
-
- System.out.println(s);//dbc
- System.out.println(ss);//dbc
需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。
分析:
①通过Properties加载配置文件
②得到类名和方法名
③通过类名反射得到Class对象
④通过Class对象创建一个对象
⑤通过Class对象得到方法
⑥调用方法
代码示例:
- public class ReflectDemo9 {
- public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
- //1.读取配置文件的信息
- Properties prop = new Properties();
- FileInputStream fis = new FileInputStream("day14-code\\prop.properties");
- prop.load(fis);
- fis.close();
- System.out.println(prop);
-
- String classname = prop.get("classname") + "";
- String methodname = prop.get("methodname") + "";
-
- //2.获取字节码文件对象
- Class clazz = Class.forName(classname);
-
- //3.要先创建这个类的对象
- Constructor con = clazz.getDeclaredConstructor();
- con.setAccessible(true);
- Object o = con.newInstance();
- System.out.println(o);
-
- //4.获取方法的对象
- Method method = clazz.getDeclaredMethod(methodname);
- method.setAccessible(true);
-
- //5.运行方法
- method.invoke(o);
-
-
- }
- }
-
- 配置文件中的信息:
- classname=com.itheima.a02reflectdemo1.Student
- methodname=sleep
- public class MyReflectDemo {
- public static void main(String[] args) throws IllegalAccessException, IOException {
- /*
- 对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
- */
- Student s = new Student("小A",23,'女',167.5,"睡觉");
- Teacher t = new Teacher("播妞",10000);
- saveObject(s);
- }
-
- //把对象里面所有的成员变量名和值保存到本地文件中
- public static void saveObject(Object obj) throws IllegalAccessException, IOException {
- //1.获取字节码文件的对象
- Class clazz = obj.getClass();
- //2. 创建IO流
- BufferedWriter bw = new BufferedWriter(new FileWriter("myreflect\\a.txt"));
- //3. 获取所有的成员变量
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- //获取成员变量的名字
- String name = field.getName();
- //获取成员变量的值
- Object value = field.get(obj);
- //写出数据
- bw.write(name + "=" + value);
- bw.newLine();
- }
-
- bw.close();
-
- }
- }
- public class Student {
- private String name;
- private int age;
- private char gender;
- private double height;
- private String hobby;
-
- public Student() {
- }
-
- public Student(String name, int age, char gender, double height, String hobby) {
- this.name = name;
- this.age = age;
- this.gender = gender;
- this.height = height;
- this.hobby = hobby;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return age
- */
- public int getAge() {
- return age;
- }
-
- /**
- * 设置
- * @param age
- */
- public void setAge(int age) {
- this.age = age;
- }
-
- /**
- * 获取
- * @return gender
- */
- public char getGender() {
- return gender;
- }
-
- /**
- * 设置
- * @param gender
- */
- public void setGender(char gender) {
- this.gender = gender;
- }
-
- /**
- * 获取
- * @return height
- */
- public double getHeight() {
- return height;
- }
-
- /**
- * 设置
- * @param height
- */
- public void setHeight(double height) {
- this.height = height;
- }
-
- /**
- * 获取
- * @return hobby
- */
- public String getHobby() {
- return hobby;
- }
-
- /**
- * 设置
- * @param hobby
- */
- public void setHobby(String hobby) {
- this.hobby = hobby;
- }
-
- public String toString() {
- return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}";
- }
- }
- public class Teacher {
- private String name;
- private double salary;
-
- public Teacher() {
- }
-
- public Teacher(String name, double salary) {
- this.name = name;
- this.salary = salary;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return salary
- */
- public double getSalary() {
- return salary;
- }
-
- /**
- * 设置
- * @param salary
- */
- public void setSalary(double salary) {
- this.salary = salary;
- }
-
- public String toString() {
- return "Teacher{name = " + name + ", salary = " + salary + "}";
- }
- }