java反射
一、java反射概念
反射是java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection api 取得任何类的内部信息,并能直接操作任意对象的内部的属性和方法。
- 获取任何类的内部构成信息。
- 直接操作任意对象的内部属性和方法。
二、java反射作用与相关API
反射能做什么
- 在运行时判断任意一个对象所属类。
- 在运行时新建任意一个类的实例。
- 在运行时判断任意一个类所具有的成员属性和方法。
- 在运行时调用任意一个对象的成员属性和方法。
- 生成动态代理。
反射相关API
- java.lang.Class : 代表一个类;
- java.lang.reflect.Method : 代表类的方法;
- java.lang.reflect.Field : 代表类的属性;
- java.lang.reflect.Constructor : 代表类的构造器方法;
三、java反射的关键类 Class
1、Class类简介
在java的世界里,一切皆对象。从某种意义来讲,java中有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类相关的信息;我们的实例对象就是通过Class对象来创建的;java使用Class对象执行其RTTI(运行时类型识别),多台是基于RTTI实现的;
每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型(boolean, byte, short, int, long, float , double)有Class对象,数组有Class对象,关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类。Class类没有公共的构造方法,Class对象是在类加载的时候由java虚拟机
以及通过调用类加载器中的defineClass方法自动构造的,因此不能显式地声明一个Class对象. 当.class文件加载到内存以后,就是一个运行时类,存放于缓存区,此时这个运行时类本身就是一个Class类型的实例。
- 每个运行时类只加载一次,且线程安全。
- 有了Class实例之后,我们才可以进行反射操作。
2、Class类型对象常用方法
方法名 | 说明 |
---|---|
forName() | (1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。 (2)为了产生Class引用,forName()立即就进行了初始化。 |
Object-getClass() | 获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。 |
getName() | 取全限定的类名(包括包名),即类的完整名字。 |
getSimpleName() | 获取类名(不包括包名) |
getCanonicalName() | 获取全限定的类名(包括包名) |
isInterface() | 判断Class对象是否是表示一个接口 |
getInterfaces() | 返回Class对象数组,表示Class对象所引用的类所实现的所有接口。 |
getSupercalss() | 返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现一个对象完整的继承结构。 |
newInstance() | 返回一个Oject对象,是实现“虚拟构造器”的一种途径。使用该方法创建的类,必须带有无参的构造器。 |
getFields() | 获得某个类的所有的公共(public)的字段,包括继承自父类的所有公共字段。 类似的还有getMethods和getConstructors。 |
getDeclaredFields() | 获得某个类的自己声明的字段,即包括public、private和proteced,默认但是不包括父类声明的任何字段。类似的还有getDeclaredMethods和getDeclaredConstructors。 |
getMethods | |
getDeclaredMethods | |
getConstructors | |
getDeclaredConstructors |
3、获取Class类型实例
- 通过运行时类本身的.class属性获取 Class 实例。
Class clazz = Person.class;
Class clazz1 = String.class;
System.out.println( clazz.getName() ); #获取类完整名。
System.out.println( clazz1.getPackage() ); #获取类所在的包名。
- 通过运行时类的对象.getClass()方法获取 Classs 实例。
Perosn person = new Person();
Class clazz = person.getClass();
- 通过 Class 的静态方法获取 Class 实例。
String className = "com.mz.Person";
Class clazz = Class.forName(className);
System.out.println(clazz.getName());
三、java类加载器 ClassLoader
1、类加载器简介
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对类进行初始化。
- 类的加载 :
将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成。 - 类的连接 :
将类的二进制数据合并到JRE中。 - 类的初始化 :
JVM负责对类进行初始化。
类加载器是用来把类(class)装载到内存中的,JVM规范定义了两种类型的类加载器: 启动类加载器Bootstrap
,用户自定义类加载器user-defined classLoader
.JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。双亲委派机制
- Bootstrap classLoader 引导器加载器 :
用c++编译,是jvm自带的类加载器,负责java平台核心库,用来加载核心类库,该加载器无法直接获取。 - Extension classLoader 扩展器加载器 :
负责jre/lib/ext目录下的jar包,或-D java.ext.dirs指定目录下的jar包装入工作库。 - System classLoader 系统类加载器 :
负责应用的类路径下的jar包加载。
2、 获取classloader的方式
#方式1
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
System.out.println( loader1 );
#方式2
ClassLoader loader2 = loader1.getParent();
System.out.println( loader2 );
#方式3
Class clazz = Person.class;
ClassLoader loader3 = clazz.getClassLoader();
System.out.println( loader3 );
#方式4
String className = "java.lang.Object";
class clazz4 = Class.forName(className);
#java核心类库的classLoader是不能获取到的。
ClassLoader loader4 = clazz4.getClassLoader();
System.out.println( loader4 ); # null
#方式5
String className = "com.mz.UserInfo";
class clazz5 = Class.forName(className);
#java核心类库的classLoader是不能获取到的。
ClassLoader loader5 = clazz5.getClassLoader();
System.out.println( loader5 ); #存在,是SystemClassLoader
3、通过classLoader来加载类路径下的文件
#类路径下加载文件
ClassLoader loader = this.getClass().getClassLoader();
InputStream is = loader.getResourceAsStream("com/mz/jdbc.properties");
Properties props = new Properties();
props.load(is);
三、java反射使用
利用反射获取类结构信息
1、通过Class类型实例创建对象
- 要求:
- 类必须有一个无参的构造器。
- 类的构造器的访问权限需要足够(public或者同包下protected)。
Class clazz = Class.forName("com.mz.UserInfo"); Object obj = claz.newInstance();
2、获取运行时类对象的成员属性 Field
- getFields() : 获取到运行时类中定义的,或者继承来的public修饰符的成员属性。
Field[] fields = clazz.getFields(); for( Field item : fields ){ System.out.println(item); }
- getDeclaredFields() : 获取运行时类自身声明的所有的属性。
Field[] fields = clazz.getDeclaredFields(); for( Field item : fields ){ System.out.println(item); }
3、获取属性的权限修饰符
,变量类型
,变量名
public void test(){
Class clazz = Perosn.class;
Field[] fields = clazz.getDeclaredFields();
for( Field item : fields ){
//1.获取属性名
String propertyName = item.getName();
System.out.println(propertyName);
//2.获取属性类型
Class type = item.getType();
String typeName = type.getTypeName();
System.out.println("typeName: "+typeName);
System.out.println(type.getName());
//3.获取权限修饰符
int i = item.getModifiers();
String modifierName = Modifier.toString(i);
System.out.println("modifierName:"+modifierName);
}
}
4、获取运行时类对象的方法 Method,以及注解
,权限修饰符
,返回值类型
,方法名
,形参列表
,异常
Class clazz = Class.forName("com.company.UserInfo");
#获取public修饰的自身定义,以及继承来的方法。
Method[] methods = clazz.getMethods();
for ( Method item : methods ){
System.out.println(item.getName());
}
#获取自身类定义的所有方法。
methods = clazz.getDeclaredMethods();
for ( Method item : methods ){
//1.获取方法名
System.out.println(item.getName());
//获取方法上的注解
Annotation[] annotations = item.getAnnotations();
for ( Annotation annotation : annotations ){
System.out.println(annotation);
}
//获取方法的权限修饰符
String modifierName = Modifier.toString(item.getModifiers());
System.out.println(modifierName);
//获取返回值类型
Class returnType = item.getReturnType();
String returnTypeName = returnType.getTypeName();
System.out.println(returnTypeName);
//获取形参列表的类型
Class[] params = item.getParameterTypes();
for ( Class p : params ){
String paramName = p.getName();
System.out.println("paramName: "+paramName);
}
//获取方法抛出异常的类型
Class[] exps = item.getExceptionTypes();
for ( Class exp : exps ){
System.out.println(exp.getName());
}
System.out.println("============>");
}
5、通过 Class对象 获取构造器
Class clazz = Class.forName("com.company.UserInfo");
#与Method类似
Constructor[] constructors = clazz.getConstructors();
for ( Constructor item : constructors ){
System.out.println(item.getName());
}
6、通过 Class对象 获取类的父类
Class clazz = Class.forName("com.company.UserInfo");
#获取本类继承的父类的Class对象。
Class superClass = clazz.getSuperclass();
System.out.println(superClass.getName());
7、通过 Class对象 获取父类的泛型
Class clazz = Class.forName("com.company.UserInfo");
Type type = clazz.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
//获取泛型编译之后的实际类型
Type[] ars = parameterizedType.getActualTypeArguments();
System.out.println( ((Class)ars[0]).getName() );
8、通过 Class对象 获取类实现的接口
Class clazz = Class.forName("com.company.UserInfo");
Class[] interfaces = clazz.getInterfaces();
for ( Class item : interfaces ){
System.out.println( item);
}
9、通过 Class对象 获取类所在的包
Class clazz = Class.forName("com.company.UserInfo");
Package aPackage = clazz.getPackage();
System.out.println( aPackage.getName() );
10、通过 Class对象 获取类上的注解
Class clazz = Class.forName("com.company.UserInfo");
Annotation[] annotations = clazz.getAnnotations();
利用反射,获取和设置属性值,调用方法
利用反射,获取和设置属性值
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.company.UserInfo");
UserInfo userInfo = (UserInfo) clazz.newInstance();
userInfo.setUsername("meng");
userInfo.setAge(24);
userInfo.setAdult(true);
userInfo.setGender(1);
userInfo.setWeight(150);
Field[] fields = clazz.getDeclaredFields();
for ( Field item : fields ){
//1.获取属性名
String propertyName = item.getName();
System.out.println(propertyName);
//1.1获取属性的类型
String propertyType = item.getType().getSimpleName();
System.out.println(propertyType);
//2.获取值
item.setAccessible(true);
System.out.println( item.get(userInfo) );
System.out.println("=========>");
//3.设置值
if ( "boolean".equals(propertyType.toLowerCase()) ){
item.set(userInfo, false);
}else if( "float".equals(propertyType.toLowerCase()) ){
item.set(userInfo, 0F);
}else if( "int".equals(propertyType.toLowerCase()) ){
item.set(userInfo,0);
}else {
item.set(userInfo, null);
}
}
}
利用放射,调用实例中的静态方法,成员方法
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.company.UserInfo");
UserInfo userInfo = (UserInfo) clazz.newInstance();
userInfo.setUsername("meng");
userInfo.setAge(24);
userInfo.setAdult(true);
userInfo.setGender(1);
userInfo.setWeight(150);
//获取 并且 调用无参的实例方法,并且获取返回值。
Method method = clazz.getDeclaredMethod("getUsername");
String name = (String) method.invoke(userInfo);
System.out.println(name);
//获取 并且 调用有参的实例方法。
Method method1 = clazz.getDeclaredMethod("setUsername", String.class);
method1.invoke(userInfo, "mmm");
System.out.println(userInfo.getUsername());
//获取 并且 调用静态方法。
Method method2 = clazz.getDeclaredMethod("info");
method2.invoke( UserInfo.class );
}
四、java反射实例
实例1 : 动态代理
实例2 :对象属性复制