Java反射
反射可以通过对象获得该对象的类,并通过类获得该类的包名
Class c= Class.forName("包名.类名")
Class 本身也是一个类,但是只能由系统创建。
一个加载的类在JVM中只会有一个Class实例
一个Class对象对应一个class文件
每个类的实例都会记得自己是由那个Class实例所生成的
通过Class可以完整的得到一个类中的所有被加载的结构
Class类时Reflection的根源,针对想获得动态加载、运行的类,唯有先获得相应的Class对象
反射相关的主要API
-
Class
-
Method
-
Field
-
Constructor
如何获得Class 类的实例?
-
Class class =Person.class//直接通过类的class属性获得
-
Class class = person.getClass();//直接通过类的实例获得
-
Class class = Class.forName("包名.类名")//通过Class类的静态方法forName()获取可能抛出一个异常
-
内置基本数据类型可以直接用类名
Class class =Integer.TYPE
-
Class class =class.getSuperclass()//获得父类的类型
-
还可以利用ClassLoader获取Class
有哪些类型可以有Class对象
-
所有的类都有Class对象
-
interface
-
数组[]
-
enum枚举
-
annotation注解
-
primitive type 基本数据类型
-
void
Java内存分析(理解Class)
堆存放new的对象和数组
栈存放基本变量类型和引用对象的变量
方法区存放所有的class和static变量
类加载的过程
-
加载Load
将类的calss文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
-
类的链接Link
将类的二进制数据合并到JRE中,所有的static和常量和默认初始值,都在这个阶段已经完成
-
类的初始化Initialize
JVM负责对类进行初始化,clinit()方法
什么时候会发生类的初始化?
主动引用的时候会发生类的初始化
主动引用包括:
-
虚拟机启动时,初始化main方法所在的类;
-
new一个类的对象;
-
调用静态成员(除了final)和方法;
-
使用reflect包反射调用;
-
子类初始化会先初始化父类。
类的被动引用不会初始化。包括:
-
通过数组定义类引用,不会触发初始化,因为只是声明空间但是没有指向具体对象所以没有触发类的初始化;
-
引用常量不会触发;
-
访问一个静态域时,只有真正声明这个域的类才会被初始化。如通过子类引用父类的静态变量,不会导致子类的初始化,因为父类的静态变量已经事先初始化好了。
类加载器
-
引导类加载器
JVM自带的,负责Java平台核心库(rt.jar),该加载器无法直接获取
-
扩展类加载器
负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
-
系统类加载器
负责java-classpath或-D java.class.path所指的目录下的类,与jar包装入工作,是最常用的加载器
系统类加载器实例:
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();//系统类加载器 ClassLoader parent =systemClassLoader.getParent();//获取扩展类加载器 Class.forName("com.sdds.xxx").getClassLoader();
双亲委派机制
如果用户自定义了一个String包,那么一定是在系统类加载器的范围内。java会自动搜索扩展类加载器或者引导类加载器内是否存在String包,如果存在,则自定义包String失效。
Class类的方法
class.getName();//获得包名和类名 class.getSimpleName();//获得类名 class.getFields();//获得类的public属性 class.getDeclaredFields();//得到类的全部属性 class.getMethods();//获得正常的public method包括继承的方法 class.getDeclaredMethods();//获得本类的所有方法 Method w=class.getMethod("方法名",参数类型.class...);//获取指定的方法 Constructor[] cons= class.getConstructors();//获得public的构造器 Constructor con = class.getConstructor();//获得本类的全部方法包括private class.getDeclaredConstructor(参数类型.class....); User u = (User) class.newInstance();//构造类的对象,调用了类的无参构造器 Construct constructor =class.getDeclaredConstructor(String.class); User user2 =(User)constructor.newInstance("张三");//获取有参数的构造函数 Method setName = class.getDeclaredMethod("setName",String.class); setName.invoke(传递的对象,传递的值);//这样就能使用函数了 Field name = class.getDeclaredField("name");//获得指定的属性名(私有) name.setAccessible(true);//打开修改权限,私有的方法可以直接执行 name.set(指定的对象,指定的值);//修改指定对象的属性为指定的值
反射调用的运行速度比较慢(和正常调用比较)。
反射操作泛型
首先介绍四各类:
-
ParameterizedType:表示一种参数化类型如List<String>
-
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
-
TypeVariable:是各种类型变量的公共父接口
-
WildcardType:代表一种通配符类型表达式
例子:
public class Test{ public void test(Map<String,User> map,List<User> list){ sout(test); } public static coid main(String[] args) throws NoSuchMethodException { Method method =Test.class.getMethod("test",Map.class,List.class); Type[] genericParameterTypes =method.getGenericParameterTypes(); //此时该变量成员有两个即java.util.Map<....>和java.util.List<...> for(Type genericParameterType : genericParameterTypes){ if(genericParameterType instanceof ParameterizedType){ ((ParameterizedType)genericParameterType).getActualTypeArguments();// //此时改成员变量有两个一个为String,一个为User 第二个循环该变量有一个为User } } } }
反射获取注解
ORM(object relationship mapping)
即每new出来一个对象,对应于数据库中表的一行,对象的每一个属性对应着数据库表的一列
因此,可以通过注解和反射完成类和表的结构的映射关系
实例
@Table1("Db_Students")//对对象注解 class Student{ @Field1(columnName="Db_Id",type="int",length=10) private int id;//对属性进行注解 @Field1(columnName="Db_Age",type="int",length=10) private int age; @Field1(columnName="Db_Name",type="varchar",length=10) private String name; } @Target(ElementType.Type)//使用范围为对象 @Retention(RetentionPolicy.Runtime)//在运行级别 @interface Table1{ String value(); } @Target(ElementType.Fiele)//使用范围为属性 @Retention(RetentionPolicy.Runtime)//在运行级别 @interface Field1{ String columnName(); String type(); int length(); } public static void main(String[] args) { Class class = Class.forName(...);//获取Class对象 Annotation[] annotations = class.getAnnotations(); for(Annotation annotation : annotations){ sout(annotation);//此时会输出外面对象的注解即@Table1(value=DbStudents) } Annotation annotation =(Annotation)class.get(Annotation(Table1.class)); String c = annotation.value(); sout(c);//此时会显示Db_Students //获得类的注解 Field f =class.getDeclaredField("name");//参数填上指定的属性名 Field1 annotation = f.getAnnotation(Field1.class); sout(annotation.type());//显示想要显示的注解属性 }