- 概念:
指的是可以在运行时加载、探知、使用编译期间完全未知的类。程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类都可以知道该类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。
加载类完成后,在堆内存中,产生一个class类型的对象(一个类只有一个class对象),该对象就包括完整的类的结构信息通过该对象看到类的结构该对象如同一面镜子,透过其可看到类的结构,因此成为反射。 - 解决的问题:
由于在传统的创建对象的方法中,需要预先知道要使用的类,若要修改使用的类必须修改源码,因此使用反射机制。 - 使用:
获取类对象、操作属性、方法、构造器
1.反射获取类对象的三种方式:
Class.forName();//根据全限定路径获取
对象.getclass();//根据对象获取
类名.class();//根据类名获取
2. 反射创建类对象(实现java对象的动态创建):
Class cls=Class.forName(“类的路径”);
Object obj=cls.newInstance();//对创建的类对象进行实例化
缺点:代码效率低
Class cls=类名.class();
Class cls=new 类名.getclass();
3 .反射操作元素属性:
Class cls=Class.forName(" ");//获取类对象
Field[ ] fld=cls.getfields();//获取类及父类的公共字段
Field[ ] fld=cls.getDecloaredFields();//获取类声明的所有字段
4 .反射操作字段值:
Field fs=cls.getDeclaredField(“字段名”);
fs.set(null,200);//操作静态属性
Field fd=cls.getDeclaredField(“字段名”);
Obejct obj=cls.newInstance();
fd.set(obj,“字段内容”);//操作非静态属性
5 .反射操作方法:
获取类对象
获取方法对象
getMethods();//获取所有的公共方法
getDeclearedMethods();//获取所有声明的方法
getMethod(String name,class cls);//获取指定的公共方法
getDeclearedMethod(String name,class cls);//获取指定声明的方法
方法对象.invoke(null,参数值1,参数值2,…);//静态方法
oject obj=cls.newInstance();
方法对象.invoke(obj,参数值1,参数值2,…);
方法对象.invoke(obj,null);
public class Demo01 {
public static void main(String[] args) {
String path = "com.bjsxt.test.bean.User";
try {
Class clazz = Class.forName(path);
//对象是表示或封装一些数据。 一个类被加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会放到对应的Class对象中。
//这个Class对象就像一面镜子一样,通过这面镜子我可以看到对应类的全部信息。
System.out.println(clazz.hashCode());
Class clazz2 = Class.forName(path); //一个类只对应一个Class对象
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][3];
int[] arr03 = new int[30];
double[] arr04 = new double[10];
System.out.println(arr01.getClass().hashCode());
System.out.println(arr02.getClass().hashCode());
System.out.println(arr03.getClass().hashCode());
System.out.println(arr04.getClass().hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 反射机制性能问题:
setAccessible:应用和禁用访问安全检查的开关,true指示反射的对象在使用时应取消java访问检查,禁止安全检查,可提高反射的运行速度。
public class Demo06 {
public static void test01(){
User u = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
u.getUname();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法调用,执行10亿次,耗时:"+(endTime-startTime)+"ms");
}
public static void test02() throws Exception{
User u = new User();
Class clazz = u.getClass();
Method m = clazz.getDeclaredMethod("getUname", null);
// m.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
m.invoke(u, null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射动态方法调用,执行10亿次,耗时:"+(endTime-startTime)+"ms");
}
public static void test03() throws Exception{
User u = new User();
Class clazz = u.getClass();
Method m = clazz.getDeclaredMethod("getUname", null);
m.setAccessible(true); //不需要执行访问安全检查
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000L; i++) {
m.invoke(u, null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射动态方法调用,跳过安全检查,执行10亿次,耗时:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws Exception {
test01();
test02();
test03();
}
}
-
Class类介绍:
java.lang.Class类用来表示java中类型本身。
Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个Class对象。当一个class被加载,或当加载器的defineClass()被JVM调用,JVM自动产生一个Class对象。
Class类是反射的根源 -
反射操作泛型:
java采用泛型擦除机制引入泛型,java中的泛型只是给编译器使用的,确保数据的安全性和免去强制类型转换的麻烦。但是一旦编译完成,所有的和泛型有关的类型全部擦除。
为通过反射操作这些类型,java新增ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型代表不能被归一到Class类中的类型又和原始类型齐名的类型。
• ameterizedType: 表示一种参数化的类型,比如Collection
• GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
• TypeVariable: 是各种类型变量的公共父接口
• WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? super Integer【 wildcard是一个单词:就是“通配符”】
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 {
//获得指定方法参数泛型信息
Method m = Demo04.class.getMethod("test01", Map.class,List.class);
Type[] t = m.getGenericParameterTypes();
for (Type paramType : t) {
System.out.println("#"+paramType);
if(paramType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("泛型类型:"+genericType);
}
}
}
//获得指定方法返回值泛型信息
Method m2 = Demo04.class.getMethod("test02", null);
Type returnType = m2.getGenericReturnType();
if(returnType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型类型:"+genericType);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 反射操作注解
可以通过反射API:getAnnotations,getAnnotation获得相关注解信息。
public class Demo05 {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.bjsxt.test.annotation.SxtStudent");
//获得类的所有有效注解
Annotation[] annotations=clazz.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
//获得类的指定的注解
SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable.class);
System.out.println(st.value());
//获得类的属性的注解
Field f = clazz.getDeclaredField("studentName");
SxtField sxtField = f.getAnnotation(SxtField.class);
System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());
//根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表
} catch (Exception e) {
e.printStackTrace();
}
}
}