Java学习笔记:反射

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/sinat_38393872/article/details/91323998

什么是反射:当我们得到一个Object时,我们不知道这个对象具体是哪一个类,但我们又需要操作这个对象里的方法或者变量时,我们可以通过反射得到这个对象的类信息。

先介绍一下Java里一个使用一个类之前JVM里发生了什么。

当程序使用某个类时,JVM会连续完成类的加载,连接和初始化这三个步骤。后面两个步骤先不考虑,就单独说说加载。类加载就是将类的class文件读入内存,并且为之创建一个java.lang.Class对象。这个java.lang.Class对象里记录着某一个类的类信息。反射获取的Class对象就是这个java.lang.Class对象。

下面开始总结通过反射得到类信息和操作类中的成员。


通过反射获取Class对象

Java程序里获取Class对象有三种方式

  • 使用Class类的forName(String className)的静态方法。
  • 调用某个类的class属性来获取Class对象。比如Person.class就会返回Person类的Class对象。这个方法比第一个方法要好一些,因为这是调用属性,不是调用方法,性能更好。而且在编译阶段程序就可以检查需要访问的Class对象是否存在。
  • 调用某个对象的getClass()方法。

得到Class对象之后,就可以通过这个Class对象来获取其它信息了


通过反射获取类Class中的构造方法类Constructor

第一种方法

Constructor<T> getConstructor(Class<?> parameterTypes)

这是返回此Class对象对应类的带指定形参列表的public构造器。其中的参数都是Class。比如说,某一个构造器是这样写的,参数类型是String,

A(String s){
    s = "hello";
}

那么在利用反射获取构造器时参数是String.class。比如下面这样的写法。

Class<A> a = A.class;
Constructor<T> constr = a.getConstructor(String.class);

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第二种方法

Constructor<?>[] getContructors()

返回此Class对象对应类的所有public构造器。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第三种方法

Contructor<T> getDeclaredConstructor(Class<?> ...parameterTypes)

返回此Class对象对应类的带指定形参列表的构造器,并且和构造器的访问权限无关。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第四种方法

Constructor<?>[] getDeclaredConstructors()

返回此Class对象对应类的所有构造器,并且与构造器的访问权限无关。


通过反射获取类Class中的方法类Method

第一种方法

Method getMethod(String name, Class<?>...parameter)

获取指定名称,指定参数的public方法,

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第二种方法

Method[] getMethods()

获取所有的public方法。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第三种方法

Method getDeclaredMethod(String name, Class<?>...parameter)

获取指定名称指定参数的方法,与访问权限无关。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第四种方法

Method[] getDeclaredMethods()

获取所有的方法,与访问权限无关。


通过反射获取类CLASS中的成员变量类Field

第一种方法

Field getField(String name)

返回类中对应名称的,public的成员变量。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第二种方法

Field[] getFields()

返回类中所有的public成员变量。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第三种方法

Field getDeclaredField(String name)

放回类中对应名称的成员变量,与访问权限无关。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

第4中方法

Field[] getDeclaredFields()

返回所有成员变量,与访问权限无关。


访问CLASS对应类包含的Annotation


访问CLASS对应类包含的内部类

下面是通过反射生成并操作对象,在JavaEE框架中就常常会用到


通过反射获取对象实例

Java程序里获取Class对象有两种方式

  • 使用Class类中的newInstance()方法:这个方法其实是调用默认构造器来生成实例,但是不推荐,java文档中已经弃用了。比较推荐下面的用法。
  • 通过Class类获取Constructor对象,再调用Constructor中的newInstance()方法来得到类的实例。

得到对象实例之后,就可以通过这个实例来获取其它信息了


通过反射使用对象实例的方法

在上面提到了如果获取某一个类方法的Method对象,下面假设已经获得的Method对象名是method。

method里只是储存方法的信息,如果要调用方法则必须使用Method中的invoke方法,如下所示

Object inovke(Object obj, Object...parameter)

我们要通过具体的实例obj调用方法。invoke的第二个参数是调用方法所需要的参数,类型都是Class。

invoke返回的是调用方法的返回值。具体实例如下

class A{
	int d;
	public A(int a, int b, int c){
		d = 2;
	}
	public int a1(){
		System.out.println("a1");
		return 1;
	}
}
public class test{
	public static void main(String[] args)throws Exception{
		Class clazz = A.class;
		Class[] buff = new Class[3];
		buff[0] = int.class;
		buff[1] = int.class;
		buff[2] = int.class;
		A a = new A(1,2,3);
		Method method = clazz.getMethod("a1");
		System.out.println(method.invoke(a));
	}
}

输出如下

通过反射操作方法必须是操作某一具体实例的方法,即使这个方法是static方法——属于类方法,那也必须通过某一具体实例。

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

这里说一下使用反射操作方法时涉及到的权限问题。可以将反射看成一般的函数调用,符合一般的函数调用的权限规则。比如将上面代码中类A的方法a1的作用域改成private,反射调用方法就会出现错误。如果还是想调用private方法,那就要使用Method中的setAccessible方法

void setAccessible(boolean flag)

如果flag设为true,表明这个方法可以无视一般的权限规则,随意调用;如果flag设为false,表明这个方法要遵守一般的权限规则。默认为false。

class A{
	int d;
	public A(int a, int b, int c){
		d = 2;
	}
	private int a1(){
		System.out.println("a1");
		return 1;
	}
}
public class test{
	public static void main(String[] args)throws Exception{
		Class clazz = A.class;
		Class[] buff = new Class[3];
		buff[0] = int.class;
		buff[1] = int.class;
		buff[2] = int.class;
		A a = new A(1,2,3);
		Method method = clazz.getDeclaredMethod("a1");
		method.setAccessible(true);
		System.out.println(method.invoke(a));
	}
}

通过反射访问类中的成员变量

在上面提到了获取Field类的方法,假设已经获取了某一类的Field类实例变量名为field。

Field类主要提供了获取成员变量的值和修改成员变量的值两个方法。先说前者。

xxx getXxx(Object obj)    //这是获取某一具体类实例的成员变量值。obj是具体的类实例,
//xxx是成员变量的类型。比如下面这些代码成员变量分别是char,int和boolean。
char getChar(Object obj)
int getInt(Object obj)
boolean getBoolean(Object obj)

//如果成员变量类型是引用,那么就应该省略xxx。比如某一成员变量的类型是类A,那么获取该成员变量的方法是
Object get(Object obj)

改变成员变量的值也差不多

xxx getXxx(Object obj, xxx val)    //这是改变某一具体类实例的成员变量值。obj是具体的类实例,val是要修改的值。

猜你喜欢

转载自blog.csdn.net/sinat_38393872/article/details/91323998