> 文档中心 > 猿创征文 | 反射机制(反射Method、Constructor、Field)

猿创征文 | 反射机制(反射Method、Constructor、Field)


✅作者简介:一位材料转码农的选手,希望一起努力,一起进步!
📃个人主页:@每天都要敲代码的个人主页

🔥系列专栏:JavaSE从入门到精通
💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习

目录

一:反射Field

1. 获取Field(属性

2. 反编译Field(了解)

3. 通过反射机制访问对象的属性(重点)

二:反射Method

1. 可变长度参数

2. 反射Method(了解)

3. 反编译Method(了解)

4. 通过反射机制调用方法(重点)

三:反射Constructor

1. 反射Constructor

2. 反射机制调用构造方法

3. 补充:获取父类和父类的接口(重点)

结束语


一:反射Field

1. 获取Field(属性)

首先调用Class.forName("完整类名"),获取整个类;对于类也可以调用getName()方法获取完整类名,或者调用getSimpleName()方法获取简单类名

(1)调用getFields()方法,获取类中所有的public(公开的)修饰的Field(属性),返回的是一个Field数组;在调用getName()方法,得到属性的名字!

(2)调用getDeclaredFields()方法,获取所有的Field(属性),得到这个属性以后,就可以得到:属性的修饰符列表、属性的类型、属性的名字

(3)调用getModifiers()方法,返回的是一个代号是int类型;然后在调用Modifier.toString()静态方法,把int传进去,就可以转换成字符串;得到属性的修饰符列表

(4)调用getType()方法返回的是一个Class类型,然后在调用getSimpleName()方法得到String类型,得到属性的类型

(5)直接调用getName()方法,返回一个String类型,就能得到属性的名字  

package com.bjpowernode.java.reflect;import java.lang.reflect.Field;import java.lang.reflect.Modifier;// 反射Student类中的所有Fieldpublic class ReflectTest06 {    public static void main(String[] args) throws Exception{ // 获取整个类 Class studentClass = Class.forName("com.bjpowernode.java.reflect.Student"); // 补充:studentClass也有getName()方法 String studentName = studentClass.getName(); System.out.println("完整类名:"+studentName); // com.bjpowernode.java.reflect.Student String simpleName = studentClass.getSimpleName(); System.out.println("简单类名"+simpleName); // Student // 1、 获取类中所有的public(公开的)修饰的Field(属性) Field[] fields = studentClass.getFields(); System.out.println(fields.length); //1 测试数组中只有1个元素 // 取出这个Field Field field = fields[0]; // 取出这个Field的名字 String fieldName = field.getName(); System.out.println(fieldName); // no(只有这个是public修饰的) // 2、获取所有的Field Field[] fields1 = studentClass.getDeclaredFields(); System.out.println(fields1.length); // 4 // 遍历 for(Field field1 :fields1){     // 2.1 获取属性的修饰符列表     // 用Modifiers()而不是Modifier,因为修饰符可能有多个     // 返回的是一个整型数字,每个数字是修饰符的代号     // 然后调用静态方法Modifier.toString(int) 把数字准换成对应的修饰符字符串     int i = field1.getModifiers();     String modifier = Modifier.toString(i);     System.out.println(modifier);     //2.2 获取属性的类型,field1.getType()返回的是一个Class     Class fieldType = field1.getType();     String fName = fieldType.getSimpleName();     System.out.println(fName); // int  String int boolean     //2.3 获取属性的名字, field1.getName()返回的是一个String     System.out.println(field1.getName()); //no name  age  sex }    }}// 反射属性class Student{    // 4个Field,分别采用了不同的访问控制权限修饰符    public int no; // Field对象    private String name; // Field对象    protected int age;    boolean sex;    public static final double MATH_PI = 3.1415926; // 修饰符有多个}

 

2. 反编译Field(了解)

通过反射机制,反编译一个类的属性Field;知道类的完整类名,就可以反编译该类的信息

package com.bjpowernode.java.reflect;import java.lang.reflect.Field;import java.lang.reflect.Modifier;// 反编译Fieldpublic class ReflectTest07 {    public static void main(String[] args) throws Exception {// 创建字符串拼接StringBuilder s = new StringBuilder();// 获取整个类 Class studentClass = Class.forName("com.bjpowernode.java.reflect.Student"); // 字符串拼接 //s.append("public class Student{"); // 采用动态获取的方式 s.append(Modifier.toString(studentClass.getModifiers()) +  " class " + studentClass.getSimpleName() + "{\n"); // 获取所有的属性 Field[] fields = studentClass.getDeclaredFields(); for (Field field :fields){     // 追加修饰符     s.append("\t");     s.append(Modifier.toString(field.getModifiers()));     s.append(" ");     // 追加类型     s.append(field.getType().getSimpleName());     s.append(" ");     // 追加名字     s.append(field.getName());     s.append(";\n"); } s.append("}"); System.out.println(s);    }}

3. 通过反射机制访问对象的属性(重点)

(1)怎么通过反射机制访问一个java对象的属性?
         给属性赋值使用set,获取属性的值使用get

(2)调用c.getDeclaredFields()方法,返回的是一个Field[] 数组

          调用c.getDeclaredField(String name)方法,根据属性的名称拿到Field,返回的是一个指定字符串的Field属性;有了指定的属性,就可以调用get和set方法进行修改和取出值了

(3)对于private私有的属性也是可以取到并修改的,调用nameField.setAccessible(true);就可以打破封装

(4)反射机制的缺点:打破封装,在外部也是可以访问私有private修饰的变量;造成数据不安全

package com.bjpowernode.java.reflect;import java.lang.reflect.Field;public class ReflectTest08 {    public static void main(String[] args) throws Exception { // 1. 不使用反射机制,怎么去访问一个对象的属性呢? Student s = new Student(); // 2. 给属性赋值 s.no = 1111; //三要素:给s对象的no属性赋值1111 // 要素1:对象s    要素2:no属性    要素3:值1111 // 3.  读属性值 // 两个要素:获取s对象的no属性的值。 System.out.println(s.no); // 对象.属性 // 1.使用反射机制(set get)     // 获取类 Class studentClass = Class.forName("com.bjpowernode.java.reflect.Student");     // 创建对象 Object obj = studentClass.newInstance(); // Student对象 // 2.获取no属性(根据属性的名称来获取Field) Field noField = studentClass.getDeclaredField("no"); // 3.给obj对象(Student对象)的no属性赋值  /* 虽然使用了反射机制,但是三要素还是缺一不可:     要素1:obj对象     要素2:no属性     要素3:2222值 注意:反射机制让代码复杂了,但是为了一个“灵活”,这也是值得的。  */ noField.set(obj,222);// 给obj对象的no属性赋值2222 // 4. 读取属性的值 // 两个要素:获取obj对象的no属性的值。 System.out.println(noField.get(obj)); // 属性.get(对象) // 2.可以反问私有的属性name吗?(需要打破封装才可以访问) Field nameField = studentClass.getDeclaredField("name"); // 打破封装(反射机制的缺点:打破封装,造成数据不安全) // 这样设置完之后,在外部也是可以访问私有private的。 nameField.setAccessible(true); // 给name属性赋值 nameField.set(obj,"zhangsan"); // 获取name属性的值 System.out.println(nameField.get(obj)); // zhangsan    }}

二:反射Method

1. 可变长度参数

可变长度参数
    int... args 这就是可变长度参数
    语法是:类型...  (注意:一定是3个点。)

    1、可变长度参数要求的参数个数是:0~N个。
    2、可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个
    3、可变长度参数可以当做一个数组来看待

package com.bjpowernode.java.reflect;public class ArgsTest {    public static void main(String[] args) {// 1.不带参数 一个参数 两个参数...都可以正常执行(参数可变)m();m(100);m(10,20);m2(100);m2(10,"abc");m3("abc","def","dd");// 里面也可以传一个数组进去String[] str = {"aaa","bb","c"};m3(str);    }    // 带有可变长度的方法    public static void m(int... args){ System.out.println("m方法执行了");    }    // 2.可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个    //public static void m2(String... args1,int... args2){}    public static void m2(int a,String... args){ System.out.println("m2方法执行");    }    // 3.可变长度参数可以当做一个数组来看待    public static void m3(String... args){ // args有length属性,说明args是一个数组 for (int i = 0; i < args.length; i++) {     System.out.println(args[i]); }    }}

2. 反射Method(了解)

UserServic类

package com.bjpowernode.java.reflect;// 用户登录类public class UserService {    /**     * 登录方法     * @param name 用户名     * @param password  用户密码     * @return 表示登录成功,false表示登录失败     */    public boolean login(String name,String password){ if("admin".equals(name) && "123".equals(password)){     return true; } return false;    }    /**     *  退出系统的方法     */    public void logout(){ System.out.println("退出系统");    }}

反射Method代码 

和反射Field的方式很相似,有个别的区别:

(1)调用的是getDeclaredMethods()方法,而不是getDeclaredFields()

(2)返回的是一个Method数组,而不是Field数组

(3)获取类型,这里是返回值类型,调用的是getReturnType方法,而不是getType方法

(4)最终多了一项参数类型,调用的是getParameterTypes(),返回的是一个Class数组,然后在调用getSimpleName()方法,就可以拿到对应的参数类型

package com.bjpowernode.java.reflect;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class ReflectMethod {    public static void main(String[] args) throws Exception{ // 获取类 Class userServiceClass = Class.forName("com.bjpowernode.java.reflect.UserService"); // 获取所有的Method Method[] methods =  userServiceClass.getDeclaredMethods(); for(Method method :methods){     // 1.获取修饰符列表     int i = method.getModifiers();     System.out.println(Modifier.toString(i));     // 2.获取方法的返回值类型     Class classMethod = method.getReturnType();     System.out.println(classMethod.getSimpleName());     // 3.获取方法名     System.out.println(method.getName()); //获取方法名:login logout     // 4.获取方法的参数类型(方法的参数可能有多个)     Class[] parameterTypes = method.getParameterTypes();     for(Class parameterType : parameterTypes){  System.out.println(parameterType.getSimpleName());     } }    }}

3. 反编译Method(了解)

通过这种方式,可以反编译一个类的方法

package com.bjpowernode.java.reflect;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class ReflectMethodTest02 {    public static void main(String[] args) throws Exception { StringBuilder s = new StringBuilder(); // 获取类 Class userServiceClass = Class.forName("java.lang.String"); // 追加 //s.append("public class UserService{"); // 采用动态获取的方式 s.append(Modifier.toString(userServiceClass.getModifiers())+" class "+userServiceClass.getSimpleName()+ "{\n"); // 获取方法 Method[] methods = userServiceClass.getDeclaredMethods(); for(Method method : methods){     s.append("\t");     // 追加修饰符     s.append(Modifier.toString(method.getModifiers()));     s.append(" ");     // 追加类型     s.append(method.getReturnType().getSimpleName());     s.append(" ");     // 追加方法名     s.append(method.getName());     // 追加参数类型     s.append("(");     Class[] parameterTypes = method.getParameterTypes();     for (Class parameterType :parameterTypes){  s.append(parameterType.getSimpleName());  s.append(",");     }     // 最后会多一个 , 怎么删除?     // 方法1:删除指定下标位置上的字符     s.deleteCharAt(s.length()-1);     s.append("){}");     s.append("\n"); } s.append("}"); System.out.println(s);    }}

4. 通过反射机制调用方法(重点)

重点:必须掌握,通过反射机制怎么调用一个对象的方法?

(1)和通过反射机制访问对象的属性很相似,那是通过set和get方法进行修改和读取数据的;而通过反射机制调用方法,是通过invoke方法进行数据填入,用返回值作为数据的读出

(2)反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,但是java代码不需要做任何改动。这就是反射机制的魅力!

package com.bjpowernode.java.reflect;import java.lang.reflect.Method;public class ReflectMethodTest03 {    public static void main(String[] args) throws Exception { // 1.不使用反射机制调用方法 UserService userService = new UserService(); boolean login = userService.login("admin","123"); System.out.println(login?"登录成功":"登录失败"); // 2.使用反射机制来调用一个对象的方法 // 获取Class Class userServiceClass = Class.forName("com.bjpowernode.java.reflect.UserService"); // 创建对象 Object obj = userServiceClass.newInstance(); // 获取方法(通过方法名和参数区分方法) Method loginMethod = userServiceClass. getDeclaredMethod("login",String.class,String.class); // 调用方法  /* 四要素: loginMethod方法 obj对象 "admin","123" 实参 retValue 返回值  */ // invoke调用的意思  Object retValue = loginMethod.invoke(obj,"admin","123");  // obj这个对象invoke调用loginMethod方法,传参数 System.out.println(retValue);     }}

三:反射Constructor

1. 反射Constructor

构造方法

package com.bjpowernode.java.reflect;public class Vip {    int no;    String name;    String birth;    boolean sex;    public Vip() {    }    public Vip(int no) { this.no = no;    }    public Vip(int no, String name) { this.no = no; this.name = name;    }    public Vip(int no, String name, String birth) { this.no = no; this.name = name; this.birth = birth;    }    public Vip(int no, String name, String birth, boolean sex) { this.no = no; this.name = name; this.birth = birth; this.sex = sex;    }    // 重写一下toString    @Override    public String toString() { return "Vip{" +  "no=" + no +  ", name='" + name + '\'' +  ", birth='" + birth + '\'' +  ", sex=" + sex +  '}';    }}

反编译一个类的Constructor构造方法

package com.bjpowernode.java.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Modifier;public class ReflectConstructorTest01 {    public static void main(String[] args) throws Exception{ StringBuilder s = new StringBuilder(); Class vipClass = Class.forName("com.bjpowernode.java.reflect.Vip"); //s.append("public class Vip {"); // 采用动态方式获取 s.append(Modifier.toString(vipClass.getModifiers())+" class "+vipClass.getSimpleName()+" {\n"); // 拼接构造方法 Constructor[] constructors = vipClass.getConstructors(); for (Constructor constructor :constructors){     s.append("\t");     // 追加修饰符     s.append(Modifier.toString(constructor.getModifiers()));     s.append(" ");     // 追加类名     s.append(vipClass.getSimpleName());     // 追加参数     s.append("(");     Class[] parameterTypes = constructor.getParameterTypes();     for (Class paramaterType: parameterTypes){  s.append(paramaterType.getSimpleName());  s.append(",");     }     // 删除最后元素下标位置上的字符     if(parameterTypes.length>0){  s.deleteCharAt(s.length()-1);     }     s.append("){}\n"); } s.append("}"); System.out.println(s);    }}/*public class Vip {    public Vip(int,String,String,boolean){}    public Vip(int,String,String){}    public Vip(int,String){}    public Vip(int){}    public Vip(){}}*/

2. 反射机制调用构造方法

通过反射机制调用构造方法实例化java对象。(这个不是重点)

package com.bjpowernode.java.reflect;import java.lang.reflect.Constructor;// 比上一个例子重要public class ReflectConstructorTest02 {    public static void main(String[] args) throws Exception { //1. 不使用反射机制怎么创建对象 Vip v1 = new Vip(); Vip v2 = new Vip(110,"zhangsan","2022-10-11",true); //2. 使用法反射机制 Class c = Class.forName("com.bjpowernode.java.reflect.Vip"); // 调用无参构造方法 Object obj = c.newInstance(); System.out.println(obj); // 调用有参构造方法( 区分构造方法只需要形参) // 第一步:先获取到这个有参数的构造方法 Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class); // 第二步:调用构造方法new对象、 Object newobj = con.newInstance(220,"lisi","2022-10-10",true); System.out.println(newobj); // 调用构造方法,也可以先拿到构造方法 Constructor con1 = c.getDeclaredConstructor(); // 什么都不传 System.out.println(con1.newInstance());    }}

3. 补充:获取父类和父类的接口(重点)

一个类,怎么获取这个类的父类,已经实现了哪些接口?

package com.bjpowernode.java.reflect;/*重点:给你一个类,怎么获取这个类的父类,已经实现了哪些接口? */public class ReflectTest09 {    public static void main(String[] args) throws Exception{ // String类举例 Class stringClass = Class.forName("java.lang.String"); // 获取String的父类 Class superClass = stringClass.getSuperclass(); System.out.println(superClass.getName()); // java.lang.Object // 获取String类实现的所有接口(一个类可以实现多个接口) Class[] interfaces = stringClass.getInterfaces(); for (Class inter : interfaces){     System.out.println(inter.getName()); }    }}

结束语

今天的分享就到这里啦!快快通过下方链接注册加入刷题大军吧!各种大厂面试真题在等你哦!
💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习

多事通报价网