2.2.3 类加载器类加载器的浸染:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据构造,然后在堆中天生一个代表这个类的java.lan.Class工具,作为方法区中类数据的访问入口。类缓存:标准的JavaSE类加载器可以按哀求查找类,但一旦某个类被加载到类加载器中,它将坚持加载(缓存)一段韶光。不过JVM垃圾回收机制可以回收这些Class工具。
JVM规范定义了如下类型的类的加载器:勾引类加载器:用C++编写的,是JVM自带的类加载器,卖力Java平台核心库,用来装载核心类库。需把稳此库无法直接获取。扩展类加载器:卖力jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入事情库系统类加载器:卖力java -classpath或-D java.class.path所指的目录下的类与jar包装入事情,是最常用的加载器。双亲委派机制:是防止同名包、类与 jdk 中的相冲突,实际上加载类的时候,先关照 appLoader,看 appLoader 是否已经缓存,没有的话,appLoader 又委派给他的父类加载器(extLoader)讯问,看他是不是能已经缓存加载,没有的话,extLoader 又委派他的父类加载器(bootstrapLoader)讯问,BootstrapLoader看是不是自己已缓存或者能加载的,有就加载,没有再返回 extLoader,extLoader 能加载就加载,不能的话再返回给 appLoader 加载,再返回的路中,谁能加载,加载的同时也加缓存里。正是由于一直的找自己父级,以是才有 Parents 加载机制,翻译过来叫 双亲委派机制2.2.4 类的加载与ClassLoader的理解加载:将class文件字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据构造,然后天生一个代表这个类的java.lang.Class工具链接:将Java类的二进制代码合并到JVM的运行状态之中的过程验证:确保加载的类的信息符合JVM规范,没有安全方面的问题准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。解析:虚拟机常量池内的符号引用(常量名)更换为直接引用(地址)的过程初始化:实行类布局器()方法。类布局器()方法是由编译器自动网络类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类布局器是布局类信息的,不是布局该类工具的布局器)当初始化一个类的时候,如果创造其父类还没有进行初始化,则须要先触发其父类的初始化。虚拟机会担保一个类的()方法在多线程环境中被精确加锁和同步2.2.5 获取运行时类的完全构造通过反射包括如下信息:Field、Method、Constructors、Superclass、Interface、Annotation实现的全部接口所继续的父类全部的布局器全部的方法全部的Field表明···小结在实际的操作中,取得类的信息的操作代码,并不会常常开拓一定要熟习java.lang.reflect包的浸染和反射机制如何取得属性、方法、布局器的名称,润色等。2.3 动态创建工具实行方法创建类的工具:调用Class工具的newInstance()方法1)类必须有一个无参数的布局器。(无参布局器必须有)2)类的布局器的访问权限须要足够除了调用无参布局器创建工具外,也可以1)通过Class类的getDeclaredConstructor(Class...parameterTypes)取得本类的制订形参类型的布局器2)向布局器的形参中通报一个工具数组进去,里面包含告终构器中所需的各个参数3)通过Constructor实例化工具利用反射调用指定的方法通过反射,调用类中的方法,通过Method类完成。通过Class类的getMethod(String name,Class...parameterTypes)方法取得一个Method工具,并设置此方法操作时所须要的参数类型(防止涌现方法重写,利用参数类型和方法名确定详细的方法)之后利用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的方法SetAccessibleMethod和Field、Constructor工具都有setAccesible()方法。setAccessible浸染是启动和禁用访问安全检讨的开关。参数值为true则指示反射的工具在利用时应该取消Java措辞访问检讨。提高反射的效率。如果代码中必须用反射,而该句代码须要频繁被调用,那么设置为true。使得原来无法访问的私有成员也可以访问。参数值为false则指示反射的工具该当履行Java措辞访问检讨2.4 反射操作泛型Java采取泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器javac利用的,确保数据的安全性和免去逼迫类型转换的问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型ParameterizedType:表示一种参数化类型,如CollectionGenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型TypeVariable:是各种类型变量的公共父接口WildcardType:代表一种通配符类型表达式2.5 反射操作表明这部分很主要,开始和后面框架涌现结合(熟知表明对付后期框架学习很主要)放一个案例在这里解释干系功能日后将在框架学习条记中进一步阐述用反射操作表明的主要性先定义一个类表明(关注Target里面参数设置)//类名的表明@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@interface TypeTong{ String value();}
再定义一个属性的表明(须要把稳自定义的两个表明都有参数)
//属性的表明@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface FieldTong{ String colunmName(); String type(); int length();}
此后定义一个student类,用于后面的反射
@TypeTong(value = "db_student")class student2{ @FieldTong(colunmName = "db_name", type = "varchar",length = 3 ) private String name; @FieldTong(colunmName = "db_id", type = "int",length = 10 ) private int id; @FieldTong(colunmName = "db_age", type = "int",length = 10 ) private int age; public student2() { } public student2(String name, int id, int age) { this.name = name; this.id = id; this.age = age; } public String getName() { return name; } public void setName(String name) { 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; } @Override public String toString() { return "student2{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; }}
main函数体例
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class s1 = Class.forName("AnnotationandReflection.Demo03.student2"); //通过反射得到表明 Annotation[] annotations = s1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //通过反射得到指定表明属性值 System.out.println("=========================="); TypeTong typeTong = (TypeTong)s1.getAnnotation(TypeTong.class); String value = typeTong.value(); System.out.println(value); //得到类指定的表明 System.out.println("=========================="); Field f = s1.getDeclaredField("id"); FieldTong annotation = f.getAnnotation(FieldTong.class); System.out.println(annotation.colunmName()); System.out.println(annotation.type()); System.out.println(annotation.length()); }
程序运行后结果如下:
