Java反射的基本理解,Java反射理解
Java反射的基本理解,Java反射理解
在了解Java的反射之前,先理解一下Java的动态性
一、动态语言:
程序运行的时候,可以改变程序的结构或变量的类型。
1、典型的动态语言有:Python,ruby,JavaScript
2、C,C++,Java都不是动态语言,但是Java有一点不同,Java虽然不是动态语言,但是Java具有一定的动态特性,我们可以利用Java的反射机制,字节码操作获得类似动态语言的特性。
二、反射机制
1、反射机制指的是可以于运行时加载,探知,使用编译期间完全未知的类
2、程序在运行状态中,可以动态加载一个只有名称的类,对于任何一个已加载的类,都能知道这个类的所有属性和方法,对于任意一个对象都能够调用它的任何一个属性和方法
3、加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结果信息。可以通过这个对象看到类的结果。
4、一个类被加载后,JVM会创建一个对应类的Class对象,类的整个结构信息会放在对应的Class对象中。
简单实例:
package com.silence.bean;
/**
* 创建一个Javabean
* @author zhuxiang
*
*/
public class User {
private int id;
private int age;
private String uname;
//一个Javabean必须要有无参构造器
public User(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public User(int id, int age, String uname) {
super();
this.id = id;
this.age = age;
this.uname = uname;
}
}
通过另一个类来测试
package com.silence.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import com.silence.bean.User;
/**
* 通过反射动态调用构造器
* @author Silence
*
*/
@SuppressWarnings("all")
public class Test02 {
public static void main(String[] args) {
String path = "com.silence.bean.User";
try {
Class<User> clz = (Class<User>) Class.forName(path);
//通过反射API调用构造器,构造对象
User user = clz.newInstance();//调用User的无参构造器实例化一个User对象
System.out.println(user);
//通过指定构造器构造对象
Constructor<User> constructor = clz.getDeclaredConstructor(int.class,int.class,String.class);
User user2 = constructor.newInstance(1210322,22,"studentname");
System.out.println(user2.getUname());
//通过反射API动态调用普通方法
User user3 = clz.newInstance();
Method method = clz.getDeclaredMethod("setUname", String.class);
method.invoke(user3, "长江");//这两行相当于user3.setUname("长江");
//此处应注意一个问题,那就是如果调用某个类的main方法的时候,由于main方法是静态的以及参数是String数组(String[] args)
//调用时invoke()函数的参数应该这样写:invoke(null,(object)new String[]{})。
//调用静态方法时第一个参数为null即可,第二个参数必须强制转换为object类型
System.out.println(user3.getUname());
//通过反射API动态调用属性
User user4 = clz.newInstance();
Field field = clz.getDeclaredField("uname");
field.setAccessible(true); //该句代码表示不检查私有的变量,让反射机制可以访问私有变量,
//没有该句代码会出现异常,提示不能操作private修饰的变量
field.set(user4, "大海");//通过反射写入属性
System.out.println(user4.getUname());
System.out.println(field.get(user4));//通过反射读取属性
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、反射机制的常见的作用
1、动态加载类,动态获取类的信息(属性,方法,构造器);
2、动态构造实例
3、动态调用类和对象的任意方法,构造器
4、动态调用和处理类的属性
5、获取泛型信息
6、获取处理注解
四、反射机制的性能问题
1、setAccessible
1)启用和禁用访问安全检查的开关,值为true则指示反射的对象在使用时应取消Java语言访问检查;值为false时,则指示反射的对象应该实施Java语言的访问检查。并不是值为true时就能访问,值为false时就不能访问。
2)禁止安全访问检查,可以提高反射的运行速度。一般来说,不用反射的(普通调用)比反射(setAccessible=false)效率高30倍左右,比反射(setAccessible=true)效率高7倍左右。当然只是一般来说。。。
2、反射操作泛型
1)Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。但是,一旦编译完成后,所有的和泛型有关的类型全部擦除了,无法查看到了。
2)为了通过反射来操作这些类型以迎合实际开发的需要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型,但是又和原始类型齐名的类型。
ParameterizedType:表示一种参数化的类型,比如Collection<String>
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共接口
WildcardType:代表一种通配符类型 比如 ? , ? extends Number, ? super Integer
下面以第一个parameterizedType为例,获取泛型参数和泛型类型返回值的方法:
package com.silence.test;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import com.silence.bean.User;
/**
* 通过反射来操作泛型
* @author zhuxiang
*
*/
public class RefGeneric {
public void test01(Map<String, User> map, List<User> list){
System.out.println("RefGeneric.test01()");
}
public Map<Integer, User> test02(){
System.out.println("RefGeneric");
return null;
}
public static void main(String[] args) {
try {
//获得指定方法参数泛型信息
Method method = RefGeneric.class.getMethod("test01", Map.class,List.class);
Type[] types = method.getGenericParameterTypes();
for (Type paramType : types) {
System.out.println("#" + paramType);
if (paramType instanceof ParameterizedType) {
Type[] genericTypes = ((ParameterizedType)paramType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("泛型类型:" + genericType);
}
}
}
//获得指定方法返回值泛型信息
Method method2 = RefGeneric.class.getMethod("test02", null);
Type returnType = method2.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
Type[] genericTypes = ((ParameterizedType)returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型类型:" + genericType);
}
}
} catch (Exception e) {
}
}
}
相关文章
- 暂无相关文章
用户点评