【Java笔记】反射机制中用Class操作的一些演示

来源:互联网 发布:js 检测div大小变化 编辑:程序博客网 时间:2024/06/10 06:50
package Test_01;
import org.junit.Test;public class Test_01 {@Testpublic void Dome_05() throws InstantiationException, IllegalAccessException{Class cc1=Cat.class;Cat cat=(Cat) cc1.newInstance();//这个方法是通过类对象调用构造器来创建类的实例对象;cat.age=3;}}
package Test_01;public class Cat extends Animals{ String name; int age; int legs; Cat(){}}
成功创建Cat对象


我们来看一下newInstance的API解释:

newInstance

public T newInstance()              throws InstantiationException,                     IllegalAccessException

创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。



实际上newInstance就是通过调用无参构造器来创建对象,我如果把Cat中的构造器私有化:

package Test_01;public class Cat extends Animals{ String name; int age; int legs;private Cat(){}}
运行时报错

所以,用newInstance必须保证在类里一定要有一个无参构造器;

上面是newInstance来创建对象的方法,其实和直接new对象没有什么很大的区别;下面我们来看一下Class的真正强大之处:

package Test_01;public class Cat extends Animals{ private String name; private int age; private int legs; private Cat(){} private Cat(String name,int age,int legs){this.age=age;this.legs=legs;this.name=name;}}
可以看到我完全把Cat类封装,也没有实行单例模式,也没有设置get、set方法,按理来说已经没办法实例化它的对象了,但是用Class的反射机制可以通过调用方法来返回Constructor中的方法来实例化它!

API:Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。 

@Testpublic void Dome_05() throws InstantiationException, IllegalAccessException, Exception, Throwable{Class<Cat> cc = Cat.class;//通过Class类中的getDeclaredConstructor可以获得私有化的构造器Constructor<Cat> constructor =cc.getDeclaredConstructor(String.class,int.class,int.class);//把constructor的权限设成trueconstructor.setAccessible(true);//下面就可以通过构造器来实例化对象了Cat gaffey=constructor.newInstance("gaffey",3,4);System.out.println(gaffey);}
输出结果:Test_01.Cat@14514713

打印出了对象的地址,说明成功创建了一个对象;注意:此时就算是创建了对象,我的Cat的成员变量仍是全部私有化的,所以也不能通过对象对成员变量进行操作;

在jdk的API中:

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)           返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。  Constructor<?>[] getDeclaredConstructors()           返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 

可知,我们通过控制传入参数的多少来控制调哪一个构造器,要注意的是,如果我们传参数,传入的必须是类对象,这个类不是我们通常说的类或创建的类(小写的class),而是大写的Class,是jdk中存在的单例模式的Class,所有的小写的class类,都可以是这个大写的Class类的对象,比如我们要传入String,就应该传入String的class属性,用“String.class";

看一下Constructor类,里面也有一个newInstance方法:

newInstance
public T newInstance(Object... initargs)

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

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

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

如果构造方法正常完成,则返回新创建且已初始化的实例。

显然通过构建Constructor就可以调用有参的构造器了,我上面的那篇代码中也演示了用Constructor的newInstance方法来调用构造器实例化对象;