DAY11.2 Java核心基础
反射(第二弹)
第一弹请访问链接:
反射(第一篇)
- getMethod(String name, Class… parameterTypes)
- getMethods()
- getDeclaredMethod(String name,Class… parameterTypes)
- getDeclaredMethods()
getMethods() 获取类中所有方法,包括从父类继承过来的方法以及自定义的方法,这些方法都是 public 方法
public String getName() {return name;
}private void setName(String name) {this.name = name;
}protected int getAge() {return age;
}void setAge(int age) {this.age = age;
}@Override
public String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';
}
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");Method[] methods = class1.getMethods();for (Method method : methods) {System.out.println(method.getName());}
}
可以看见这个输出只有public访问符的方法
getMethod(String name,Class… parameterTypes) 根据方法名和参数列表获取具体的某个方法,只能是 public
方法,包括自定义的方法以及从父类继承过来的方法
private void setName(String name) {this.name = name;
}
Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");
Method setName = class1.getMethod("setName", String.class);
System.out.println(setName);
这样是获取不到的,抛出找不到方法的异常
因为这个只能获取到公有方法(public修饰的)
改为public就可以获取到了
同理
getDeclaredMethods() 获取类中所有的方法,包括 public、protected、private、默认,但是无法获取从父类继承过来的方法
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");Method[] declaredMethods = class1.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod.getName());}
}
public String getName() {return name;
}public void setName(String name) {this.name = name;
}protected int getAge() {return age;
}void setAge(int age) {this.age = age;
}@Override
public String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';
}
输出:
可以看见可以获取所有声明的方法,和这个方法的访问权限符无关
getDeclaredMethod(String name,Class… parameterTypes) 根据方法名和参数列表获取具体的某个方法,对于访问权限修饰符没有限制,但是只能获取自定义的方法
Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");
Method getAge = class1.getDeclaredMethod("getAge");
System.out.println(getAge);
获取到的是protected的方法,对于访问权限修饰符没有限制,但是只能获取自定义的方法
获取类中成员变量
Class 提供了 4 个方法获取类中的成员变量
- getFields():获取类中全部的 public 修饰的成员变量,包括继承自父类的成员变量以及自定义的成员变量
- getDeclaredFields():获取类中全部修饰符修饰的成员变量,但仅限于类自定义的,不包括从父类继承过来的
- getField(String name):根据成员变量名称获取类中的某个具体的 public 修饰的成员变量,包括继承自父类的成员变量以及自定义的成员变量
- getDeclaredField(String name):根据成员变量名称获取类中某个具体的成员变量,不受访问权限修饰符的限制,但是只能获取类自定义的成员变量,不包括从父类继承过来的成员变量
和上面的获取方法同理
类中的字段:
public String name;
public int age;
private String sex;
Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");
Field[] fields = class1.getFields();
for (Field field : fields) {System.out.println(field);
}
System.out.println(class1.getDeclaredField("name"));
可以看见getFields()获取到两个public的字段,getDeclaredField获取的是privare的sex
反射就是在程序运行的时候动态获取类的信息(比如构造器,成员方法,成员变量)
反射的应用
通过 Class 类提供的方法可以获取类中的成员变量、成员方法、构造函数
获取这些有什么用?实际开发中如何应用反射?
反射调用方法
常规创建并操作对象的方法
public User(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;
}
public String getInfo() {return this.name + " " + this.age + " " + this.sex;
}
User user = new User("deepseek", 18, "男");
user.getInfo();
User类的构造方法和测试方法
getMethod() 和 invoke()
public User(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;
}
public String getInfo() {return this.name + " " + this.age + " " + this.sex;
}
Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");
Constructor constructor = class1.getConstructor(String.class, int.class, String.class);
User user1 = (User) constructor.newInstance("deepSeek", 18, "男");
Method getInfoMethod = class1.getMethod("getInfo",null);
System.out.println(getInfoMethod.invoke(user1));
输出:
反射就是将常规方式进行反转
// 常规调用
user.getInfo();
// 反射创建
Method getInfoMethod = class1.getMethod("getInfo",null);
System.out.println(getInfoMethod.invoke(user1));
常规:
1、创建实例化对象
2、调用实例化对象的方法
反射:
1、获取反射源头 Class 对象
2、根据 Class 对象获取目标方法
3、通过反射机制调用目标方法
反射访问成员变量
getDeclaredFields() :获取类中所有成员变量
Class class1 = Class.forName("com.deepSeek.shuwu.Day11.User");
Field[] declaredFields = class1.getDeclaredFields();
for (Field declaredField : declaredFields) {// 获取字段名称、类型、修饰符、泛型类型System.out.println(declaredField.getName());System.out.println(declaredField.getType());System.out.println(declaredField.getModifiers());System.out.println(declaredField.getGenericType());System.out.println("-------------------------------");
}
获取字段,然后可以传入对象获取对象的id;
public static void main(String[] args) throws Exception {// 加载 User 类Class<?> class1 = Class.forName("com.deepSeek.shuwu.Day11.User");// 创建 User 对象User user1 = new User("user1", 18, "男");User user2 = new User("user2", 18, "男");User user3 = new User("user3", 18, "男");// 获取 name 字段(假设它是 public 的)Field name = class1.getField("name");System.out.println(name.get(user1)); System.out.println(name.get(user2)); System.out.println(name.get(user3)); // 获取 sex 字段(private 字段)Field sex = class1.getDeclaredField("sex");sex.setAccessible(true); System.out.println(sex.get(user1)); // 修改 user1 的 sex 字段值sex.set(user1, "女");System.out.println(sex.get(user1));
}
输出:
可以通过反射获取到对象的private值,以及对对象的值进行修改
如下图所示:
反射调用构造函数
反射机制下用 Constructor 类来描述构造函数,同时一个类可以拥有多个构造函数
一个User类中的三个构造函数:
public User(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;
}
public User() {}
public User(String name, int age) {this.name = name;this.age = age;
}
@Override
public String toString() {eturn "User{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';
}
测试类;
// 加载 User 类
Class<?> class1 = Class.forName("com.deepSeek.shuwu.Day11.User");Constructor<?> constructor1 = class1.getConstructor(String.class, int.class);
User user1 = (User) constructor1.newInstance("李四", 20);
System.out.println(user1);Constructor<?> constructor2 = class1.getConstructor(null);
User user2 = (User) constructor2.newInstance();
System.out.println(user2);Constructor<?> constructor3 = class1.getConstructor(String.class, int.class, String.class);
User user3 = (User) constructor3.newInstance("张三", 18, "男");
System.out.println(user3);
输出:
反射调用构造函数和反射调用普通方法的区别
1、构造函数使用 Constructor 来表示,普通方法使用 Method 来表示
2、Constructor 调用的是 newInstance 方法,Method 调用的是 invoke 方法
3、Constructor 不需要传入对象,只需传入参数,Method 需要同时传入对象和参数
直接访问成员变量进行赋值 or 通过调用成员方法对成员变量进行赋值
public static void main(String[] args) throws Exception {// 加载 User 类Class<?> class1 = Class.forName("com.deepSeek.shuwu.Day11.User");User user =new User();Field name = class1.getField("name");// 直接赋值name.set(user,"deepSeek");// 如果不是public字段,需要先设置可访问性Field age = class1.getDeclaredField("age");age.setAccessible(true);age.set(user,19);// 调用 setSex 方法赋值,前提是这个方法是publicMethod setSex = class1.getMethod("setSex", String.class);setSex.invoke(user,"女");// 输出System.out.println(user);
}