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引用的对象
}
}