java反射详细讲解(2022版)

导读:本篇文章讲解 java反射详细讲解(2022版),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

什么是反射?

一、三种获取类信息的方式

二、获取类的相关信息

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

四、获取成员变量并调用

五: 获取成员方法并调用

六、 将map转成对象


什么是反射?

(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。

(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁  

        反射:能够分析类信息的能力叫做反射

类的生命周期

java反射详细讲解(2022版)

 Java代码在计算机中经历的三个阶段

java反射详细讲解(2022版)

一、三种获取类信息的方式

  •  类名.class
  •  对象.getClass();
  • Class.forName(“这里面是类的全限定名 包名+类名”)
public class TestClass {
//    private Map<String,String> map;

    public static void main(String[] args) {

    }
    public void test() throws ClassNotFoundException {
        //获取Cat对象
        Class<Cat> catClass = Cat.class;
        //通过对象方式获取
        Cat cat = new Cat();
        Class<? extends Cat> aClass = cat.getClass();
        //通过类名字获取类对象
        Class<? extends Object> aClass1 = Class.forName("com.fanshe.Cat");

        System.out.println(catClass == aClass);
    }
}

结论:

同一个类加载器加载的文件(*.class)在一次程序运行过程中,只会被加载一次,不论你通过那种方式获取的class对象都是同一个

二、获取类的相关信息

 @Test
    public void testClass() {
        //获取 猫类的类对象
        Class<Cat> catClass = Cat.class;

        //获取该类的加载器
        System.out.println("该类的加载器"+catClass.getClassLoader());

        //获取  类的 类名
        System.out.println(catClass.getName());
        System.out.println(catClass.getSimpleName());
        System.out.println(catClass.getTypeName());

        //获取该类的  父类   (继承是单继承)
        Class<? super Cat> superclass = catClass.getSuperclass();
        System.out.println(superclass.getName());

        //获取  该类  实现的所有接口(Java采用的是多实现)
        Class<?>[] interfaces = catClass.getInterfaces();

        System.out.println(Arrays.toString(interfaces));

        //获取类上的注解
        Annotation[] annotations = catClass.getAnnotations();
        System.out.println(Arrays.toString(annotations));
    }

 java反射详细讲解(2022版)

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

Student测试类

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);
    }

}

共有6个构造方法

测试类

public class StudentConstructors {

    /*
     * 通过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 static void main(String[] args) throws Exception {
            //1.加载Class对象
            Class clazz = Class.forName("com.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('男');
        }

    }

输出

**********************所有公有构造方法*********************************
public com.fanshe.Student(java.lang.String,int)
public com.fanshe.Student(char)
public com.fanshe.Student()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
private com.fanshe.Student(int)
protected com.fanshe.Student(boolean)
public com.fanshe.Student(java.lang.String,int)
public com.fanshe.Student(char)
public com.fanshe.Student()
com.fanshe.Student(java.lang.String)
*****************获取公有、无参的构造方法*******************************
con = public com.fanshe.Student()
调用了公有、无参构造方法执行了。。。
******************获取私有构造方法,并调用*******************************
public com.fanshe.Student(char)
姓名:男

调用方法:
1.获取构造方法:

  •  批量的方法:

            public Constructor[] getConstructors():所有”公有的”构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保 护、默认、公有)
     

  • 获取单个的方法,并调用:

public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法:

public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;

  调用构造方法:
Constructor–>newInstance(Object… initargs)

2、 newInstance是 Constructor类的方法(管理构造函数的类)
newInstance(Object… initargs)
           使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

四、获取成员变量并调用

Student类:

public class Student {

    public Student(){

    }
    //**********字段*************//
    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex
                + ", phoneNum=" + phoneNum + "]";
    }
}

测试类:

public class Fields {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.fanshe.student.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);

    }
}

结果:

************获取所有公有的字段********************
public java.lang.String com.fanshe.student.Student.name
************获取所有的字段(包括私有、受保护、默认的)********************
public java.lang.String com.fanshe.student.Student.name
protected int com.fanshe.student.Student.age
char com.fanshe.student.Student.sex
private java.lang.String com.fanshe.student.Student.phoneNum
*************获取公有字段**并调用***********************************
public java.lang.String com.fanshe.student.Student.name
验证姓名:刘德华
**************获取私有字段****并调用********************************
private java.lang.String com.fanshe.student.Student.phoneNum
验证电话:Student [name=刘德华, age=0, sex= , phoneNum=18888889999]

由此可见:

调用字段时:需要传递两个参数:
Object obj = stuClass.getConstructor().newInstance();//产生Student对象–》Student stu = new Student();
//为字段设置值f.set(obj, “刘德华”);

//为Student对象中的name属性赋值–》stu.name = “刘德华”
第一个参数:要传入设置的对象,第二个参数:要传入实参

五: 获取成员方法并调用

Student

  public void show1(String s){
        System.out.println("调用了:公有的,String参数的show1(): s = " + s);
    }
    protected void show2(){
        System.out.println("调用了:受保护的,无参的show2()");
    }
    void show3(){
        System.out.println("调用了:默认的,无参的show3()");
    }
    private String show4(int age){
        System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
        return "abcd";
    }
    

测试类:

public class MethodClass {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.fanshe.student.Student");
        //2.获取所有公有方法
        System.out.println("***************获取所有的”公有“方法*******************");
        stuClass.getMethods();
        Method[] methodArray = stuClass.getMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("***************获取所有的方法,包括私有的*******************");
        methodArray = stuClass.getDeclaredMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("***************获取公有的show1()方法*******************");
        Method m = stuClass.getMethod("show1", String.class);
        System.out.println(m);
        //实例化一个Student对象
        Object obj = stuClass.getConstructor().newInstance();
        m.invoke(obj, "刘德华");

        System.out.println("***************获取私有的show4()方法******************");
        m = stuClass.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
        System.out.println("返回值:" + result);


    }
}

m = stuClass.getDeclaredMethod(“show4”, int.class);//调用制定方法(所有包括私有的),需要传入两个参数,第一个是调用的方法名称,第二个是方法的形参类型,切记是类型。
 System.out.println(m);
 m.setAccessible(true);//解除私有限定
 Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
 System.out.println(“返回值:” + result);

六、 将map转成对象

Cat

public class Cat extends Animal {

    public String name;

    private int age;



    @Override
    public void call() {
        System.out.println("猫在叫~~~~");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", type='" + type + '\'' +
                '}';
    }
}

测试

 @Test
    public void testMapToCat() throws Exception{
        Map<String, Object> map = new HashMap<>();
        map.put("name", "小白胖");
        map.put("age", 2);
        map.put("type","加菲猫");
        //将上述的Map  通过  反射转换成一个  猫对象

        //Class<Cat> clz = Cat.class;
        Class<?> clz = Class.forName("com.fanshe.Cat");
        //获取猫类的所有属性
        Field[] fields = clz.getDeclaredFields();
        //获取父类定义的所有属性
        Field[] parents = clz.getSuperclass().getDeclaredFields();
        //合并2个类的所有属性
        List<Field> collect = Arrays.stream(fields).collect(Collectors.toList());
        List<Field> collect2 = Arrays.stream(parents).collect(Collectors.toList());
        collect.addAll(collect2);

//        Cat cat = new Cat();
        //反射去new Cat 调用他的无参构造
        Object obj = clz.getDeclaredConstructor().newInstance();

        //遍历所有的Field
        for(Field f : collect){
            //破坏封装
            f.setAccessible(true);

            //属性名,是否在Map中
            if(map.containsKey(f.getName())){
                //将map  中对应的key值,写入到f中
                f.set(obj, map.get(f.getName()));
            }
        }
        System.out.println(obj);
    }

java反射详细讲解(2022版)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80104.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!