当前位置: 首页 > news >正文

Java高级-03.反射-获取构造器对象并使用

 一.获取构造器对象

获取构造器对象我们有四种方法,其中带Constructor的获取单个构造器对象。而带Constructors的是获取构造器对象数组。带Declared的是无论构造器是否私有都能拿到该构造器对象,而不带Declared的方法无法获取到私有的构造器对象。

首先我们将要使用到的Cat对象定义出来:

package com.njau.d2_reflect;

import com.sun.xml.internal.ws.api.ha.StickyFeature;

public class Cat {
    
    private String name;
    private int age;

    private Cat(String name, int age) {
        System.out.println("有参构造器执行了!");
        this.name = name;
        this.age = age;
    }

    private Cat() {
        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 +
                '}';
    }
}

接着我们使用上述四种方法获取构造器对象,在获取构造器对象的第一步,就是首先获取该类对象,因为构造器是类的一部分,只有获取到了该类对象,才能进一步获取该类的构造器对象。

Constructor<?>[] getConstructors()   获取全部的构造器(不包括private修饰的,只包括public修饰的)
Constructor<?>[] getDeclaredConstructors()   获取全部的构造器(包括private,public修饰的)
Constructor<?>[] getConstructor(Class<?>...parameterTypes)   获取某个构造器(不包括private修饰的,只包括public修饰的)
Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes)   获取某个构造器(包括private,public修饰的)

在获取某个构造器时,使用getDeclaredConstructor方法,其中()内有参数的获取有参构造器,没有参数的获取无参构造器。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * 目标:获取类的构造器、并对其进行操作
 * Class提供了从类中获取构造器的方法
 * Constructor<?>[] getConstructors()   获取全部的构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructors()   获取全部的构造器(包括private,public修饰的)
 * Constructor<?>[] getConstructor(Class<?>...parameterTypes)   获取某个构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes)   获取某个构造器(包括private,public修饰的)
 * 获取类构造器的作用:依然是初始化对象返回
 * 获取类构造器的作用:依然是初始化对象返回
 * T newInstance(Object...initargs)  调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)
 */
public class Test2Constructor {
    @Test
    public void testGetConstructors() throws Exception {
        // 反射第一步:先得到类的Class对象
        Class c1 = Cat.class;
        System.out.println(c1.getName());   // com.njau.d2_reflect.Cat
//        Constructor[] constructors = c1.getConstructors();
        Constructor[] constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }
    }

    @Test
    public void testGetConstructor() throws Exception {
        Class c2 = Cat.class;
//        Constructor constructor = c2.getConstructor();
        Constructor constructor = c2.getDeclaredConstructor();
        System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());

//        Constructor constructor1 = c2.getConstructor(String.class,int.class);
        Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
        System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());
    }
}

.class用来拿到当前的类型。携带Declared方法功能较为强大,因此我们在使用时要使用带Declared的方法。getName()和getParameterCount()用来拿到构造器名字和构造器参数个数。

二.获取类构造器的作用

Cat.java

package com.njau.d2_reflect;

import com.sun.xml.internal.ws.api.ha.StickyFeature;

public class Cat {
    
    private String name;
    private int age;

    private Cat(String name, int age) {
        System.out.println("有参构造器执行了!");
        this.name = name;
        this.age = age;
    }

    private Cat() {
        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 +
                '}';
    }
}

作用:初始化一个对象返回

在使用反射初始化对象时,我们首先获得了类的构造器对象。该构造器对象可以调用newInstance方法创建出一个类的实例化对象并返回。在该方法中传入参数即调用有参构造器,无参数则调用无参构造器。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * 目标:获取类的构造器、并对其进行操作
 * Class提供了从类中获取构造器的方法
 * Constructor<?>[] getConstructors()   获取全部的构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructors()   获取全部的构造器(包括private,public修饰的)
 * Constructor<?>[] getConstructor(Class<?>...parameterTypes)   获取某个构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes)   获取某个构造器(包括private,public修饰的)
 * 获取类构造器的作用:依然是初始化对象返回
 * 获取类构造器的作用:依然是初始化对象返回
 * T newInstance(Object...initargs)  调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)
 */
public class Test2Constructor {
    @Test
    public void testGetConstructors() throws Exception {
        // 反射第一步:先得到类的Class对象
        Class c1 = Cat.class;
        System.out.println(c1.getName());   // com.njau.d2_reflect.Cat
//        Constructor[] constructors = cat.getConstructors();
        Constructor[] constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }

//        System.out.println(cat.getConstructor(String.class, int.class));
    }

    @Test
    public void testGetConstructor() throws Exception {
        Class c2 = Cat.class;
//        Constructor constructor = c2.getConstructor();
        Constructor constructor = c2.getDeclaredConstructor();
        System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());

//        Constructor constructor1 = c2.getConstructor(String.class,int.class);
        Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
        System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());

        Cat cat1 = (Cat) constructor.newInstance();  // private修饰的,无法直接使用无参构造器进行初始化(Object对象,要进行强转)
        System.out.println(cat1);    


    }
}

 我们在刚才的无参构造器constructor的基础上调用newInstance方法来实例化对象。因为无参构造器constructor自己本身不知道自己是什么类型的,因此他声明出来的类实例化对象是Object类型的,因此要强转成Cat类型才行。

但当我们执行该代码时,发现报错。报错类型为

可以看到因为该无参构造器是私有的private修饰,因此并没有成功创建该类的实现类对象。要想解决这个问题,除了将该无参构造器改为公共的以外,还可以使用setAccessible()方法。

我们可以调用setAccessible方法设置为true,表示禁止检查访问控制,即使用暴力反射。这样的话即使是私有的构造方法也可以进行对象的实例化。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * 目标:获取类的构造器、并对其进行操作
 * Class提供了从类中获取构造器的方法
 * Constructor<?>[] getConstructors()   获取全部的构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructors()   获取全部的构造器(包括private,public修饰的)
 * Constructor<?>[] getConstructor(Class<?>...parameterTypes)   获取某个构造器(不包括private修饰的,只包括public修饰的)
 * Constructor<?>[] getDeclaredConstructor(Class<?>...parameterTypes)   获取某个构造器(包括private,public修饰的)
 * 获取类构造器的作用:依然是初始化对象返回
 * 获取类构造器的作用:依然是初始化对象返回
 * T newInstance(Object...initargs)  调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)
 */
public class Test2Constructor {
    @Test
    public void testGetConstructors() throws Exception {
        // 反射第一步:先得到类的Class对象
        Class c1 = Cat.class;
        System.out.println(c1.getName());   // com.njau.d2_reflect.Cat
//        Constructor[] constructors = cat.getConstructors();
        Constructor[] constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }

//        System.out.println(cat.getConstructor(String.class, int.class));
    }

    @Test
    public void testGetConstructor() throws Exception {
        Class c2 = Cat.class;
//        Constructor constructor = c2.getConstructor();
        Constructor constructor = c2.getDeclaredConstructor();
        System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());

//        Constructor constructor1 = c2.getConstructor(String.class,int.class);
        Constructor constructor1 = c2.getDeclaredConstructor(String.class,int.class);
        System.out.println(constructor1.getName() + "--->" + constructor1.getParameterCount());

        constructor.setAccessible(true);  // 先设置为true,才能使用private修饰的无参构造器进行初始化对象
        Cat cat1 = (Cat) constructor.newInstance();  // private修饰的,无法直接使用无参构造器进行初始化(Object对象,要进行强转)
        System.out.println(cat1);    // Cat{name='null', age=0}

        constructor1.setAccessible(true);
        Cat cat2 = (Cat) constructor1.newInstance("招财猫", 3);
        System.out.println(cat2);
    }
}

 

从这里我们也可以看出来反射破坏封装性。

相关文章:

  • kali常用命令
  • Vue3使用ECharts入门示例
  • C++初阶——类和对象(一)
  • ArcGIS助力水文分析:数据处理、地图制作与流域特征提取
  • Linux--普通文件的管理
  • 如何让你的应用在市场中脱颖而出?
  • vscode远程连接服务器并运行项目里的.ipynb文件 如何在 Jupyter Notebook 中切换/使用 conda 虚拟环境?
  • 【计算机网络通信 MQTT和AMQP的原理及应用场景、优缺点】
  • Maven安装、idea集成Maven、Maven依赖管理、Maven生命周期
  • WEB-CTFyj解题视频笔记(持续更新)
  • 不与最大数相同的数字之和(信息学奥赛一本通-1113)
  • 图像分类数据集
  • 工程实践:如何使用SU17无人机来实现室内巡检任务
  • python3GUI--模仿安卓桌面 By:PyQt5(附下载地址)
  • Linux——管道通信
  • C++标准模板库学习--函数模板返回值参数类型
  • Linux驱动开发之中断处理
  • 网页转图片的方法(超出可视范围的也可以)dom-to-image
  • 网编高级 day03
  • dify-1.0.1 + deepseek调用本地知识库
  • 著名心血管病学专家李国庆教授逝世,享年63岁
  • 自然资源部:不动产登记累计化解遗留问题房屋2000多万套
  • 上海市税务局回应刘晓庆被举报涉嫌偷漏税:正依法依规办理
  • 上海率先推进生物制品分段生产试点,这款国产1类创新药获批上市
  • 商务部:中方将适时发布中美经贸磋商相关消息
  • 菲律宾中期选举初步结果出炉,杜特尔特家族多人赢得地方选举