反射的使用

一. 反射概述

Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展

反射

二. 获取Class类的对象

我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象
这里我们提供三种方式获取Class类型的对象

  • 使用类的class属性来获取该类对应的Class对象
    举例:Student.class将会返回Student类对应的Class对象

  • 调用对象的getClass()方法,返回该对象所属类对应的Class对象
    该方法是Object类中的方法,所有的Java对象都可以调用该方法

  • 使用Class类中静态方法forName(String className)
    该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径

代码如下:

package Demo.ReflectDemo;
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        //如果简单测试,就用1和2

//        使用类的class属性来获取该类对应的Class对象
        Class<Student> c1 = Student.class;
        System.out.println(c1);//class Demo.ReflectDemo.Student

        Class<Student> c2 = Student.class;
        System.out.println(c1==c2);//true


        System.out.println("------");
//        调用对象的getClass()方法,返回该对象所属类对应的Class对象
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c1==c3);//true


        //以下方式灵活性更高

//        使用Class类中静态方法forName(String className)
        Class<?> c4 = Class.forName("Demo.ReflectDemo.Student");//?代表的是泛型通配符
        System.out.println(c1==c4);//true
    }
}

在这里插入图片描述

三. 反射获取构造方法并使用

在这里插入图片描述

常用四种:Class类中用于获取构造方法的方法

方法名方法说明
Constructor< T > getConstructor​(Class< ? >… parameterTypes);返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数
Constructor< ? >[ ] getConstructors​();返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数
Constructor< T > getDeclaredConstructor​(Class< ? >… parameterTypes);返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数
Constructor< ? >[ ] getDeclaredConstructors​();返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组
  • Class类中用于创建对象的方法

    方法名方法说明
    T newInstance​(Object… initargs);根据指定的构造方法创建对象

    代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
   反射获取构造方法并使用
   Constructor<T> getConstructor​(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。
   Constructor<?>[] getConstructors​() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。

   Constructor<T> getDeclaredConstructor​(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。
   Constructor<?>[] getDeclaredConstructors​() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组



   T newInstance​(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
   void setAccessible​(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。



*/
public class ReflectDemo {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //获取Class对象
       Class<?> c=Class.forName("Demo.ReflectDemo.Student");

       //反射获取构造方法并使用

/*
       System.out.println("返回Class表示类指定所有公共的构造器");
       Constructor<?>[] cp = c.getConstructors();//返回Class表示类指定所有公共的构造器
       for (Constructor<?> cc : cp) {
           System.out.println(cc);
       }

       System.out.println("------------------------------------------");

       System.out.println("返回Class表示类指定公有的构造器");
       Constructor<?> cp1 = c.getConstructor(String.class,int.class,String.class);//返回Class表示类指定公有的构造器
       System.out.println(cp1);

       System.out.println("------------------------------------------");

       System.out.println("返回Class表示类指定所有的构造器");
       Constructor<?>[] cp2 = c.getDeclaredConstructors();//返回Class表示类指定所有的构造器
       for (Constructor<?> cc : cp2) {
           System.out.println(cc);
       }

       System.out.println("------------------------------------------");

*/

       System.out.println("返回Class表示类指定的构造器");
       Constructor<?> cp3 = c.getDeclaredConstructor(String.class,int.class);//返回Class表示类指定的构造器
       System.out.println(cp3);

       System.out.println("**************************************");

       //Constructor提供了一个类的单个构造函数的信息和访问权限
       Object o = cp3.newInstance("坤坤",25);
       System.out.println(o);

   }
}
   

在这里插入图片描述

(一) 练习

  1. 例题:
    通过反射实现如下操作
    • Student s=new Student(“坤坤”,25,“鸡你太美村”);
    • System.out.println(s);

代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
    反射获取构造方法并使用
    Constructor<T> getConstructor​(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。
    Constructor<?>[] getConstructors​() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。

    Constructor<T> getDeclaredConstructor​(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。
    Constructor<?>[] getDeclaredConstructors​() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组



    T newInstance​(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
    void setAccessible​(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。

通过反射实现如下操作

Student s=new Student("坤坤",25,"鸡你太美村");
System.out.println(s);


 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        //"林青霞",30,"西安" 并且构造函数为public Student(String name, int age, String address)
        //所以:Constructor<T> getConstructor​(Class<?>... parameterTypes);返回指定的公有的构造函数

        Constructor<?> constructor = c.getConstructor(String.class, int.class, String.class);

        //T newInstance​(Object… initargs);	根据指定的构造方法创建对象。
        Object o = constructor.newInstance("坤坤", 25, "鸡你太美村");
        System.out.println(o);


    }
}

在这里插入图片描述

  1. 例题:
    通过反射实现如下操作
    • Student s=new Student(“坤坤”);
    • System.out.println(s);//

代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        //反射获取构造方法并使用                ->("iKun")
        Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class);

        //T newInstance​(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。

        Object iKun = declaredConstructor.newInstance("iKun");
        System.out.println(iKun);

    }
}

在这里插入图片描述

修改后的代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        //反射获取构造方法并使用                ->("iKun")
        Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class);

        //T newInstance​(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
        declaredConstructor.setAccessible(true);
        Object iKun = declaredConstructor.newInstance("iKun");
        System.out.println(iKun);

    }
}

在这里插入图片描述

总结:

  1. 基本数据类型也可以通过.class得到对应的Class类型
  2. void setAccessible​(boolean flag);值为true,取消访问检查(!!暴力反射很直接)

四. 反射获取成员变量并使用

在这里插入图片描述

常用四种:Class类中用于反射获取成员变量的方法

获取成员变量的方法名获取成员变量的方法说明
Field getDeclaredField​(String name);返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段
Field[] getDeclaredFields​();返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段
Field getField​(String name);返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段
Field[] getFields​();返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段
  • File类中用于给成员变量赋值和获取赋值变量的方法
方法名方法说明
void set(Object obj,Object value);给obj对象的成员变量赋值为value
Object get​(Object obj);返回由该 Field表示的字段在指定对象上的值。

代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/*
public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件
        Student student = new Student();
        Class<? extends Student> c = student.getClass();

/*
        //反射获取成员变量并使用
//        Field[] fields = c.getFields();
        Field[] fields = c.getDeclaredFields();
        for(Field field : fields){
            System.out.println(field);
        }
*/
        //反射获取成员变量并使用(例如:获取指定的"address"变量)
        Field addressField = c.getDeclaredField("address");

        //获取无参构造方法创建对象
        Constructor<?> con = c.getConstructor();
        Object obj= con.newInstance();

        //Field提供有关类或接口的单个字段的信息和动态访问                  void set(Object obj,Object value);给obj对象的成员变量赋值为value
        addressField.set(obj,"鸡你太美村");
        System.out.println(obj);


    /*    Object o = addressField.get(obj);
        System.out.println(o);*/


//        obj.addressField="西安"; 不能这样写会出现错误

     /*
         通过反射↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
        Student s1 = new Student();
        s1.address="西安";
        System.out.println(s1.address);

        */


    }
}

在这里插入图片描述

  • 注意:

在这里插入图片描述

(一) 练习

  1. 例题:
    通过反射实现如下操作:
    • Student s=new Student(“坤坤”,25,“鸡你太美村”);
    • s.name=“iKun”;
    • s.age=30;
    • s.address=“西安”;
    • System.out.println(s);

代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;


public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件
        Class<Student> c = Student.class;

        //反射获取构造方法并使用
        Constructor<?> cs = c.getConstructor();
         Object o= cs.newInstance();

        //反射获取成员变量并使用
        Field de1 = c.getDeclaredField("name");
        de1.setAccessible(true);
        Field de2 = c.getDeclaredField("age");
        de1.setAccessible(true);
        Field de3 = c.getDeclaredField("address");
        de1.setAccessible(true);

        //File类中用于给成员变量赋值和获取赋值变量的方法
        de1.set(o,"坤坤");
        de2.set(o,25);
        de3.set(o,"鸡你太美村");


        System.out.println(de1);
        System.out.println(de2);
        System.out.println(de3);




    }
}

在这里插入图片描述

五. 反射获取成员方法并使用

方法名方法说明
Method getDeclaredMethod​(String name, Class<?>… parameterTypes);返回一个方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。
Method[] getDeclaredMethods​();返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法。
Method getMethod​(String name, Class<?>… parameterTypes);返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法。
Method[] getMethods​();返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。

常用四种:Class类中用于反射获取成员方法的方法(有区别)

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        System.out.println("---------1------------");

        //Method getDeclaredMethod​(String name, Class<?>... parameterTypes) 返回一个方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。
        Method dm = c.getDeclaredMethod("function");
        System.out.println(dm);

        System.out.println("---------2------------");

        //Method[] getDeclaredMethods​() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法。
        Method[] dms = c.getDeclaredMethods();
        for (Method m:dms){
            System.out.println(m);
        }//但不包括继承方法  本类所有

        System.out.println("---------3------------");

        //Method[] getMethods​() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。
        Method[] dms2 = c.getMethods();
        for (Method m:dms2){
            System.out.println(m);
        }//包括继承方法   所有公共的

        System.out.println("---------4------------");

        Method dm3 = c.getMethod("method1");
        System.out.println(dm3);

    }
}

在这里插入图片描述

在这里插入图片描述

  • 方法在类或接口上提供有关单一方法的信息和访问权限
方法名方法说明
Object invoke​(Object obj, Object… args);在具有指定参数的指定对象上调用此方法对象表示的基础方法

Method类中的Object invoke​(Object obj, Object… args);在具有指定参数的指定对象上调用此方法对象表示的基础方法
Object:返回值类型
obj:调用方法的对象
args:方法需要的参数

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        //获取反射指定方法method1
        Method dm1 = c.getMethod("method1");

        //获取无参构造方法获取对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //方法在类或接口上提供有关单一方法的信息和访问权限       Object invoke​(Object obj, Object… args);	在具有指定参数的指定对象上调用此方法对象表示的基础方法
        dm1.invoke(obj);


        //o.dm;错误的写法,不能这样!!

        /*
          通过实例化获取对象↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
          Student s=new Student();
          s.method();
         */

    }
}

在这里插入图片描述

(一) 练习

  1. 例题:
    通过反射实现如下操作:
    • Student s=new Student();
    • s.method1();
    • s.method2(“iKun”);
    • String ss=s.method3(“iKun”,30)
    • System.out.println(ss);
    • s.function();

代码如下:

package Demo.ReflectDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException {
        //获取字节码文件
        Class<?> c = Class.forName("Demo.ReflectDemo.Student");

        //通过反射获取构造器后得到对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //通过反射获取方法
        Method m1 = c.getMethod("method1");
        m1.invoke(obj);//method1

        System.out.println("------------------------------");

        Method m2 = c.getMethod("method2",String.class);
        m2.invoke(obj,"iKun");

        System.out.println("------------------------------");

        Method m3 = c.getMethod("method3", String.class, int.class);
        Object iKun = m3.invoke(obj, "iKun", 30);
        System.out.println(iKun);

        System.out.println("------------------------------");
        Method m4 = c.getDeclaredMethod("function");
        m4.setAccessible(true);
        m4.invoke(obj);
    }
}

注意:m4.setAccessible(true);是可以允许访问私有权限的

在这里插入图片描述

六. 反射练习之超过泛型检查(重点!!!!!!!!!!!)

  • 例如:我有ArrayList< Integer >集合,现在我想在这个集合中添加一个字符串数据,如何实现?

注意泛型为< Integer > (说白点就是卡bug)

package Demo.ReflectDemo1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class ReflectDemo {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //创建集合
        ArrayList<Integer> ai = new ArrayList<Integer>();
        ai.add(1);


        Class<? extends ArrayList> c = ai.getClass();//字节码文件

        //通过反射获取方法
        Method addMethod = c.getDeclaredMethod("add", Object.class);

        //加入字符串
        addMethod.invoke(ai, "鸡你太美村");

        System.out.println(ai);
    }
}

在这里插入图片描述

  • 原因
    在这里插入图片描述

七. 通过配置文件运行类中的方法(重点!!!!!!!!!!!)

在这里插入图片描述

例如:

  • 定义一个学生类,里面有一个study()方法
  • 定义一个老师类,里面有一个teach()方法
package Demo.ReflectDemo2;

public class ReflectDemo2 {
    public static void main(String[] args) {

        Student s = new Student();
        s.study();

        Teacher t = new Teacher();
        t.teach();


    }
}

分析:
在这里插入图片描述
1.我们不可能来回调用方法在类中使用,这样非常繁琐
2.我们可以考虑用反射制定一个模板,修改关键值

通过反射我们可以指定模板(此时会牵扯IO流中的)
详细博客地址:
https://blog.csdn.net/o676448/article/details/124194706

在这里插入图片描述

修改后的代码:

package Demo.ReflectDemo2;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectDemo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        /*
           class.txt
           className=xxx
           methodName=xxx
         */

        Properties pro = new Properties();
        FileReader fileReader = new FileReader("C:\\untitled\\src\\Demo\\ReflectDemo2");

        pro.load(fileReader);
        fileReader.close();

        String className = pro.getProperty("className");//Demo.ReflectDemo.Student
        String methodName = pro.getProperty("methodName");//Study

        //通过反射来使用
        Class<?> c = Class.forName(className);

        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        Method m = c.getMethod(methodName);

        m.invoke(obj);



    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发热的嘤嘤怪(2003计科胜胜同学)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值