Java 反射方法的运用(通过反射创建对象)

Android 专栏收录该内容
27 篇文章 0 订阅

Java 的反射

涉及到的知识:1.通过反射创建对象;2.通过反射调用某个类的方法。

这篇主要是讲解 通过反射创建对象


一、反射的简单定义:java可以在运行时动态获取某个类的类信息,这就是java的反射。

1. 涉及Class(类)
Class 类的实例表示正在运行的 Java 应用程序中的类和接口
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

这个类指的是类对象,是具体某个类对象,描述类信息。不是我们平时说的对象,这样说有点抽象,举个例子:

比如:String a=new String ();这个a 是String 的对象,不是类对象;

Class c=String.class;这个c就是String的类对象,描述的是String这个class类的信息

那么怎么样才能得到某个类的类对象呢?

1.得到相应的 类对象

class 里面有个方法 Class c= Class.forName(className),通过这个方法可以得到相应的  类信息

Class.forName(className) 返回与带有给定字符串名的类或接口相关联的 Class 对象,其中className是字符串,----要求:所需类的完全限定名。比如String的className 为 java.lang.String   ,如果是自定义的对象,也需要传入完整的路径  例如:![这是一个类的包名](//img-blog.csdn.net/20180510102221797?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L0dSWV9ZSg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ,有个Student的类,则className 为 com.paynews.javalib.Student

调运改方法会抛出异常:
LinkageError - 如果链接失败
ExceptionInInitializerError - 如果此方法所激发的初始化失败
ClassNotFoundException - 如果无法定位该类

2.通过类对象得到 所表示的类的实例

2.1创建不带任何参数的对象(构造函数没有参数列表)

得到了类对象,创建它表示的类的一个新的实力,调用 public T newInstance();

public T newInstance();

    创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
    注意,此方法传播 null 构造方法所抛出的任何异常,包括已检查的异常。使用此方法可以有效地绕过编译时的异常检查,而在其他情况下编译器都会执行该检查。 Constructor.newInstance 方法将该构造方法所抛出的任何异常包装在一个(已检查的)InvocationTargetException 中,从而避免了这一问题。

返回:
   **此对象所表示的类的一个新分配的实例。**
抛出:
   IllegalAccessException - 如果该类或其 null 构造方法是不可访问的。
   InstantiationException - 如果此 Class 表示一个抽象类、接口、数组类、基本类型或 void; 或者该类没有 null 构造方法; 或者由于其他某种原因导致实例化失败。
   ExceptionInInitializerError - 如果该方法引发的初始化失败。
   SecurityException - 如果存在安全管理器 s,并满足下列任一条件:
   调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝创建该类的新实例
调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包

注:这个方法是 Class类中的方法,且只能创建不带任何参数的对象形式(构造函数没有参数列表)。直接返回T模版类型的对象,自己要把它转换为实际类型。

举例:
Class c=Class.forName("java.lang.String");
String s=(String)c.newInstance();

2.2创建带参数的对象

创建带参数的对象(构造函数中有参数)比较复杂,因为构造函数里面的参数可以是不同的,所以创建实例的时候,需要指明函数中的参数列表,传入相应的参数形式,否则会抛出异常。

调用的方法:
public Constructor<T> getConstructor(Class<?>... parameterTypes) 

返回一个 Constructor 对象,它反应此 Class类对象 所表示的 类 的公共构造方法,parameterTypes 参数是Class类对象的数组,对应构造函数中的参数,这个数组的顺序 与 构造函数中参数顺序一致。这样理解比较抽象,举个例子:
public Student getStudent(String name ,int age,String content){}parameterTypes对应的Class 类对象的数组
 Class name=Class.forName("java.lang.String");
 Class age=Interger.TYPE;
 Class content=Class.forName("java.lang.String"); 

 parameterTypes[0]=name
 parameterTypes[1]=age
 parameterTypes[2]=content
 像这样一样要一一对应

参数:
   parameterTypes - 参数数组
返回:
   与 指定的 parameterTypes(Class对象数组) 相匹配的 公共构造方法的 Constructor 对象
抛出:
   NoSuchMethodException - 如果找不到匹配的方法。
   SecurityException - 如果存在安全管理器 s,并满足下列任一条件:
调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问构造方法
调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包

需要注意的是:

如果是基本类型请使用它们的Type字段,如果是非基本类型使用class字段来返回其CLass类信息。


得到构造方法的 Constructor 对象,下一步就是得到相应 类 的实例了。

public T newInstance(Object... initargs)  

使用 此Constructor对象的构造方法 来 创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换。
如果底层构造方法所需形参数为 0,则所提供的 initargs 数组的长度可能为 0 或 null。

如果构造方法的声明类是非静态上下文的内部类,则构造方法的第一个参数需要是封闭实例;请参阅Java 语言规范 第 15.9.3 节。

如果所需的访问检查和参数检查获得成功并且实例化继续进行,这时构造方法的声明类尚未初始化,则初始化这个类。
如果构造方法正常完成,则返回新创建且已初始化的实例。

参数:
   initargs - 将作为变量传递给构造方法调用的对象数组;基本类型的值被包装在适当类型的包装器对象(如 Float 中的 float)中。(之前parameterTypes参数对应的Class对象数组,initargs则是Class对象数组中代表的类的具体的数值)

返回:
   通过调用此对象表示的构造方法来创建的新对象

抛出:
   IllegalAccessException - 如果此 Constructor 对象实施 Java 语言访问控制并且底层构造方法是不可访问的。
   IllegalArgumentException - 如果实参和形参的数量不同;如果基本参数的解包转换失败;如果在可能的解包后,无法通过方法调用转换将参数值转换为相应的形参类型;如果此构造方法属于枚举类型。
InstantiationException - 如果声明底层构造方法的类表示抽象类。
InvocationTargetException - 如果底层构造方法抛出异常。
ExceptionInInitializerError - 如果此方法引发的初始化失败。

以下是以上总结的一个实例

1.自定义一个类(作为 非基本类型的 类)

public class CustomClass {

    private String name = "";

    CustomClass(String name) {
        this.name = name;
        show();//如果创建成功,进行展示显示
    }

    public void show() {
        System.out.println(name);
    }

    @Override
    public String toString() {
        return "CustomClass=" + name;
    }
}

2.创建 反射类(里面有 不带参数的构造函数 和 代参的构造函数(参数有 整型、字符串、自定义类))

class ReflectClass {
    private String name = "ReflectClass";

    public ReflectClass(int age, String name, CustomClass my) {
        this.name = name;
        show(age, name, my);//创建成功后展示
    }

    public ReflectClass() {//构造函数重载,使用不同的参数列表创建对象
        //没有带参数的构造方法
    }

    public final void show(int age, String name, CustomClass my) {
        System.out.println("age=" + age + " name=" + name + " my=" + my);
    }

    @Override
    public String toString() {
        return "ReflectClass=" + name;
    }
}

3.展示

public class HomeClass {

    public static void main(String args[]) {
        //创建不带参数的对象
        ReflectClass rc1=(ReflectClass) HomeClass.getInstance("com.jijing.classDemo.ReflectClass");
        System.out.println("ReflectClass111="+rc1);

        System.out.println("******************************");
        //创建 带参数的 对象
        ReflectClass rc2 = (ReflectClass) HomeClass.getInstance("com.paynews.javalib.ReflectClass",
                new Class[]{Integer.TYPE, String.class, CustomClass.class},
                new Object[]{20, "这是String的值", new CustomClass("这是自定义类")});

        System.out.println("需要反射的 ReflectClass =" + rc2);
    }

    /**
     * @param name 需实例化类 的全路径
     * @return 不带参数的反射创建对象
     */
    public static Object getInstance(String name){
        Class c=getClass(name);
        Object o=null;
        try {
            o=c.newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
        }
        return o;
    }

    /**
     * @param className 需实例化类 的全路径
     * @return 返回根据className指明的类信息
     */
    public static Class getClass(String className){
        Class c=null;
        try {
            c=Class.forName(className);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
        }
        return c;
    }

    /**
     * @param name  需要返回的类 的全路径
     * @param classParas  Class类对象数组
     * @param paras   对应的具体的数值数值
     * @return 返回参数的类的实力
     */
    public static Object getInstance(String name,Class classParas[],Object paras[]){
        Object o=null;
        try {
            Class c=getClass(name);
            Constructor con=c.getConstructor(classParas);//获取使用当前构造方法来创建对象的Constructor对象,用它来获取构造函数的一些
            try {
                //信息
                o=con.newInstance(paras);//传入当前构造函数要的参数列表
            } catch (InstantiationException ex) {
                Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (NoSuchMethodException ex) {
            Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(ClassMain.class.getName()).log(Level.SEVERE, null, ex);
        }

        return o;//返回这个用Object引用的对象
    }
}

参考资料:直到完成无形的天空 的Java通过反射创建对象

  • 3
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值