JAVA动态性之一一反射机制reflection

时间:2022-10-26 21:18:17

package com.bjsxt.reflection.test.bean;

public class User {
private int id;
private int age;
private String uname;
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;
}
public User() {
super();
// TODO Auto-generated constructor stub
}

}

package com.bjsxt.reflection.test;
/**
*
* 测试各种类型(class,interface,enum,annotation,primitive type,void)java。lang。Class对象获取方式
* @author Administrator
*
*/
@SuppressWarnings(
"all")
public class Demo01 {
public static void main(String[] args) {
String path
= "com.bjsxt.reflection.test.bean.User";
try {
Class clazz
= Class.forName(path);
// 一个类被加载后 JVM就会创建一个该类的Class对象。类的结构信息会放大对应的Class对象中

System.
out.println(clazz.hashCode());


Class clazz2
= Class.forName(path);
System.
out.println(clazz2.hashCode());//同一个类只有一个反射对象


Class strClazz
= String.class;
Class strClazz2
= path.getClass();
System.
out.println(strClazz == strClazz2);

Class intClazz
= int.class;
//数组 同样的数据类 比较是不是同一个维度 不同 则不同
int[]arr01 = new int[10];
int[]arr02 = new int[30];
//2维数组
int[][]arr03 = new int [3][3];
System.
out.println(arr01.getClass().hashCode());
System.
out.println(arr02.getClass().hashCode());
System.
out.println(arr03.getClass().hashCode());

double[]arr04 = new double[10];
System.
out.println(arr04.getClass().hashCode());
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

 

1442002549
1442002549
true
1383884648
1383884648
1701381926
1381270477

 

以上是如何获取

各种类型(class,interface,enum,annotation,primitive type,void)java。lang。Class对象获取方式
获取到对象后,下面利用反射里面的Api
java.lang.reflect
做些事情
应用反射的API 获取类的信息(包的名字 类的名字 属性 方法  构造方法等)
 package com.bjsxt.reflection.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* 应用反射的API 获取类的信息(类的名字 属性 方法 构造方法等)
* @author Administrator
*
*/
public class Demo02 {
public static void main(String[] args) {
String path
= "com.bjsxt.reflection.test.bean.User";
try {
Class clazz
= Class.forName(path);

//获取包名+类名
System.out.println(clazz.getName());
// 获得类名 User
System.out.println(clazz.getSimpleName());
//获取属性信息
//引入import java.lang.reflect.Field;
Field[] fields = clazz.getFields();//返回所有属性 public的属性 如何是别的 获取不到
System.out.println(fields.length);//0
Field[] fields1 = clazz.getDeclaredFields();//获得所有的属性 不管你的访问修饰符是什么
System.out.println(fields.length);//3
for(Field temp:fields){
System.
out.println("属性"+temp);
}
// Field f1 = clazz.getDeclaredField("id");
// Field f2 = clazz.getDeclaredField("age");
// Field f3 = clazz.getDeclaredField("uname");

//获得 方法信息
Method[] method = clazz.getDeclaredMethods();
Method m
=clazz.getDeclaredMethod("getUname", null);
Method m2
= clazz.getDeclaredMethod("setUname", String.class);
//获得构造放方法的信息
Constructor[]constructors = clazz.getDeclaredConstructors();// 获得所有构造器
Constructor c= clazz.getDeclaredConstructor(null);// 获得无参构造器
Constructor c1= clazz.getDeclaredConstructor(int.class,int.class,String.class);
//获得参数列表类型是int int String 方法的构造器

}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}

}

 动态调用 获取到的 类的信息 (属性 方法 构造器)

 

package com.bjsxt.reflection.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.bjsxt.reflection.test.bean.User;

public class Demo03 {
public static void main(String[] args) {
String path
= "com.bjsxt.reflection.test.bean.User";
try {
Class
<User> clazz = (Class<User>)Class.forName(path);
// 通过反射api调用构造方法 构造对象
User u = clazz.newInstance(); //调用了 User的无参构造方法
System.out.println(u);
//调用有参构造器
Constructor<User>c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
User u2
= c.newInstance(1001,18,"王二");
System.
out.println(u2.getUname());

//通过反射api调用普通方法
User u3 = clazz.newInstance();
Method method
=clazz.getDeclaredMethod("setUname", String.class);
method.invoke(u3,
"张三");//25 26 行代码 相等于 u3.setUname("张三");

System.
out.println(u3.getUname());

// 通过反射api调用属性
User u4 = clazz.newInstance();
Field f
= clazz.getDeclaredField("uname");
f.setAccessible(
true);//这个属性不用做安全检查了 可以直接访问 否则会报错 说不能访问私有属性
f.set(u4, "李四");//通过反射直接写属性的值
System.out.println(u4.getUname());//通过反射直接读属性的值
System.out.println(f.get(u4));//通过反射读属性


}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (SecurityException e) {
// TODO Auto-generated catch block
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}




}
}

反射机制的性能问题

使用setAccessible提高性能(setAccessible是启用/禁用访问安全的开关)

f.setAccessible(true);// 禁用安全检查 这个属性不用做安全检查了 可以直接访问  否则会报错 说不能访问私有属性

效率提高4倍 

 

反射操作注解(annotation)

反正操作泛型(Generic)

java采用泛型擦除的机制来引入泛型,也就是说,泛型仅仅是给编译器javac看的,来确保数据的安全性和免去数据类型转换,但是,一旦编译完成,所有和泛型相关的东西都被擦除,这一点也可以从类编译的class文件反编译看到。   为了用反射操作泛型 Java就新增了几种类型来代表不能被归一到Class类中的类型,但又和基本数据类型齐名的类型,通常使用的是前两个:
  • ParameterizedType:表示一种参数化的类型,比如Collection< String >
  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable:是各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式,比如?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)

 

package com.bjsxt.reflection.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.bjsxt.reflection.test.bean.User;

public class Demo04 {
//参数类型有泛型
public void test01(Map<String,User>map,List<User>list){
System.
out.println("Demo04.test01()");
}
// 无参 但是有返回值类型 泛型
public Map<Integer,User> test02(){
System.
out.println("Demo04.test02()");
return null;
}
//通过程序读取到 参数的泛型 和 返回值的泛型
public static void main(String[] args) {
try {
//Demo04.class获得Demo04这个类的一个对象
//Demo04.class.getMethod("test01",Map.class,List.class);获得这个类的test01方法Method m这个对象
Method m = Demo04.class.getMethod("test01",Map.class,List.class);
// m.getGenericParameterTypes();获得带泛型参数类型
Type[]t = m.getGenericParameterTypes();
for(Type paramType:t){
System.
out.println("#"+paramType);
//判断是否参数类型是带有泛型
if(paramType instanceof ParameterizedType ){
//强制转换成带泛型的参数类型((ParameterizedType) paramType)
//.getActualTypeArguments();获得真正的带泛型参数类型
Type[]gernericTypes=((ParameterizedType) paramType).getActualTypeArguments();
for(Type genericType:gernericTypes){
System.
out.println("泛型类型"+genericType);

}
}
}
}
catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#java.util.Map<java.lang.String, com.bjsxt.reflection.test.bean.User>
泛型类型class java.lang.String
泛型类型class com.bjsxt.reflection.test.bean.User
#java.util.List
<com.bjsxt.reflection.test.bean.User>
泛型类型class com.bjsxt.reflection.test.bean.User