一、概念
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的因此也被称为动态加载类。反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。
1.认识Class类
Class是一个java类,跟Java API中定义的诸如Thread、Integer类、我们自己定义的类是一样,也继承了Object(Class是Object的直接子类)。总之,必须明确一点,它其实只是个类,只不过名字比较特殊。更进一步说,Class是一个java中的泛型类型。
Java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象,可以通过这个Class对象对被装入类的详细信息进行访问。(Java中Class对象和类的实例对象是两个不同的概念,不能混淆!)(每一个类都有一个封装它的java.lang.Class类对象) 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
一般某个类的Class对象被载入内存,它就用来创建这个类的所有实例对象:事实上,Class对象就是用来创建类的所有的“普通”对象的。 类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(恰当地说,是被保存在一个同名的.class文件中)。在运行时,当我们想生成这个类的对象时,运行这个程序的 Java虚拟机(JVM)首先检查这个类的Class对象是否已经加载。如果尚未加载,JVM就会根据类名查找.class文件,并将其载入。 一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有(实例)对象.
在Java中Object是一切类的父类,那么所有类的对象实际上也都是Java.lang.Class类的实例,所以所有的对象都可以转变为Java.lang.Class类型表示。
2.获取class 对象三种方法
1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:MyObject x;
Class c1 = x.getClass();
2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如:
Class c2 = Class.forName("myObject") //MyObject 必须是接口或则类名
3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
Class c1 = Manager.class;
Class c2 = int.class;
Class c3 = Double[].class;
//综合实例
public class test {
public static void main(String[] args)
{
//三种反射方式
/************************************/
try {
Class<?> h2 =Class.forName("Hello");
//找到了封装的Class类对象.
h2.getConstructors();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
/*************************************/
Class<?> h = Hello.class;
//找到了封装的Class类对象.
h.getConstructors();
/*************************************/
Hello hello =new Hello();
Class<?> c = hello.getClass();
//找到了封装的Class类对象.
c.getConstructors();
}
}
3.Class类的常用方法
// 得到一个类的对象.
public T newInstance()
// 得到一个类的全部构造方法
public Constructors[] getConstructors() throws SecurityException
//得到本类中单独定义的全部属性(不包括继承的属性)
public Field[] getDeclareFields() throws SecurityException
//得到本类全部属性(public)
public Field[] getFields() throws SecurityException
//得到一个类中的全部方法
public Method[] getMethods()
//得到一个类中自定义的方法
public Method[] getDeclareMethods()
//返回一个method对象,并设置一个方法中的所有参数类型
public Method getMethod(String methodname, Class<?>... parameterTypes){参数类类型数组}
4.使用Class对象
要想对JVM中Class类封装的信息进行访问
通过无参构造实例化对象
Class<?> c =String.class;//也可以用forname得到class对象。
//得到class对象后,通过newInstance实例化对象。
Object str =c.newInstance();
调用有参构造实例化对象
操作时需要明确调用的构造函数,并将参数进行传递。
1.通过class类的getConstructors()取得本类中的全部构造方法
2.向构造方法传递一个对象数组进去,里面包含了构造方法所需的各个参数
3.之后通过Constructor实例化对象
Class<?> c =null;
c =Class.forNAme("org.sysu.book");
Constructor<?> cons[] =null;
cons=c.getConstructors();
Book book =(Book)cons[0].newInstance("wkn",22);
二、反射的基本运用
反射可以用于判断任意对象所属的类,获得Class对象,构造任意一个对象以及调用一个对象。介绍一下基本反射功能的实现.
1 判断是否为某个类的实例
public native boolean isInstance(Object obj);
Hello hello =new Hello();
Class<?> c = hello.getClass();//找到了封装的Class类对象.
System.out.println(c.isInstance(hello));
//true
2. 创建实例
1.使用class对象的newInstance()方法创建class对象对应类的实例(默认的构造函数)
Class<?> c =String.class;
Object str =c.newInstance();
2.先通过class对象获取指定的Constructor对象(由于构造器之间的区别在于参数,故需要传入参数对应的泛型类),再调用Constructor对象的newInstance()方法创建实例,这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器!!!!
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("wkn");
System.out.println(obj);
3.获取方法
1.getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
2.getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
3.getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes)
4.调用方法
当我们从类中获取了一个方法后,我们就可以用invoke()方法来调用这个方法。invoke方法的原型为: 调用方法,必须传入对象实例
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
//obj是指定哪个对象调用,args是传入的参数.
//实例2
Hello hello1 =new Hello();
Class<?> t = hello.getClass();//找到了封装的Class类对象.
try {
Method m = t.getMethod("method1",String.class);//method1 是方法的名字
Hello hello2 = (Hello) t.newInstance();// Hello对象
Object re = m.invoke(hello2,"sss"); //反射调用方法
System.out.println(re);
} catch (Exception e) {
e.printStackTrace();
}