1. Class类
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了那些接口。
对于每个类而言,JRE都为其保留了一个不变Class类型的对象。
一个Class对象包含了特定于某个结构(class/interface/enum/annotation/primitive type/void/[])有关信息
- Class本身也是一个类
- Class对象只能由系统建立对象
- 一个加载的类在JVM中只有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由那个Class实例所生成
- 通过Class可以完整的得到一个类中的所有被加载的结构
- Class类时Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
1.1Class类的常用方法
static ClassforName(String name):返回指定类名name的Class对象 Object newInstance():调用缺省构造函数,返回Class对象的一个实例 getName():返回次Class对象所表示的实体(类,接口,数组类或void)的名称 Class getSuperClass():返回当前Class对象的父类的Class对象 ClassLoader getClassLoader():返回该类的类加载器 Constructor[] getConstructors():返回一个包含某些Constructor对象的数组 Method getMethod(String name,Class.. T):返回一个Method对象,此对象的形参类型为paramType Field[] getDeclaredFields():返回Field对象的一个数组
1.2获取Class类的实例
- 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz=Person.class;
- 已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz=person.getClass();
- 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz=Class.forName("demo-1.Student");
- 内置基本数据类型可以直接用类名.Type获取
- 还可以利用Class Loader获取
1.3哪些类型可以有Class对象
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- interface:接口
- []:数组
- enum:枚举
- annotation:注解@interface
- primitive:基本数据类型
- void
案例代码如下:package snow.dong.reflection; import java.lang.annotation.ElementType; //所有类型的Class public class TestClass { public static void main(String[] args) { Class c1=Object.class;//类 Class c2=Comparable.class;//接口 Class c3=String[].class;//一维数组 Class c4=int[][].class;//二维数组 Class c5=Override.class;//注解 Class c6= ElementType.class;//枚举 Class c7=Integer.class;//基本数据类型 Class c8=void.class;//void Class c9=Class.class;//Class //打印信息 System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //只要元素类型与维度一样,就是同一个class int[] a=new int[10]; int[] b=new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } } #结果如下: class java.lang.Object interface java.lang.Comparable class [Ljava.lang.String; class [[I interface java.lang.Override class java.lang.annotation.ElementType class java.lang.Integer void class java.lang.Class 460141958 460141958
2.获取运行时类的完整结构
2.1 通过反射获取运行时类的完整结构
- 能够获得filed、Method、Constructor,SuperClass,Interface,Annotation
2.2 有Class对象,能做什么
- 创建类的对象:调用Class对象的newInstance()方法
- 1类必须有一个无参数的构造器
- 2类的构造器的访问权限需要足够
但是,只要在操作的时候明确调用类中的构造器,并将参数传递进去,才可以实例化对象 - 1通过Class类的getDeclaredconstructor(Class... patameterType)取得本类的指定形参类型的构造器。
- 2向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
- 3通过Constructor实例化对象
- 调用指定的方法(调用类中的方法,通过Method类来完成)
- 1通过Class类的getMethod(String name,Class...parameterTypes)方法获取一个Method对象,并设置此方法操作所需要的的参数类型。
- 2之后使用Object invoke(Object obj,Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息
- Object invoke(Object obj,Object...args)
- Object对应着原方法的返回值,若原方法没有返回值,返回null
- 若原方法为静态方法,此时形参Object obj 可为null
- 若原方法形参列表为空,则Object[] args为null
- 若原方法声明为private,则需要在调用次invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private方法
- setAccessible
- Method 和Filed,Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁用安全检查的开关
- 参数为true则指示反射的对象在使用时应该取消Java语言的访问检查
- 提高反射的效率。如果代码中必须用到反射,而该句代码需要频繁的被调用,那么请设置为true
- 使得原本无法访问的私有成员也可以访问
- 设置为false则指示反射的对象应该实施Java语言访问检查
package snow.dong.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestReflection { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //获得Class对象 Class c1=Class.forName("snow.dong.reflection.User"); //构造一个对象 User user=(User)c1.newInstance();//本质上调用了类的无参构造器 System.out.println(user); System.out.println("----通过构造器创建对象----"); Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,String.class); User user1=(User)constructor.newInstance("snowdong",18,"man"); System.out.println(user1); System.out.println("----通过反射调用普通方法----"); Method setName=c1.getDeclaredMethod("setName",String.class); //invoke:激活 //(对象,"方法的值") setName.invoke(user,"snowDong01"); System.out.println(user.getName()); System.out.println("----通过反射操作属性----"); Field gender=c1.getDeclaredField("gender"); //不能直接操作私有属性,需关闭程序的安全检测,如下 gender.setAccessible(true); gender.set(user,"不男不女"); System.out.println(user.getGender()); } } #//运行结果如下: #User{name='null', age=0, gender='null'} #----通过构造器创建对象---- #User{name='snowdong', age=18, gender='man'} #----通过反射调用普通方法---- #snowDong01 #----通过反射操作属性---- #不男不女
2.3反射操作泛型
- Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除。
- 为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
- ParameterizedType:表示一种参数化类型,比如Collection
- GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable:是各种类型变量的公共父接口
- WildcardType:代表一种通配符类型表达式
具体案例代码说明:package snow.dong.reflection; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class TestGenericType { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method=TestGenericType.class.getDeclaredMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("#--------"+genericParameterType); if(genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } method=TestGenericType.class.getDeclaredMethod("test02", null); Type genericReturnType = method.getGenericReturnType(); System.out.println("#--------"+genericReturnType); if(genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } } #//返回结果 #--------java.util.Map<java.lang.String, snow.dong.reflection.User> class java.lang.String class snow.dong.reflection.User #--------java.util.List<snow.dong.reflection.User> class snow.dong.reflection.User #--------java.util.Map<java.lang.String, snow.dong.reflection.User> class java.lang.String class snow.dong.reflection.User
2.4反射操作注解
利用注解和反射完成类和表结构的映射关系,代码如下:
package snow.dong.reflection; import java.lang.annotation.*; import java.lang.reflect.Field; public class TestAnnotation { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1=Class.forName("snow.dong.reflection.Student"); //通过反射获得注解 Annotation[] annotations=c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value值 Tabledong tabledong= (Tabledong) c1.getAnnotation(Tabledong.class); String value=tabledong.value(); System.out.println(value); //获得类指定的注解 Field f=c1.getDeclaredField("name"); Fileddong fileddong=f.getAnnotation(Fileddong.class); System.out.println(fileddong.columnName()); System.out.println(fileddong.type()); System.out.println(fileddong.length()); } } @Tabledong("db_student") class Student{ @Fileddong(columnName = "db_id",type = "int",length = 10) private int id; @Fileddong(columnName = "db_age",type = "int",length = 10) private int age; @Fileddong(columnName = "db_name",type = "varchar",length = 3) private String name; public Student() { } public Student(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } 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 getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //类名的注解 @Target(ElementType.TYPE)//表示在类上面的注解 @Retention(RetentionPolicy.RUNTIME) @interface Tabledong{ String value(); } //属性的注解 @Target(ElementType.FIELD)//表示在类上面的注解 @Retention(RetentionPolicy.RUNTIME) @interface Fileddong{ String columnName(); String type(); int length(); } #//运行结果 @snow.dong.reflection.Tabledong(value=db_student) db_student db_name varchar 3