跟着狂神学注解&反射

it2025-07-20  3

跟着狂神学注解&反射

注解

什么是注释

内置注释

@Override//重写注解 @Deprecated//不推荐使用注解,可以使用但是又风险或者有更好的方式 @SuppressWarnings//“镇压”警告注解

元注解

案例

import java.lang.annotation.*; public class annotion01 { public void test(){ } } //自定义注解 //@Target、@Retention是在自定义注解时必须使用的两个注解 //@Retention表示注解的生命周期、@Target表示注解可以声明在什么地方 //ElementType.TYPE表示注解可以声明在类上 //ElementType.METHOD表示注解可以声明在方法上 @Target(value = {ElementType.METHOD/*方法*/}) @Retention(RetentionPolicy.RUNTIME) @Documented //表示把注解生成在Javadoc中 @Inherited //表示可以被继承 @interface MyAnnotation{ }

ElementType 取值及含义

public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }

自定义注解

如果自定义注解中参数是value,则使用注解时可以省略‘value=‘,当且仅当是value时才可以省略。如果是其他参数名,则不可以省略,见下:

package com.huang.annotion_reflection; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class annotation02 { //注解可以显示赋值,也可以使用默认赋值 @MyAnnotation2(name = "xxx") public void test01(){} @MyAnnotation3("xxx") public void test02(){} } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ //注解的参数:参数类型+参数名(); String name() default ""; int id() default -1;//默认值为-1代表不存在 } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ //注解的参数:参数类型+参数名(); String value(); }

反射机制

静态VS动态语言

Java Reflection

java反射机制及其研究

java 反射优点和缺点

反射相关的主要的API

package com.huang.annotation_reflection; public class reflection01 { public static void main(String[] args)throws Exception { Class<?> c1 = Class.forName("com.huang.annotation_reflection.User"); System.out.println(c1); //一个类在内存中只有一个Class对象 //一个类被加载后整个结构都会被封装在Class对象中 System.out.println(Class.forName("com.huang.annotation_reflection.User")); System.out.println(Class.forName("com.huang.annotation_reflection.User")); System.out.println(Class.forName("com.huang.annotation_reflection.User")); } } //实体类 class User{ private String name; private int id; private int age; public User() { } public User(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; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } public void setAge(int age) { this.age = age; } }

运行结果:

class com.huang.annotation_reflection.User class com.huang.annotation_reflection.User class com.huang.annotation_reflection.User class com.huang.annotation_reflection.User

Class类

Class类的常用方法

获取Class类的实例

案例

package com.huang.annotation_reflection; public class reflection02 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); //方式一:通过对象获得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式二: forName 获得 Class c2 = Class.forName("com.huang.annotation_reflection.Student"); System.out.println(c2.hashCode()); //方式三:通过类名.class获得 Class c3 = Student.class; System.out.println(c3.hashCode()); //方式四:基本内置类型的包装类都有一个Type属性 Class c4 = Integer . TYPE; System.out .println(c4); //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person { String name; public Person() { } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person { public Student() { this.name = "学生"; } } class Teacher extends Person { public Teacher() { this.name = "老师"; } }

运行截图

1163157884 1163157884 1163157884 int class com.huang.annotation_reflection.Person

哪些类型可以有Class对象

案例

package com.huang.annotation_reflection; import java.lang.annotation.ElementType; public class reflection03 { 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 1163157884 1163157884

Java内存分析

了解:类的加载过程

类的加载与Classloader的理解

package com.huang.annotation_reflection; public class reflection04 { public static void main(String[] args) { A a = new A(); System.out.println(a.m); /* 1.加获到内存,会产生一个类对应Class对象 2.链接,链接结束后m=0 3.初始化 <clinit>(){ System.out.println("静态代码块初始化"); m = 300; m = 100; } m=100 */ } } class A { static { System.out.println("静态代码块初始化"); m = 300; } static int m = 100; public A() { System.out.println("无参构造初始化"); } }

执行结果

静态代码块初始化 无参构造初始化 100 首先是准备阶段,静态代码块并没有执行,m给予了默认值0,然后初始化的时候从上到下执行,m被赋予=300,然后又=100

什么时候会发生类初始化

代码

package com.huang.annotation_reflection; //类什么时候会被初始化 public class reflection05 { static{ System.out.println("Main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { //1、主动引用:new一个对象(会发生类的初始化) Son son = new Son(); //2、主动引用:反射 (会发生类的初始化) Class c1 = Class.forName("com.huang.annotation_reflection"); //不会产生类的引用的方法,因为是子类调用父类的static常量 //在这里父类会被初始化,但是子类不会被初始化 System.out.println(Son.b); //数组只开辟了空间,也被命名了,但是没有加载任何类,不会发生类的初始化 Son[] array = new Son[5]; //常量,静态变量在链接阶段就被赋值并且调用到了常量池中了,所以调用时不会发生类的初始化 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; }

类加载器的作用

代码

package com.huang.annotation_reflection; public class reflection06 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类加载器 ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println(classLoader); //获取系统类加载器的父类加载器 --> 扩展类加载器 ClassLoader parent = classLoader.getParent(); System.out.println(parent); //无法扩展类加载器的父类 --> 引导类加载器 //测试当前类是哪个加载器加载的(系统类加载器,也就是App加载器) ClassLoader classLoader1 = Class.forName("com.huang.annotation_reflection.reflection06").getClassLoader(); System.out.println(classLoader1); //测试Object类是哪个加载器加载的(引导类加载器) classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader); //如何获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path").replace(";",";\n")); //双亲委派机制 //自定义一个包java.lang.string --> 先推系统类加载器是否有这个包,再往上推扩展加载器有没有这个包,最后是引导类加载器— //如果发现了同样名字的包,就不会使用自定义的包 } }

运行结果

sun.misc.Launcher$AppClassLoader@18b4aac2 sun.misc.Launcher$ExtClassLoader@4554617c sun.misc.Launcher$AppClassLoader@18b4aac2 null C:\Program Files\Java\jdk1.8.0_91\jre\lib\charsets.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\deploy.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\access-bridge-64.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\dnsns.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jaccess.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\localedata.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\nashorn.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunec.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\ext\zipfs.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\javaws.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\jce.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfr.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\jfxswt.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\jsse.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\management-agent.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\plugin.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\resources.jar; C:\Program Files\Java\jdk1.8.0_91\jre\lib\rt.jar; F:\IdeaProjects\JVM_MSB\jvm_01\target\classes; F:\IDEA\set_in\IntelliJ IDEA 2019.3.2\lib\idea_rt.jar

创建运行时类的对象

获取运行时类的完整结构

package com.huang.annotation_reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //获得类的信息 public class reflection07 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { //此处在com.reflection下面有一个User类,获取Class Class<?> c1 = Class.forName("com.huang.annotation_reflection.User"); //也可以用实例去获取Class User user = new User(); c1 = user.getClass(); //获取类的名字(包名 + 类名) System.out.println("获取类的名字(包名 + 类名)"); System.out.println(c1.getName()); //获得简单名字 (类名) System.out.println("获得简单名字 (类名)"); System.out.println(c1.getSimpleName()); //获得类的属性 System.out.println("获得类的属性,只能找到public 属性"); Field[] fields = c1.getFields(); //只能找到public 属性 for (Field field : fields) { System.out.println(field); } System.out.println("可以找到全部的属性"); fields = c1.getDeclaredFields(); //可以找到全部的属性 for (Field field : fields) { System.out.println(field); } //获得指定属性的值 System.out.println("获得指定属性的值"); Field name = c1.getDeclaredField("name"); System.out.println(name); //获得类的方法,可以获得本类和父类的全部方法(不包括私有方法) System.out.println("获得类的方法,可以获得本类和父类的全部方法(不包括私有方法)"); Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println("正常的 " + method); } //获得本类的所有方法(包括私有方法) System.out.println("获得本类的所有方法(包括私有方法)"); methods = c1.getDeclaredMethods(); for (Method method : methods) { System.out.println("declaredMethods " + method); } //获得指定方法,第一个为想要获取的方法名,后面为参数类型 //重载 System.out.println("获得指定方法,第一个为想要获取的方法名,后面为参数类型"); Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); System.out.println(setName); //获得的构造器(public构造器) System.out.println("获得的构造器(public构造器)"); Constructor<?>[] constructors = c1.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } //获得全部的构造器 System.out.println("获得全部的构造器"); Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } //获得指定构造器 System.out.println("获得指定构造器"); Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor); } }

运行结果

获取类的名字(包名 + 类名) com.huang.annotation_reflection.User 获得简单名字 (类名) User 获得类的属性,只能找到public 属性 ================ 可以找到全部的属性 private java.lang.String com.huang.annotation_reflection.User.name private int com.huang.annotation_reflection.User.id private int com.huang.annotation_reflection.User.age 获得指定属性的值 private java.lang.String com.huang.annotation_reflection.User.name 获得类的方法,可以获得本类和父类的全部方法(不包括私有方法) ================ 正常的 public java.lang.String com.huang.annotation_reflection.User.toString() 正常的 public java.lang.String com.huang.annotation_reflection.User.getName() 正常的 public int com.huang.annotation_reflection.User.getId() 正常的 public void com.huang.annotation_reflection.User.setName(java.lang.String) 正常的 public void com.huang.annotation_reflection.User.setId(int) 正常的 public void com.huang.annotation_reflection.User.setAge(int) 正常的 public int com.huang.annotation_reflection.User.getAge() 正常的 public final void java.lang.Object.wait() throws java.lang.InterruptedException 正常的 public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException 正常的 public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException 正常的 public boolean java.lang.Object.equals(java.lang.Object) 正常的 public native int java.lang.Object.hashCode() 正常的 public final native java.lang.Class java.lang.Object.getClass() 正常的 public final native void java.lang.Object.notify() 正常的 public final native void java.lang.Object.notifyAll() 获得本类的所有方法(包括私有方法) declaredMethods public java.lang.String com.huang.annotation_reflection.User.toString() declaredMethods public java.lang.String com.huang.annotation_reflection.User.getName() declaredMethods public int com.huang.annotation_reflection.User.getId() declaredMethods public void com.huang.annotation_reflection.User.setName(java.lang.String) declaredMethods public void com.huang.annotation_reflection.User.setId(int) declaredMethods public void com.huang.annotation_reflection.User.setAge(int) declaredMethods public int com.huang.annotation_reflection.User.getAge() 获得指定方法,第一个为想要获取的方法名,后面为参数类型 ================ public java.lang.String com.huang.annotation_reflection.User.getName() public void com.huang.annotation_reflection.User.setName(java.lang.String) 获得的构造器(public构造器) ================ public com.huang.annotation_reflection.User() public com.huang.annotation_reflection.User(java.lang.String,int,int) 获得全部的构造器 public com.huang.annotation_reflection.User() public com.huang.annotation_reflection.User(java.lang.String,int,int) 获得指定构造器 public com.huang.annotation_reflection.User(java.lang.String,int,int) Process finished with exit code 0

小结

有了Class对象,能做什么

调用指定的方法

代码

package com.huang.annotation_reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class reflection08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { //获得Class对象 Class c1 = Class.forName("com.huang.annotation_reflection.User"); //构造一个对象(无参构造) Constructor declaredConstructor = c1.getDeclaredConstructor(); User user = (User) declaredConstructor.newInstance(); user= (User) c1.getDeclaredConstructor().newInstance(); System.out.println(user); //通过构造器创建对象 Constructor declaredConstructor1 = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 = (User) declaredConstructor1.newInstance("有参构造", 20, 21); System.out.println(user2); //通过反射调用普通方法 User user3 = (User) c1.newInstance(); Method setName = c1.getDeclaredMethod("setName", String.class); //invoke()激活这个方法,第一个参数为调用的实例,第二个为想调用方法传入的参数 setName.invoke(user3,"反射调用方法"); System.out.println(user3.getName()); //通过反射操作属性(不可直接操作私有属性) User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //由于权限不够(name属性为private),需要设置安全检测改为可以访问 //关闭权限检查可以提高程序性能 name.setAccessible(true); name.set(user4,"反射操作属性"); System.out.println(user4.getName()); } }

运行结果

User{name='null', id=0, age=0} User{name='有参构造', id=20, age=21} 反射调用方法 反射操作属性

setAccessible

反射操作泛型

代码

package com.huang.annotation_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 reflection09 { 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 = reflection09.class.getMethod("test01", Map.class, List.class); //获得参数重泛型信息 Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println(genericParameterType); System.out.println("============="); //获得真实的泛型信息 if(genericParameterType instanceof ParameterizedType){ for (Type actualTypeArgument : ((ParameterizedType) genericParameterType).getActualTypeArguments()) { System.out.println(actualTypeArgument); } } } //获得返回值泛型信息 System.out.println("--------------------------" ); Method method2 = reflection09.class.getMethod("test02"); Type genericReturnType = method2.getGenericReturnType(); if(genericReturnType instanceof ParameterizedType){ for (Type actualTypeArgument : ((ParameterizedType) genericReturnType).getActualTypeArguments()) { System.out.println(actualTypeArgument); } } } }

运行结果

java.util.Map<java.lang.String, com.huang.annotation_reflection.User> ============= class java.lang.String class com.huang.annotation_reflection.User java.util.List<com.huang.annotation_reflection.User> ============= class com.huang.annotation_reflection.User -------------------------- class java.lang.String class com.huang.annotation_reflection.User Process finished with exit code 0 .getGenericParameterTypes()获得泛型的参数类型

思路

先获取方法获取方法的泛型参数化类型获取泛型返回类型

反射操作注解

练习:ORM

代码

package com.huang.annotation_reflection; import java.lang.annotation.*; public class reflection10 { public static void main(String[] args) throws NoSuchFieldException { Class c1 = Student2.class; //获得注解 System.out.println("获得注解"); Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解Value值 System.out.println("获得注解Value值"); MyTable myTable = (MyTable) c1.getAnnotation(MyTable.class); System.out.println(myTable.value()); //获得类指定的注解和值 System.out.println("获得类指定的注解和值"); MyFiled myFiled = c1.getDeclaredField("name").getAnnotation(MyFiled.class); System.out.println(myFiled.colName()); System.out.println(myFiled.type()); System.out.println(myFiled.length()); } } @MyTable("db_student2") class Student2 { @MyFiled(colName = "db_name",type = "varchar",length = 10) String name; @MyFiled(colName = "db_id",type = "int",length = 20) int id; @MyFiled(colName = "db_age",type = "int",length = 3) 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 + '}'; } } //类名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface MyTable { String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface MyFiled { String colName(); String type(); int length(); }

运行结果

获得注解 @com.huang.annotation_reflection.MyTable(value=db_student2) 获得注解Value值 db_student2 获得类指定的注解和值 db_name varchar 10

双亲委派机制

双亲委派机制,的确是防止同名包、类与 jdk 中的相冲突,实际上加载类的时候,先通知 appLoader,看 appLoader 是否已经缓存,没有的话,appLoader 又委派给他的父类加载器(extLoader)询问,看他是不是能已经缓存加载,没有的话,extLoader 又委派他的父类加载器(bootstrapLoader)询问,BootstrapLoader看是不是自己已缓存或者能加载的,有就加载,没有再返回 extLoader,extLoader 能加载就加载,不能的话再返回给 appLoader 加载,再返回的路中,谁能加载,加载的同时也加缓存里。正是由于不停的找自己父级,所以才有 Parents 加载机制,翻译过来叫 双亲委派机制。

参考资料

Java注解与反射深入浅出完整学习笔记(附完整案例代码以及内存加载机制)注解–案例–简单的测试框架(黑马程序员)

代码资料

Annotation&Reflection_01
最新回复(0)