注解与反射
注解与反射
注解
注解:就是以@开头的
比如:@Override
内置注解
例如:
@Override:重写注解
@Deprecated:表示已过时的注解(不推荐使用某方法)
@SuppressWarnings(String[] value()):镇压警告,参数是value=一个字符串数组
元注解
修饰其他注解的注解
@Target:描述注解的使用范围
@Retention:表示在什么级别保留注解信息,用于描述注解的生命周期
(SOURCE<CLASS<RUNTIME)
......
自定义注解
//元注解修饰自定义注解 @Target(value= {ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) //自定义注解,写法:public @interface 注解名 public @interface MyAnotation{ String name() default "qs";//注解参数,这里默认值为qs,写法:类型 名() int[] num();//注解参数 } //由public修饰的类时,自定义注解不用写public
反射
反射机制:Java有一个很特别的类——Class,java的所有类都有一个Class对象,该对象记录关于对应的类的信息,所有类都只有一个Class对象,Class对象是由JVM(Java虚拟机)创建的,自己不能实例化class对象
通过引入java.lang.reflect.* 我们可以获取对应的类对象的构造器、方法、属性等,还可以实例化类对象对应的类从而获得一个对象
获取类对象的方式
-
对象.getClass()
import java.lang.reflect.*; public class test { public static void main(String[] args){ User user = new User(); Class c = user.getClass(); System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } } -
Class.ForName()
import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException{ Class c = Class.ForName("testReflaction/User"); System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } } -
类名.class
import java.lang.reflect.*; public class test { public static void main(String[] args){ Class c = User.class; System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } }
所有类型的class对象
- 类有class对象:object.class
- 数组有class对象:String[].class
- 接口有class对象:Comparable.class
- 二维数组有class对象
- 注解有class对象:Override.class
- 枚举有class对象:ElementType.class
- 基本数据类型有class对象
- void有class对象:void.class
- Class类本身有class对象:class.class
类加载内存和类初始化
类的加载:把class文件的字节码读入内存,把静态数据转换为方法区运行时数据结构,并生成一个Class对象表示该类
链接:
- 验证:确保类信息符合JVM规范
- 准备:正式为静态变量(类变量)分配内存并设置默认值,这些内存在方法区分匹配
- 解析:把虚拟机常量池内的符号引用(常量名引用)转换为直接引用(地址引用)
初始化:执行类构造器
class Test{ static{ ... } static int a = 100; public Test(){ ... } } //如以上代码,把这里的static修饰的变量和static代码块里面的代码合并起来就是类构造器方法 //而Test()这个方法才是构造方法
初始化一个类,发现其父类没有初始化,会首先初始化父类
虚拟机会保证一个类的构造器方法在多线程环境被正确加锁和同步
什么时候类会初始化:
主动引用:
- new的时候
- 反射的时候
类加载器
类缓存:类被加载到加载器,会维持加载一段时间,JVM垃圾回收机制可以回收这些缓存的类的class对象
类加载器类型:
-
引导类加载器(根加载器,c++写的无法获取)
-
扩展类加载器
-
系统类加载器(常用)
package testReflaction; public class ClassLoader { public static void main(String[] args){ java.lang.ClassLoader loader1 = java.lang.ClassLoader.getSystemClassLoader(); System.out.println(loader1);//打印系统类加载器 java.lang.ClassLoader loader2 = loader1.getParent(); System.out.println(loader2);//打印扩展类加载器 java.lang.ClassLoader loader3 = loader2.getParent(); System.out.println(loader3);//打印根类加载器,无法获取显示为空 } }
获取类运行时结构
获取类名:
类对象.getName()——获取包名+类名
类对象.getSimpleName()——获取类名
获取类属性
类对象.getFields()——只获取public属性
类对象.getDeclaredFields()——获取所有属性
类对象.getField("属性名")——获得指定public属性
类对象.getDeclaredFields("属性名")——获取指定的非public属性
package testReflaction; import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{ Class c1 = Class.forName("testReflaction.User");//获取类对象 //获取类名 System.out.println("获取类名:"); System.out.println(c1.getName());//获取并打印包名+类名 System.out.println(c1.getSimpleName());//获取并打印类名 //获取类属性 System.out.println("获取类属性:"); System.out.println("___________________________________________"); Field[] fields = c1.getFields(); for(Field field:fields){ System.out.println(field); } System.out.println(""); for (Field f : c1.getDeclaredFields()){ System.out.println(f); } Field f1 = c1.getField("name"); Field f2 = c1.getDeclaredField("a"); System.out.println("获取指定属性:\n" + f1 + "\n" + f2); } } class User{ public String name="qq"; static int a = 1; int b = 3; public User(String n){ this.name = n; } public User(){ } public String getName(){ return this.name; } public int getA(){ return a; } int getB(){ return b; } }
获取类方法
类对象.getMethod()——获取指定public方法
类对象.getMethods()——获取所有public方法
类对象.getDeclaredMethod()——获取指定非Public方法
类对象.getDeclaredMethods()——获取所有非public方法
package testReflaction; import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{ Class c1 = Class.forName("testReflaction.User");//获取类对象 //获取类方法 System.out.println("获取类方法:"); Method[] methods = c1.getMethods(); System.out.println("getMethods:"); for (Method m : methods){ System.out.println(m); } System.out.println("getDeclaredMethods:"); for (Method m1 : c1.getDeclaredMethods()){ System.out.println(m1); } Method m3 = c1.getDeclaredMethod("getB"); System.out.println(m3); Method m4 = c1.getMethod("getA"); System.out.println(m4); } } class User{ public String name="qq"; static int a = 1; int b = 3; public User(String n){ this.name = n; } public User(){ } public String getName(){ return this.name; } public int getA(){ return a; } int getB(){ return b; } }
获取构造方法
类对象.getConstructor():获取指定的公有构造方法
类对象.getConstructors():获取类中所有公有构造方法
类对象.getDeclaredConstructor():获取指定的构造方法
类对象.getDeclareConstructors():获取类的所有构造方法
package testReflaction; import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{ Class c1 = Class.forName("testReflaction.User");//获取类对象 //获取构造方法 System.out.println("___________________________________________"); System.out.println("获取构造方法:"); for (Constructor c : c1.getConstructors()){ System.out.println(c); } for (Constructor c2 : c1.getDeclaredConstructors()){ System.out.println(c2); } System.out.println(c1.getConstructor(String.class)); System.out.println(c1.getDeclaredConstructor()); } } class User{ public String name="qq"; static int a = 1; int b = 3; public User(String n){ this.name = n; } public User(){ } public String getName(){ return this.name; } public int getA(){ return a; } int getB(){ return b; } }
通过反射动态创建对象
package testReflaction; import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException,IllegalAccessException,InstantiationException{ Class c1 = Class.forName("testReflaction.User");//获取类对象 //创建对象 //newInstance() User user = (User)c1.newInstance(); System.out.println(user); //通过构造器创建 Constructor c = c1.getDeclaredConstructor(String.class); User use = (User)c.newInstance("小d"); System.out.println(use); //调用方法 Method getA = c1.getMethod("getA",null); getA.invoke(use,null); } } class User{ public String name="qq"; static int a = 1; int b = 3; public User(String n){ this.name = n; } public User(){ } public String getName(){ return this.name; } public int getA(){ return a; } int getB(){ return b; } }
反射机制很重要,在java反序列化时会用到,可以用来获取一些自定义类的信息,还可以利用JAVA本身自带的包中的类来执行系统命令或执行代码,在框架中也会用到
接下来会去学习并记录一些JAVA反序列化的实战,以及框架方面的知识
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理