java注解与反射--3
类的加载与ClassLoader
java内存
- 堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会存放别的对象引用
- 栈
- 方法区
- 可以被所有线程共享
- 包含了所有的class和static变量
类的加载过程 1->2->3
- 类的加载(load):将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
- 类的链接(Link):将类的二进制数据合并到 JRE中。
- 类的初始化(Initialize):JVM负责对类进行初始化。
| package com.ssl.demo02; |
| |
| |
| public class Test05 { |
| public static void main(String[] args) { |
| A a = new A(); |
| System.out.println(A.m); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| } |
| |
| class A{ |
| static { |
| System.out.println("A类静态代码块初始化"); |
| m=300; |
| } |
| static int m = 100; |
| |
| public A() { |
| System.out.println("A类的无参构造初始化"); |
| } |
| } |
什么时候发生类的初始化
- 类的主动引用(一定会发生类的初始话)
- 当虚拟机启动,先初始化main方法所在的类
- new 一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则先会出初始化它的父类
- 类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化。
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化。
| package com.ssl.demo02; |
| |
| |
| public class Test06 { |
| static { |
| System.out.println("Main类被加载"); |
| } |
| public static void main(String[] args) throws Exception{ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| System.out.println(Son.M); |
| |
| |
| |
| |
| } |
| } |
| |
| class Father{ |
| |
| static int b = 2; |
| |
| static { |
| System.out.println("父类被加载"); |
| } |
| } |
| |
| class Son extends Father{ |
| |
| static { |
| System.out.println("子类被加载"); |
| m=300; |
| } |
| |
| static int m = 100; |
| |
| static final int M = 1; |
| } |
类加载器的作用 ClassLoader
- 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
- 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
过程:源文件(.java)->java编译器->字节码(.class)->类装载器->字节码校验器->解释器->操作系统平台**
| package com.ssl.demo02; |
| |
| public class Test07 { |
| public static void main(String[] args) throws Exception{ |
| |
| |
| ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); |
| System.out.println(systemClassLoader); |
| |
| |
| ClassLoader parent = systemClassLoader.getParent(); |
| System.out.println(parent); |
| |
| |
| ClassLoader parent1 = parent.getParent(); |
| System.out.println(parent1); |
| |
| |
| |
| |
| |
| |
| |
| |
| ClassLoader aClass = Class.forName("com.ssl.demo02.Test07").getClassLoader(); |
| System.out.println(aClass); |
| |
| |
| aClass = Class.forName("java.lang.Object").getClassLoader(); |
| System.out.println(aClass); |
| |
| |
| |
| |
| |
| |
| System.out.println(System.getProperty("java.class.path")); |
| |
| |
| } |
| } |
创建运行时类的对象
获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field(字段)、Method、Constructor、Superclass、Interface、Annotation
| package com.ssl.demo02; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| |
| public class Test08 { |
| public static void main(String[] args) throws Exception{ |
| Class c1 = Class.forName("com.ssl.demo02.User"); |
| |
| |
| System.out.println(c1.getName()); |
| System.out.println(c1.getSimpleName()); |
| |
| |
| Field[] fields = c1.getFields(); |
| fields = c1.getDeclaredFields(); |
| for(Field field:fields){ |
| System.out.println(field); |
| } |
| |
| |
| Field name = c1.getDeclaredField("name"); |
| System.out.println(name); |
| |
| System.out.println("================================="); |
| |
| Method[] methods = c1.getMethods(); |
| for(Method method:methods){ |
| System.out.println("正常的"+method); |
| } |
| methods = c1.getDeclaredMethods(); |
| for(Method method:methods){ |
| System.out.println("getDeclaredMethods"+method); |
| } |
| |
| |
| |
| Method getname = c1.getMethod("getName",null); |
| Method setname = c1.getMethod("setName",String.class); |
| System.out.println(getname); |
| System.out.println(setname); |
| |
| System.out.println("================================="); |
| |
| Constructor[] constructors = c1.getConstructors(); |
| for(Constructor constructor:constructors){ |
| System.out.println(constructor); |
| } |
| constructors = c1.getDeclaredConstructors(); |
| for(Constructor constructor:constructors){ |
| System.out.println("getDeclaredConstructors"+constructor); |
| } |
| |
| Constructor constructor = c1.getConstructor(String.class, int.class, int.class); |
| System.out.println(constructor); |
| } |
| } |
小结:
- 在实际的操作中,取得类的信息的操作代码,并不会经常开发。
- 一定要熟悉java.lang.reflect包的作用,反射机制。
- 如何取得属性、方法、构造器的名称,修饰符等。
调用运行时类的指定结构
动态创建对象执行方法
| package com.ssl.demo02; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| |
| public class Test09 { |
| public static void main(String[] args) throws Exception { |
| |
| Class c1 = Class.forName("com.ssl.demo02.User"); |
| |
| |
| User user = (User) c1.newInstance(); |
| System.out.println(user); |
| |
| |
| Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); |
| User ssl = (User)declaredConstructor.newInstance("ssl", 1, 18); |
| System.out.println(ssl); |
| |
| |
| User user3 = (User)c1.newInstance(); |
| |
| Method setName = c1.getDeclaredMethod("setName", String.class); |
| |
| setName.invoke(user3,"kk"); |
| System.out.println(user3); |
| |
| |
| User user4 = (User)c1.newInstance(); |
| |
| Field name = c1.getDeclaredField("name"); |
| |
| |
| name.setAccessible(true); |
| name.set(user4,"ssl2"); |
| System.out.println(user4); |
| |
| } |
| } |
分析性能问题
| package com.ssl.demo02; |
| |
| import java.lang.reflect.Method; |
| |
| |
| public class Test10 { |
| |
| |
| public static void test01(){ |
| User user = new User(); |
| long startTime = System.currentTimeMillis(); |
| |
| for (int i = 0; i < 10_0000_0000; i++) { |
| user.getName(); |
| } |
| |
| long endTime = System.currentTimeMillis(); |
| System.out.println("普通方法执行10亿次:"+(endTime-startTime)+"ms"); |
| } |
| |
| |
| public static void test02()throws Exception{ |
| User user = new User(); |
| Class c1 = user.getClass(); |
| |
| Method getName = c1.getDeclaredMethod("getName", null); |
| |
| long startTime = System.currentTimeMillis(); |
| |
| for (int i = 0; i < 10_0000_0000; i++) { |
| getName.invoke(user,null); |
| } |
| |
| long endTime = System.currentTimeMillis(); |
| System.out.println("反射方式执行10亿次:"+(endTime-startTime)+"ms"); |
| } |
| |
| |
| public static void test03()throws Exception{ |
| User user = new User(); |
| Class c1 = user.getClass(); |
| |
| Method getName = c1.getDeclaredMethod("getName", null); |
| getName.setAccessible(true); |
| |
| long startTime = System.currentTimeMillis(); |
| |
| for (int i = 0; i < 10_0000_0000; i++) { |
| getName.invoke(user,null); |
| } |
| |
| long endTime = System.currentTimeMillis(); |
| System.out.println("setAccessible执行10亿次:"+(endTime-startTime)+"ms"); |
| } |
| |
| public static void main(String[] args) throws Exception{ |
| test01(); |
| test02(); |
| test03(); |
| |
| |
| |
| |
| |
| } |
| |
| } |
反射操作泛型
- Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题﹐但是,一旦编译完成﹐所有和泛型有关的类型全部擦除
- 为了通过反射操作这些类型,Java新增了ParameterizedType , GenericArrayType ,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型.
- ParameterizedType :表示一种参数化类型,比如Collection
- GenericArrayType :表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable:是各种类型变量的公共父接口
- WildcardType:代表一种通配符类型表达式
| package com.ssl.demo02; |
| |
| 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 Test11 { |
| |
| 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 Exception{ |
| Method method = Test11.class.getMethod("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(); |
| System.out.println(actualTypeArguments); |
| } |
| } |
| |
| |
| method = Test11.class.getMethod("test02", null); |
| Type genericReturnType = method.getGenericReturnType(); |
| if(genericReturnType instanceof ParameterizedType){ |
| Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); |
| for(Type actualTypeArgument:actualTypeArguments){ |
| System.out.println(actualTypeArgument); |
| } |
| } |
| } |
| } |
获取注解信息
- getAnnotations
- getAnnotation
练习:ORM
ORM:Object relationship Mapping --> 对象关系映射
利用注解和反射完成类和表结构的映射关系。
| package com.ssl.demo02; |
| |
| import java.lang.annotation.*; |
| import java.lang.reflect.Field; |
| |
| |
| public class Test12 { |
| public static void main(String[] args)throws Exception{ |
| |
| Class c1 = Class.forName("com.ssl.demo02.Student2"); |
| |
| |
| Annotation[] annotations = c1.getAnnotations(); |
| for(Annotation annotation:annotations){ |
| System.out.println(annotation); |
| } |
| |
| |
| Table1 table1 = (Table1)c1.getAnnotation(Table1.class); |
| String value = table1.value(); |
| System.out.println(value); |
| |
| |
| Field f = c1.getDeclaredField("name"); |
| Field1 annotation = f.getAnnotation(Field1.class); |
| System.out.println(annotation.columnName()); |
| System.out.println(annotation.type()); |
| System.out.println(annotation.length()); |
| |
| } |
| |
| } |
| @Table1("db_student") |
| class Student2{ |
| @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 = 3) |
| private String name; |
| |
| public Student2() { |
| } |
| |
| public Student2(int id, int age, String name) { |
| this.id = id; |
| this.age = age; |
| this.name = name; |
| } |
| |
| public int getId() { |
| return id; |
| } |
| |
| public int getAge() { |
| return age; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public void setId(int id) { |
| this.id = id; |
| } |
| |
| public void setAge(int age) { |
| this.age = age; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| } |
| |
| |
| |
| @Target(ElementType.TYPE) |
| @Retention(RetentionPolicy.RUNTIME) |
| @interface Table1{ |
| String value(); |
| } |
| |
| |
| @Target(ElementType.FIELD) |
| @Retention(RetentionPolicy.RUNTIME) |
| @interface Field1{ |
| String columnName(); |
| String type(); |
| int length(); |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端