首页 > 代码库 > java之反射
java之反射
java之反射
一、Java Reflection
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,
并能直接操作任意对象的内部属性及方法
①Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理
②反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
二、Class 类
①Class本身也是一个类
java.lang.Class:是反射的源头。
我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)
此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在在缓存区。那么这个运行时类本身就是一个Class的实例!
1.每一个运行时类只加载一次!
2.有了Class的实例以后,我们才可以进行如下的操作:
1)*创建对应的运行时类的对象
2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解、...)
3)*调用对应的运行时类的指定的结构(属性、方法、构造器)
4)反射的应用:动态代理
②Class类的常用方法
static Class forName(String name) :加载并返回指定类名 name 的 Class 对象
Object newInstance() :调用缺省构造函数,返回该Class对象的一个实例
String getName() :返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称
Class getSuperClass():返回当前Class对象的父类的Class对象
Class [] getInterfaces() :获取当前Class对象的接口
ClassLoader getClassLoader() :返回该类的类加载器
Constructor[] getConstructors():返回一个包含某些Constructor对象的数组
Field[] getFields():返回Field对象的一个数组
Method getMethod(String name,Class … paramTypes):返回一个Method对象,此对象的形参类型为paramType
③实例化Class类对象(四种方法)
1)前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
实例:Class clazz = new String().getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName(类的全类名)获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4)其他:通过类加载器去加载
ClassLoader loader = this.getClass().getClassLoader();
Class clazz4 = loader.loadClass(“java.lang.String”);
④了解:类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化
1)将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
2)将类的二进制数据合并到JRE中
3)JVM负责对类进行初始化
⑤了解:ClassLoader类加载器
类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:
启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)。
JVM在运行时会产生3个类加载器组成的初始化加载器层次结构
1)引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库。该加载器无法直接获取
2)扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库
3)系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器
//1.获取一个系统类加载器
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader);
//2.获取系统类加载器的父类加载器,即扩展类加载器
classloader = classloader.getParent();
//3.获取扩展类加载器的父类加载器,即引导类加载器
classloader = classloader.getParent();
//4.测试当前类由哪个类加载器进行加载
classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
//5.测试JDK提供的Object类由哪个类加载器加载
classloader = Class.forName("java.lang.Object").getClassLoader();
//*6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流
InputStream in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
三、创建类对象并获取类的完整结构
①创建类的对象:调用Class对象的newInstance()方法
要 求:1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
若没有无参的构造器,只能在操作的时候明确的调用类中的构造方法,并将参数传递进去之后,才可以实例化操作。步骤如下:
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)调用Constructor类的newInstance(object ... args)
②通过反射调用类的完整结构
②①获取对应的运行时类的属性 java.lang.reflect.Field
1)Field[] getFields():只能获取到运行时类中及其父类中声明为public的属性
2)Field[] getDeclaredFields():获取运行时类本身声明的所有的属性
3)Field getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性
4)Field getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性,可以获取所有的属性,包括private属性
5)获取属性的各个部分的内容(权限修饰符 变量类型 变量名)
1.获取每个属性的权限修饰符
int i = feild.getModifiers();返回代表修饰符的一个整数
String str1 = Modifier.toString(i);通过Modifier的toString()将数值转化为字符串
2.获取属性的类型
Class type = feild.getType();:返回属性类型的Class对象
3.获取属性名
String str = feild.getName();返回属性的名称
6)修改属性值方法一 (public String name;)
Class clazz = Person.class;
//1.获取指定的属性getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性
Field name = clazz.getField("name");
//2.创建运行时类的对象
Person p = (Person)clazz.newInstance();
System.out.println(p);
//3.将运行时类的指定的属性赋值
name.set(p,"Jerry");
7)修改属性值方法二 (private int age;)
//getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性
Field age = clazz.getDeclaredField("age");
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
age.setAccessible(true);
age.set(p,10);
②②获取运行时类的方法 java.lang.reflect.Method
1)Method[] getMethods():获取运行时类及其父类中所有的声明为public的方法
2)Method[] getDeclaredMethods():获取运行时类本身声明的所有的方法
3)Method getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
4)Method getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
5)获取方法的各个部分的内容(注解 权限修饰符 返回值类型 方法名 形参列表 异常)
//1.注解
Annotation[] ann = method.getAnnotations();
//2.权限修饰符
String str = Modifier.toString(method.getModifiers());
//3.返回值类型
Class returnType = method.getReturnType();
//4.方法名
String str = method.getName();
//5.形参列表
Class[] params = method.getParameterTypes();
//6.异常类型
Class[] exps = method.getExceptionTypes();
6)调用运行时类中指定的方法一 [public void show()]
Class clazz = Person.class;
//getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
Method method = clazz.getMethod("show");
Person p = (Person)clazz.newInstance();
//调用指定的方法:Object invoke(Object obj,Object ... obj)
Object returnVal = m1.invoke(p); :返回调用方法的返回值
System.out.println(returnVal);
//对于运行时类中静态方法的调用[public static void info()]
Method method = clazz.getMethod("info");
method.invoke(Person.class);
7)调用运行时类中指定的方法二 [private int show(String nation,int age)]
//getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
Method method = clazz.getDeclaredMethod("display",String.class,int.class);
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
method.setAccessible(true);
Object value = http://www.mamicode.com/method.invoke(p,"CHN",10);
System.out.println(value);
②③获取运行时类的构造器 java.lang.reflect.Constructor
1)public Constructor<T>[] getConstructors()返回此 Class 对象所表示的类的所有public构造方法。
2)public Constructor<T>[] getDeclaredConstructors()返回此 Class 对象表示的类声明的所有构造方法
3)public Constructor<T> getConstructor(Class<?>... parameterTypes) :返回指定的public的构造器
4)public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回类中声明了的指定的构造器,包括private构造器
5)调用运行时类中指定的构造器一
String className = "com.lang.String";
Class clazz = Class.forName(className);
//创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
//要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。
Object obj = clazz.newInstance();
String p = (String)obj;
6)调用运行时类中指定的构造器二
String1 className = "com.lang.String1";
Class clazz = Class.forName(className);
Constructor cons = clazz.getConstructor(String.class,int.class);
String1 p = (String1)cons.newInstance("小三",20);
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
String1 p = (String1)cons.newInstance("小三",20);
②④获取运行时类的注解
Class clazz = String.class;
Annotation[] anns = clazz.getAnnotations();
for(Annotation a : anns){
System.out.println(a);
}
②⑤获取运行时类所在的包
Class clazz = String.class;
Package pack = clazz.getPackage();
System.out.println(pack);
②⑥获取运行时类的实现的接口
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for(Class i : interfaces){
System.out.println(i);
}
②⑦*.获取运行时类的父类的泛型
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType)type1;
Type[] ars = param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
②⑧获取带泛型的父类
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
System.out.println(type1);
②⑨获取运行时类的父类
Class clazz = Person.class;
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
java之反射