(Java)注解和反射
文章目录
- 注解和反射
- 一. 注解
- 1.1 元注解
- 1.2 内置注解
- 1.3 自定义注解
- 二. 反射
- 2.1 什么是反射
- 2.2 Class类
- 2.3 创建Class类的方式
- 2.4 所有类型的Class
- 2.5 类加载机制内存分析
- 2.6 类的初始化
- 2.7 类加载器
- 2.7.1 双亲委派机制
- 2.9 获取运行时类的完整结构
- 2.10 通过反射动态的创建对象
- 2.11 反射操作泛型
- 2.12 反射操作注解(重点)
注解和反射
一. 注解
注解(Annotation)是Java提供的设置程序中元素的关联信息和元数据(MetaData)的方法,它是一个接口,程序可以通过反射获取指定程序中元素的注解对象,然后通过该注解对象获取注解中的元数据信息。
1.1 元注解
import java.lang.annotation.*;//测试原注解
@MyAnnotation
public class Test01 {public void test() {}}//定义一个注解
//Target 表示我们的注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})//Retention 表示我们的注解在什么地方有效 runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)//Documented 表示是否将我们的注解生成在JAVAdoc中
@Documented//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{}
1.2 内置注解
import java.util.ArrayList;//内置注解
public class Test03 {@Override //重写的注解public String toString() {return "Test03{}";}@Deprecated //不推荐使用,存在更好的public static void test() {System.out.println("Deprecated");}@SuppressWarnings("all") //镇压警告public void test2() {ArrayList arrayList = new ArrayList();}public static void main(String[] args) {test();}}
1.3 自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
public class Demo01 {//注解可以显示赋值,如果没有默认值,我们就必须给注解赋值@MyAnnotation(name="伊泽瑞尔",schools = "战争学院")public void test1(){}//一个参数的注解可以直接写值@MyAnnotation1("魔法猫咪")public void test2(){}//设置生效类型@Target({ElementType.TYPE,ElementType.METHOD})//设置作用范围@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotation{String name() default "";int age() default 0;int id() default -1;String[] schools() default {"",""};}//设置生效类型@Target({ElementType.TYPE,ElementType.METHOD})//设置作用范围@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotation1{//一个参数的注解一般用value作为参数String value();}
}
二. 反射
2.1 什么是反射
Java c c++是静态语言,Java可以通过反射获得类似动态语言的特性。(准动态语言)
动态语言是指在运行阶段可以改变其结构
反射 优点:
- 可以动态创建对象和编译,灵活
反射 缺点:
- 对象性能有影响,总是慢于直接执行相同的操作
2.2 Class类
- class本身也是一个类
- 只能由系统建立对象
- 一个加载的类在JVM中只会有一个Class实例
- 一个Class实例对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个class实例生成的
- 通过Class可以完整的得到一个类所有被加载的结构
- Class类是Reflection反射的根源,针对任何想动态加载,运行的类,唯有先获得相应的Class对象
2.3 创建Class类的方式
package com.company.demo11.reflection;public class Demo01 {public static void main(String[] args) throws ClassNotFoundException {Person person = new Student();System.out.println("这个人是:"+person.name);//1.通过对象获得Class c1 = person.getClass();System.out.println(c1.hashCode());//2.forName获得Class c2 = Class.forName("com.company.demo11.reflection.Student");System.out.println(c2.hashCode());//3.通过类名.class获得Class c3=Student.class;System.out.println(c3.hashCode());//4.基本内置类型的包装类都有一个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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';}
}
class Student extends Person {public Student() {this.name = "学生";}
}
class Teacher extends Person {public Teacher() {this.name = "老师";}
}
2.4 所有类型的Class
package com.company.demo11.reflection;import java.lang.annotation.ElementType;
//所有类型的Class
public class Demo02 {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; //voidClass c9 = Class.class; //ClassSystem.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);//只要元素类型与维度一样,就是同一个Classint[] a = new int[10];int[] b = new int[100];System.out.println(a.getClass().hashCode());System.out.println(b.getClass().hashCode());}}
2.5 类加载机制内存分析
JVM的类加载分为5个阶段:加载,验证,准备,解析,初始化。在类初始化完成后就可以使用该类的信息,在一个类不再被需要时可以从JVM中卸载。如图所示:
代码测试
public class Test {public static void main(String[] args) {A a = new A();System.out.println(a.m);/*** 1.加载到内存,会产生一个类对应的Class对象* 2.链接,链接结束后m=0 链接:把Java的二进制代码合并到JVM运行状态之中的过程* 3.初始化* <clinit>(){* System.out.println("A类静态代码块初始化");* m = 100;* m = 200;* }* m = 200*/}}
class A{static {System.out.println("A类的静态代码块初始化");m=100;}static int m = 200;public A() {System.out.println("A类的无参构造方法初始化");}
}
内存分析如图
2.6 类的初始化
主要通过执行类构造器的方法为类进行初始化。方法是在编译阶段由编译器自动收集类中静态语句块和变量的赋值操作组成的。JVM规定,只有在父类的方法都执行成功后,子类中的方法才可以被执行。在一个类中既没有静态变量赋值操作也没有静态语句块时,编译器不会为该类生成方法。
在发生以下几种情况时,JVM不会执行类的初始化流程。
- 常量在编译时会将其常量值存入使用该常量的类的常量池中,该过程不需要调用常量所在的类,因此不会触发该常量类的初始化。
- 在子类引用父类的静态字段时,不会触发子类的初始化,只会触发父类的初始化。
- 定义对象数组,不会触发该类的初始化,只是开辟了一块空间。
- 在使用类名获取Class对象时不会触发类的初始化。
- 在使用Class.forName加载指定的类时,可以通过initialize参数设置是否需要对类进行初始化。
- 在使用ClassLoader默认的loadClass方法加载类时不会触发该类的初始化
public class Test01 {static {System.out.print("main类被加载 ");}public static void main(String[] args) throws ClassNotFoundException {//在主动引用时,会初始化//1.主动引用,父类没被引用,会先加载他的父类
// Son son = new Son();//main类被加载 父类被加载 子类被加载//2.反射也会产生主动引用
// Class.forName("com.company.demo11.reflection.Son");//main类被加载 父类被加载 子类被加载//不会产生类的引用方法//1.子类引用父类的静态字段时,不会触发子类的初始化,只会触发父类的初始化
// System.out.println(Son.b);//main类被加载 父类被加载 2//2.定义对象数组,不会触发该类的初始化,只是开辟了一块空间
// Son[] sons = new Son[8];//main类被加载//3.常量调用不会初始化
// System.out.println(Son.M);//main类被加载 1//4.在使用类名获取Class对象时不会触发类的初始化
// Class c = Son.class;//main类被加载}
}
class Father{static int b =2;static {System.out.print("父类被加载 ");}
}
class Son extends Father{static {System.out.print("子类被加载 ");m=100;}static int m = 200;static final int M = 1;
}
2.7 类加载器
JVM提供了3种类加载器,分别是启动类加载器,扩展类加载器和应用程序类加载器。如图:
public class Test02 {public static void main(String[] args) throws ClassNotFoundException {//获取应用程序类加载器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//获取应用程序类加载器的父类加载器扩展类加载器ClassLoader parent = systemClassLoader.getParent();System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@4554617c//获取扩展类加载器的父类加载器启动类加载器---->无法访问,返回nullClassLoader parent1 = parent.getParent();System.out.println(parent1);//null//测试当前类是那个类加载器加载的ClassLoader classLoader = Class.forName("com.company.demo11.reflection.Test02").getClassLoader();System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2//测试JDK内置的类是谁加载的ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();System.out.println(classLoader1);//null//如何获得系统类加载器可以加载的路径 如果类不在这些地方则读取不到System.out.println(System.getProperty("java.class.path"));//双亲委派机制:多重检测,保证安全性// 比如自己定义一个java.lang.String类,要去加载,它先看用户类加载器有没有--->扩展类加载器--->根加载器//如果有自己写的就无效/**D:\work\java\jdk1.8\jre\lib\charsets.jar;D:\work\java\jdk1.8\jre\lib\deploy.jar;D:\work\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;:\work\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\work\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\work\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\work\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\work\java\jdk1.8\jre\lib\ext\localedata.jar;D:\work\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\work\java\jdk1.8\jre\lib\ext\sunec.jar;D:\work\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\work\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\work\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\work\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\work\java\jdk1.8\jre\lib\javaws.jar;D:\work\java\jdk1.8\jre\lib\jce.jar;D:\work\java\jdk1.8\jre\lib\jfr.jar;D:\work\java\jdk1.8\jre\lib\jfxswt.jar;D:\work\java\jdk1.8\jre\lib\jsse.jar;D:\work\java\jdk1.8\jre\lib\management-agent.jar;D:\work\java\jdk1.8\jre\lib\plugin.jar;D:\work\java\jdk1.8\jre\lib\resources.jar;D:\work\java\jdk1.8\jre\lib\rt.jar;E:\注解和反射\out\production\注解和反射;D:\work\idea\lib\idea_rt.jar*/}
}
2.7.1 双亲委派机制
JVM通过双亲委派机制对类进行加载。
双亲委派机制是指一个类在收到类加载请求后不会尝试自己加载这个类,而是把类加载请求向上委派给其父类去完成,其父类在接收到该类加载请求后又会将其委派给自己的父类,以此类推,这样所有的的类加载请求都被向上委派到启动类加载器中。
若父类加载器在接收到类加载请求后发现自己也无法加载该类(通常原因是该类的Class文件在父类的类加载器路径中不存在),则父类会将该信息反馈给子类并向下委派子类加载器加载该类,直到类被成功加载,若找不到该类,则JVM会抛出ClassNotFound异常。
双亲委派类加载机制的类加载流程如图:
2.9 获取运行时类的完整结构
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class Demo03 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {Class c1 = Class.forName("com.company.demo11.reflection.User");//获取类的名字System.out.println(c1.getName());//com.company.demo11.reflection.UserSystem.out.println(c1.getSimpleName());//UserSystem.out.println("--------------------------------------");//获得类的属性Field[] fields = c1.getFields();//只能找到public属性fields = c1.getDeclaredFields();//找到全部属性for (Field field : fields) {System.out.println(field);/*private java.lang.String com.company.demo11.reflection.User.nameprivate int com.company.demo11.reflection.User.idprivate int com.company.demo11.reflection.User.age*/}System.out.println("--------------------------------------");//获取指定属性的值System.out.println(c1.getDeclaredField("name"));//private java.lang.String com.company.demo11.reflection.User.nameSystem.out.println("--------------------------------------");//获取类的方法Method[] methods = c1.getMethods();//获取本类及其父类的全部public方法for (Method method : methods) {System.out.println(method);}System.out.println("--------------------------------------");Method[] declaredMethods = c1.getDeclaredMethods();//获取本类的所有方法for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println("--------------------------------------");//获得指定的方法Method getName = c1.getMethod("getName", null);Method setName = c1.getMethod("setName", String.class);System.out.println(getName);//public java.lang.String com.company.demo11.reflection.User.getName()System.out.println(setName);//public void com.company.demo11.reflection.User.setName(java.lang.String)System.out.println("--------------------------------------");//获取构造器Constructor[] constructors = c1.getConstructors();//获取public的构造器for (Constructor constructor : constructors) {System.out.println("public构造器:"+constructor);/*public com.company.demo11.reflection.User(java.lang.String,int,int)public com.company.demo11.reflection.User()*/}Constructor[] declaredConstructors = c1.getDeclaredConstructors();//获取全部的构造器for (Constructor declaredConstructor : declaredConstructors) {System.out.println("全部构造器:"+declaredConstructor);/*public com.company.demo11.reflection.User(java.lang.String,int,int)public com.company.demo11.reflection.User()*/}//获取指定的构造器Constructor constructor = c1.getConstructor(String.class, int.class,int.class);System.out.println("指定构造器"+constructor);//public com.company.demo11.reflection.User(java.lang.String,int,int)}
}
2.10 通过反射动态的创建对象
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Demo04 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {//获得Class对象Class c1 = Class.forName("com.company.demo11.reflection.User");//创建一个对象,此操作必须要有无参构造方法User user1 = (User) c1.newInstance();System.out.println(user1);//调用无参构造方法 User{name='null', id=0, age=0}//通过构造器创建对象Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);User user2 = (User) constructor.newInstance("周星驰", 007, 18);System.out.println(user2);//User{name='周星驰', id=7, age=18}//通过反射调用普通方法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.setAccessible(true);name.set(user4,"魔法猫咪");System.out.println(user4.getName());//魔法猫咪}
}
2.11 反射操作泛型
/通过反射获取泛型
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 NoSuchMethodException {/*#java.util.Map<java.lang.String, com.lcy.reflection.User>class java.lang.Stringclass com.lcy.reflection.User#java.util.List<com.lcy.reflection.User>class com.lcy.reflection.User*///加载的方法和参数Method method = Test11.class.getMethod("test01", Map.class, List.class);//获得泛型的参数类型Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type type :genericParameterTypes) { //打印泛型System.out.println("#"+type);if (type instanceof ParameterizedType) { //想知道里面的参数类型//强转获得真实的泛型参数信息Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();for (Type temp :typeArguments) {System.out.println(temp);}}}/*class java.lang.Stringclass com.lcy.reflection.User*/method = Test11.class.getMethod("test02",null);//获得返回值类型Type genericReturnType = method.getGenericReturnType();if (genericReturnType instanceof ParameterizedType) {Type[] types = ((ParameterizedType) genericReturnType).getActualTypeArguments();for (Type temp :types) {System.out.println(temp);}}}}
2.12 反射操作注解(重点)
import java.lang.annotation.*;
import java.lang.reflect.Field;public class Demo05 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {//获取Class对象Class c1 = Class.forName("com.company.demo11.reflection.Student1");//通过反射获取注解Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);//找到了外面的注解@com.company.demo11.reflection.Table(value=db_stu)}//获取注解value的值Table annotation = (Table) c1.getAnnotation(Table.class);System.out.println(annotation.value());//db_stu//获取类指定的注解Field f = c1.getDeclaredField("name");FieldZh annotation1 = f.getAnnotation(FieldZh.class);System.out.println(annotation1.columName());System.out.println(annotation1.type());System.out.println(annotation1.length());}}
@Table("db_stu")
class Student1{@FieldZh(columName = "id",type = "int",length = 10)int id;@FieldZh(columName = "name",type = "varchar",length = 10)String name;@FieldZh(columName = "age",type = "int",length = 3)int age;@Overridepublic String toString() {return "Student1{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}public Student1() {}public Student1(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
//创建表的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{String value();
}
//创建属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldZh{String columName();String type();int length();}
(Java)注解和反射相关推荐
- java注解的反射_Java注解与反射
概要 本文主要是总结Java注解与反射的相关知识,加深自己对Java类动态语言的理解,同时为日后学习Spring打下基础. 注解: 什么是注解 Annotation的作用 不是程序本身,但是可以对程序 ...
- java 注解与反射
java 注解与反射 学习笔记: 1.注解:注释给计算机理解 英文:Annotation 2.注解不是必须的,但是会因为程序的需要 3. 三种java内置类型:Override.Deprecated. ...
- Java注解与反射系列——Class类day1-3
Java注解与反射系列--Class类 Class类 常用方法 哪些类型有Class对象? 类的加载过程 类的加载 链接 初始化 什么时候会发送类的初始化 类的主动引用 类的被动引用 获取Class实 ...
- java注解与反射的使用及原理
写在前面 你们好,我是小庄.很高兴能和你们一起学习Java注解与反射的使用及原理.如果您对Java感兴趣的话可关注我的动态. 写博文是一种习惯,在这过程中能够梳理知识和巩固知识点. 文章目录 ...
- 关于Java你不知道的那些事之Java注解和反射
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 作者:轻 ...
- JAVA注解和反射(笔记)
注解简介 Annotation是从JDK5.0开始引入的新技术). Annotation的作用 : 不是程序本身(可以对程序作出解释.(这一点和注释(comment)没什么区别) 可以被其他程序(比如 ...
- java 需要class interface 或enum_阿里P8教你Java注解与反射
Ⅰ 什么是注解 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制.Java 语言中的类.方法.变量.参数和包等都可以被标注.和 Javadoc 不同,J ...
- Java基础学习(11)---Java注解和反射
文章目录 一.注解概述 二.内置注解 三.元注解 四.自定义注解 五.反射概述 ★ 静态语言 VS 动态语言 反射机制 Java反射机制研究及应用 Java反射优点和缺点 六.Class类 获取Cla ...
- java注解和反射——狂神说java学习笔记三
原文链接:公众号狂神说 视频教程[狂神说B站]: https://www.bilibili.com/video/BV12J41137hu 如有侵权,联系立删 什么是注解 Annotation是从JDK ...
- Java 注解和反射
文章目录 注解 java文档注释 自定义注解 解析注解 反射 反射机制介绍 反射入门案例 反射机制原理示意图 反射机制 反射调用优化 Class类 哪些类型有Class对象 如何获取Class类对象 ...
最新文章
- SOJ 8064 Whack the Groundhog
- Oracle的数据备份与恢复
- python字典数组排序sorted_Python利用sorted进行字典排序
- 启明云端分享| 基于ESP32-S2模块的彩屏86盒应用,有哪些亮点呢
- one-to-one
- 封头名义厚度如何圆整_压力容器封头厚度计算
- Spring-Boot使用RedisCluster
- python多进程内存共享_python 归纳 (二十)_多进程数据共享和同步_共享内存Value Array...
- [HNOI2008]玩具装箱toy(dp+斜率优化)
- Angular 5.0 学习2:Angular 5.0 开发环境的搭建和新建第一个ng5项目
- OpenCV-数组加权和cv::addWeighted
- 杰理AD14N/AD15N---外置Flash烧录音乐文件
- vm安装centos,黑屏或黑屏且左上角有光标闪动
- 【转】全套汽车标志\路牌,好不容易找到的哦!
- 【5G UP】5G QoS参数那点事儿
- 大数据学习之路一(大数据概念、特点、应用场景)
- 【硬盘测速】一条命令解决硬盘测速问题
- springcoud-kubernetes实践之用kubernetes做注册中心(包括负载均衡熔断)
- 三星手机安装linux系统下载,技术|在手机上轻松安装 Ubuntu Touch OS
- 无穷小微积分与Moodle系统
热门文章
- C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板和static
- BUUCTF firmware
- 15. 三数之和(双指针)
- MySQL—事务并发问题
- MoeCTF 2021Re部分------大佬请喝咖啡,A_game
- Ubuntu下pip安装、升级、卸载
- 渗透工具开发——XSS平台的命令行实现
- 3、创建用户(3种方式)
- 求1!+2!+3!+...+10!的值
- Python 内建函数 - sorted(iterable[, key][, reverse])