Java基础——深入理解反射

反射

反射是框架的灵魂!但先要获取到每一个字节码文件对应的Class类型的对象.

1.概述

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.总结

  • 反射就是把Java类中的各种成分映射成一个个的Java对象,所以运用反射必须依赖于目标类是否被加载,即首先需要经行类加载,获取该类在Java内存(方法区)中这个唯一实例才可

  • Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)

  • Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

3.反射的使用

:boom:3.1 获取Class对象的三种方式

:one: Object->getClass();

public class Main {
    public static void main(String[] args){
       Parent parent = new Parent();
        Class pclass = parent.getClass(); 
        //是因为Object类中的getClass方法、因为所有类都继承Object类。从而调用Object类来获取
    }
}
class Parent{
}

:two: 任何数据类型都有静态class属性

public class Main {
    public static void main(String[] args){
        Class pclass = Parent.class; 
        // 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
    }
}
class Parent{
}

:three: Class.forName(String className)

public class Main {
    public static void main(String[] args){
        Class pclass = Class.forName("ddx.Main");
        //通过Class类的静态方法:forName(String  className)(常用)
    }
}
class Parent{
}

:boom: 三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。

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

package fanshe;

public class Student {

    //---------------构造方法-------------------
    //(默认的构造方法)
    Student(String str){
        System.out.println("(默认)的构造方法 s = " + str);
    }

    //无参构造方法
    public Student(){
        System.out.println("调用了公有、无参构造方法执行了。。。");
    }

    //有一个参数的构造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }

    //有多个参数的构造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
    }

    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }

    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法   年龄:"+ age);
    }

}

测试类:

package fanshe;

import java.lang.reflect.Constructor;


/*
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 * 
 * 1.获取构造方法:
 *         1).批量的方法:
 *             public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

 *         2).获取单个的方法,并调用:
 *             public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 *             public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 *         
 *             调用构造方法:
 *             Constructor-->newInstance(Object... initargs)
 */
public class Constructors {

    public static void main(String[] args) throws Exception {
        //1.加载Class对象
        Class clazz = Class.forName("fanshe.Student");


        //2.获取所有公有构造方法
        System.out.println("**********************所有公有构造方法*********************************");
        Constructor[] conArray = clazz.getConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }


        System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
        conArray = clazz.getDeclaredConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }

        System.out.println("*****************获取公有、无参的构造方法*******************************");
        Constructor con = clazz.getConstructor(null);
        //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
        //2>、返回的是描述这个无参构造函数的类对象。

        System.out.println("con = " + con);
        //调用构造方法
        Object obj = con.newInstance();
    //    System.out.println("obj = " + obj);
    //    Student stu = (Student)obj;

        System.out.println("******************获取私有构造方法,并调用*******************************");
        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);
        //调用构造方法
        con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
        obj = con.newInstance('男');
    }

}

4.获取成员变量并调用


package fanshe.field;
import java.lang.reflect.Field;
/*
 * 获取成员变量并调用:
 * 
 * 1.批量的
 *         1).Field[] getFields():获取所有的"公有字段"
 *         2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 * 2.获取单个的:
 *         1).public Field getField(String fieldName):获取某个"公有的"字段;
 *         2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
 * 
 *      设置字段的值:
 *         Field --> public void set(Object obj,Object value):
 *                     参数说明:
 *                     1.obj:要设置的字段所在的对象;
 *                     2.value:要为字段设置的值;
 * 
 */
public class Fields {

        public static void main(String[] args) throws Exception {
            //1.获取Class对象
            Class stuClass = Class.forName("fanshe.field.Student");
            //2.获取字段
            System.out.println("************获取所有公有的字段********************");
            Field[] fieldArray = stuClass.getFields();
            for(Field f : fieldArray){
                System.out.println(f);
            }
            System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
            fieldArray = stuClass.getDeclaredFields();
            for(Field f : fieldArray){
                System.out.println(f);
            }
            System.out.println("*************获取公有字段**并调用***********************************");
            Field f = stuClass.getField("name");
            System.out.println(f);
            //获取一个对象
            Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
            //为字段设置值
            f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
            //验证
            Student stu = (Student)obj;
            System.out.println("验证姓名:" + stu.name);


            System.out.println("**************获取私有字段****并调用********************************");
            f = stuClass.getDeclaredField("phoneNum");
            System.out.println(f);
            f.setAccessible(true);//暴力反射,解除私有限定
            f.set(obj, "18888889999");
            System.out.println("验证电话:" + stu);

        }
    }

4、获取成员方法并调用

5、反射main方法

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!