Java反射基础

反射概述:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

如何获取一个字节码文件(编译后得到的.class后缀的文件)对应的Class对象?

有三种方式:

方式1:对象已经存在的情况下获取

方式2:直接通过类名的方式进行获取

方式3:调用Class类中的静态方法获取字节码文件的Class对象

参考代码如下:注意:一个字节码文件,在内存中只会存在一个对应的Class类对象

public class ClassDemo1 {
    public static void main(String[] args) throws Exception{
        //方式1:对象已经存在的情况下获取
        Student s1 = new Student();
        Class c12 = s1.getClass();
        Class c22 = s1.getClass();
       System.out.println(c12==c22);

        //方式2:直接通过类名的方式进行获取
       Class c1 = Student.class;
       Class c2 = Student.class;
       System.out.println(c1==c2);
       System.out.println(c12==c2);

        //方式3:调用Class类中的静态方法获取字节码文件的Class对象
        //TODO:其中com.day21是包名
        Class c1 = Class.forName("com.day21.Student");
        Class c2 = Class.forName("com.day21.Student");
        System.out.println(c1==c2);
    }
}

通过反射获取构造方法并使用:

获取构造方法         

getConstructors:获取所有的公共构造方法        

getDeclaredConstructors:获取所有构造方法(私有+公共)

创建对象       

 newInstance()       

 con.newInstance(“光头强",13);

通过反射获取成员变量并使用:

获取所有成员:

getFields:获取所有公共的成员变量

getDeclaredFields:

获取单个成员:

getField :获取公共的单个成员变量

getDeclaredField :获取私有的单个成员变量

修改成员的值:set(Object obj,Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

通过反射获取成员方法并使用:

获取所有方法:

getMethods :获取类的所有公共成员方法以及父类的公共成员方法       

 getDeclaredMethods:获取本类中所有的成员方法(公共+私有的成员方法)

获取单个方法         

getMethod:获取类中的某个公共成员方法         

getDeclaredMethod:获取类中私有成员方法

暴力访问         

method.setAccessible(true):获取私有成员变量或方法的时候,出现IllegalAccessException(拒绝访问的时候,抛出的异常),就可以在访问之前加上这段代码,就能正常访问并获取,如果加上这段代码后运行,还是报同样的IllegalAccessException错误,就去检查参数类型和传参问题
 

总结:

获取:

获取构造方法的时候,要传入定义的参数类型(如String.class),获取成员方法的时候,要传入    "成员方法名"(如果有参数,也加上定义参数的类型),获取成员变量的时候在括号要传入"变量名称"。所有获取的变量和方法都可以直接打印

使用:

1、使用构造方法的时候,可以用上面获取的构造方法所设的对象c1来new一个对象,如Object o = c1.newInstance();可以在这个括号里面传参数名称(如果有参数的话),就可以直接打印对象,得到想要的对象内容。

2、使用成员方法的时候,可以用获取的成员方法所设的对象名调用invke(o)方法使用,有参数要在括号写一个参数名称,o代表构造方法的对象

3.使用成员变量,也是用获取的成员变量所设的对象名,调用set()进行设值,如name.set(o,"新值")  ,o也是构造方法的对象名

(使用私有的变量方法可能会出现的问题):

使用私有的构造方法、成员方法、成员变量,出现IllegalAccessException拒绝访问报错,先设置访问权限 :E.setAccessible(true);我们知道要使用什么得先去获取才能使用,这个E代表获取的构造方法/成员方法/成员变量的对象名,然后如果设置后还是报错,就看使用的构造方法和成员方法里面是否传入了参数名称,还需注意特殊的:尤其是获取构造方法的时候参数类型是否完全一样,比如Integer.class和int.class是不同的类型。

详细代码见下:

//反射机制,获取和使用类的构造方法,成员变量和成员方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;



public class Reflection {
    public static void main(String[] args) throws Exception{
        Class  studentClass = Class.forName("day22_8_22.Student");
        //通过字节码对象获取类的无参公共构造方法
        Constructor c1 = studentClass.getConstructor();
//        System.out.println(c1);
        //获取有参的私有方法,要传参数类型
        Constructor d1 = studentClass.getDeclaredConstructor(String.class);
//        System.out.println(d1);
        //获取所有的构造方法(公共+私有)包括有参和无参
        Constructor[] ds = studentClass.getDeclaredConstructors();
        for (Constructor d : ds) {
            System.out.println(d);
        }
        //获取所有的成员变量
        Field[] df = studentClass.getDeclaredFields();
        for (Field field : df) {
            System.out.println(field.toString());
        }
        //接下来通过获取的构造方法,来创建对象并使用
        //通过构造方法来new Student对象
        Object o = c1.newInstance();
        System.out.println(o);
        //通过私有构造构造方法new对象的时候,有参数要传入参数名称,发现访问拒错误
        //所以我们要暴力执行
        d1.setAccessible(true);
        Object o1 = d1.newInstance("帅哥");
        System.out.println(o1);

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

        //获取单个公共成员变量,要给出变量名
        Field f1 = studentClass.getField("stuNumber");
        System.out.println("变量名为:"+f1.getName());
        //获取单个私有变量,也要给变量名
        Field name = studentClass.getDeclaredField("name");
        System.out.println("私有变量名:"+name.getName());
        //使用私有成员变量设值,出现IllegalAccessException,也要暴力执行或者检查参数类型
        name.setAccessible(true);
        name.set(o,"悟空");//在某个对象里面设值,下面就直接打印对象,就能看到设值
        System.out.println(o);
        //获取所有的成员变量,包括(公共+私有),直接用Arrays.toString转字符串不好看,遍历获取单个变量名称
        Field[] dfs = studentClass.getDeclaredFields();
        for (Field field : dfs) {
            System.out.println("所有变量名为:"+field.getName());
        }

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

        //先获取全部参数的私有构造方法,再使用单个成员变量,进行重新设值
        Constructor constructor = studentClass.getDeclaredConstructor(String.class,Double.class,String.class,int.class);
        //获取有参构造方法的时候,要传入参数类型,当创建对象,使用构造方法要传入参数名称
        //NoSuchMethodException报错,因为Integer.class和int.class不一样,所以参数类型要完全和类里面设定的一样
       constructor.setAccessible(true);
        Object o2 = constructor.newInstance("123456",177.7,"猪八戒",36);
        System.out.println(o2);
        //获取私有成员方法,先传方法名,有参数再传参数类型
        Method dm = studentClass.getDeclaredMethod("fun", String.class);
        //获取这个方法可以打印,但是使用的时候,因为方法里面包含了打印,就无需打印
        System.out.println(dm);
        //获取所有成员方法(注意:包括了父类的公共构造方法)
        Method[] ms = studentClass.getMethods();
        System.out.println(Arrays.asList(ms));
        //获取本类的所有成员方法,包括(公共+私有)
        Method[] declaredMethods = studentClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("所有的成员方法为:"+declaredMethod.getName());
        }
        //使用私有成员有参方法,获取后用invoke(),括号里面传入对象名
        Method dd = studentClass.getDeclaredMethod("fun", String.class);
       dd.setAccessible(true);
        dd.invoke(o,"你好");//该方法带参数,还需要传参
        //使用公共成员无参方法,获取后用invoke(),括号里面传入对象名
        Method method = studentClass.getMethod("fun1");
        method.invoke(o);


    }
}

你可能感兴趣的:(JAVA,java,反射)