时刻保持学习之心,方能成就不世功业

注解和反射

1. 注解
1.1 注解概念

注解:Java注解(Annotation)又称Java标注,是JDK5.0之后引入的一种注释机制,它可以标注在类,方法,参数、变量、包等都可以被标注。Java的标注可以通过反射来获取内容;

2.注解类型
2.1 内置注解

三个注解均在Java.Lang中,且SuppressWarnings(“all or uncher…”)

@Override—>检查该方法是否重写方法,如果其父类和实现的接口没有该方法,则会报错;

@Deprecated---->标记过时的方法,如果该方法过时,会发出警告,且该方法能用,但不建议使用;

@SuppressWarnings—>忽略代码中的声明警告;

2.2 元注解

元注解也是注解的注解,主要负责注解其他注解包括四个,在Java.lang.Annoation类型下

@Target---->用来描述注解的使用范围,属于一个接口类型

@Target(value = {ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE})
// 适用范围,可以是方法,类,包@interface test{}

@Retention ---->描述注解在三个位置中某个还有效,一般在runtime中,

runtime>class>source

 @Retention(RetentionPolicy.CLASS)// 注解保存的地方(source,class,runtime) 一般在runtime中生效@interface test{}

@Documented Java注解是否生成在Javadoc中

@Inherited 子类可以继承父类中的注解

2.3 自定义注解

我们可以通过@interface 注解名{ 定义内容 }来自定义注解;注解也可设置返回值但只能是基本类型(Class,eum,Sting)

注解的元素必须有值,我们一般在定义时通常使用0,来设置默认的注解值

    @Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)// 注解生效的地方(source,class,runtime) 一般在runtime中效@interface test{// 注解声明元素的默认格式:类型 属性名  ();// 可通过default 还设置声明参数的默认值,当有默认值时,注解参数可不填String name() default "xixi";//当注解中的声明元素只有一个时,可通过Value来命名String value();//只有一个时// 也可定义数组String[] school();}
3. 反射
3.1 概念

反射机制:(Reflection)是一种将Java静态语言变为准动态语言的关键,反射机制允许程序在运行阶段通过Reflection API取得任何类的内部信息,并且能操作任意对象的属性和方法;

原理:加载完类之后,会在堆内存方法区产生一个class类型对象(一个类只有一个class对象),这个对象包含完整类的信息结构,我们可以通过对象看到类的结构,这个对象就像一个镜子,通过其看到类的结构,因此为反射

3.2 执行方式

反射机制:实例化对象------>getClass()方法------>得到完整的包类名称

正常机制:引入需要的“包类”名称------>new 实例化------->取得实例化对象

3.3 反射的优点和缺点
  1. 优点:

    可以实现动态编译和创建对象,有很大的灵活性

  2. 缺点:

    影响性能,反射是一种解释操作,需要通过JVM虚拟机,要满足什么样的要求,这种操作总是慢于正常的操作;

3.3 获取Class类的方式
// 定义父类person
class Person{String name;int age;private int id;public Person() {}public Person(String name, int age, int id) {this.name = name;this.age = age;this.id = id;}
}
// 子类student继承person类
class student extends Person{public student(){this.name="学生";}
}
// 子类老师类继承person类
class teach extends Person{public teach(){this.name="老师";}
}
//实例化对象
Person person =new student();

方式一:通过实例化对象getClass获取Class

Class c1 = person.getClass();
System.out.println(c1.hashCode());

方式二:通过Class.forname()获取

Class c2 = Class.forName("com.muzi.test.Test.student"); //需要万完整的包名
System.out.println(c2.hashCode());

方式三:通过类名.Class获取Class

Class<student> c3 = student.class; // 已知类名的情况下
System.out.println(c3.hashCode());

方式四:通过基本类型的包装类内置TYPE属性

Class<Integer> c4 = Integer.TYPE;
System.out.println(c4);

方式五: 通过获取的Class类,在去获取父类的Class

Class c5 = c3.getSuperclass();
System.out.println(c5);

执行结果图:

3.4 各类型的Class

我们有很多类型都可以获取Class,Object,class,void,int[],String [] 等;

通过代码测试各类获取Class:

public static void main(String[] args) {Class<Object> c1 = Object.class; //object 类获取Class<Comparable> c2 = Comparable.class; //接口Class<String[]> c3 = String[].class; // 一维数组Class<int[][]> c4 = int[][].class; //二维数组获取Class<Override> c5 = Override.class; //注解获取Class<ElementType> c6 = ElementType.class; // 枚举Class<Void> c7 = void.class; // void 获取Class<Class> c8 = Class.class; //ClassClass<Integer> c9 = Integer.class; // 基本数据类型// 输出其class类 每个的hashCode()值不一样System.out.println(c1.hashCode());System.out.println(c2.hashCode());System.out.println(c3.hashCode());System.out.println(c4.hashCode());System.out.println(c5.hashCode());System.out.println(c6.hashCode());System.out.println(c7.hashCode());System.out.println(c8.hashCode());System.out.println(c9.hashCode());}
3.5 类的加载过程

步骤:

// jvm在加载类中,会先加载方法区内的静态文件 在堆中生成class文件
public class Test_03 {public static void main(String[] args) {A a = new A();System.out.println(a.m);}
}
class A {static {System.out.println("A的静态代码块的加载");int m = 300;}static int m = 10;public A() {System.out.println("A的初始化构造方法");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fiNewK5q-1604460874885)(C:\Users\暴走小萝莉\AppData\Roaming\Typora\typora-user-images\image-20201101111443850.png)]

通过结果分析:程序 执行的时候先加载static方法,在加载构造方法,通过执行类构造器<clinit>方法,

3.6 类的初始化

主动引用与被动引用:
主动引用
java类的初始化阶段,虚拟机规范严格规定了5种情况必须立即对类进行初始化。

  1. 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
  2. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  3. 当初始化一个类时,如果发现其父类没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要制定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个类。
  5. 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_geStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
    被动引用
    除了上述5种场景,其他所有类的方式都不会触发初始化,称为被动引用。
    代码实现:
// 测试主动引用和被动引用
public class Test_04 {static {System.out.println("main方法初始化");}public static void main(String[] args) {//使用子类 ,父类也会被初始化,且先执行父类的方法 --->主动引用//Son son = new Son();// 被动引用// 当子类引用父类的静态变量,子类的静态代码块不会被初始化System.out.println(Son.n);// 定义一个数组,被动引用时,不会触发出初始化//Son[] array=new Son[5];// 调用Son的常量 ,已经存在于常量池中,不会触发初始化;System.out.println(Son.M);}
}//父类
class Father {static int n = 5;static {System.out.println("父类初始化");}public Father() {System.out.println("父类构造方法");}
}// 子类
class Son extends Father {static {System.out.println("子类初始化");}final static int M = 2;}
3.7 类加载的作用

1.Java文件运行的过程:

2.类加载的作用:

概念------->类加载:通过将字节码 .class文件内容加载到内存中,并将这些静态的数据转化为方法区运行时的数据结构,后在堆中生成一个Java.lang.class对象,作为方法区类数据的访问入口;

类缓存:标准JavaSE类加载器可以按照要求查找类,如果某个类一旦被加载到类加载器中,那么它将维持加载一段时间,jvm的垃圾回收机制可以回收这些class对象;

作用:将类加载到内存中;—>jvm规范了四种类加载器:

引导类加载器:---->Bootstrap ClassLoader

由c++编写,是jvm自带的类加载器,负责java平台核心库,用来加载Java核心类库,不能直接获取;rt.jar

扩展类加载器----->Extension ClassLoader

负责jre/lib/ext目录下的jar包,或者-D Java.ext.dirs指定目录下的jar包装入工作库

系统类加载器—>System ClassLoader

负责java -classpath所指目录下的类与jar包的装入工作,是最常见的类加载器
自定义类加载器—> ClassLoader
新建一个类继承自java.lang.ClassLoader,重写它的findClass方法。 将class字节码数组转换为Class类的实例;调用loadClass方法即可.
3. 代码实现:

   public static void main(String[] args) {// 获取系统类加载ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);// 获取系统加载器的父类 ------->扩展加载器ClassLoader parent = systemClassLoader.getParent();System.out.println(parent);// 获取扩展加载器的父类----->引导类加载器(根加载器)是jvm虚拟机自带的,不能直接获取ClassLoader parent1 = parent.getParent();System.out.println(parent1);}// 测试当前类,是什么加载器加载的ClassLoader classLoader = Class.forName("com.muzi.test.Test.Test_05").getClassLoader();System.out.println(classLoader);// 测试jdk类是什么加载器加载的classLoader = Class.forName("java.lang.Object").getClassLoader();System.out.println(classLoader);//获取系统加载类可以加载的路径System.out.println(System.getProperty("java.class.path"));/*** C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;* C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;* C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;* C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;* C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;*/
3.8 获取运行类的完整结构
  • 通过反射获取类的完整结构:

反射的方法---->Field、Method、Constructor、Superclass、Interface、Annotation

  • 代码实现:

  •     // 通过反射获取类Class c1 = Class.forName("com.muzi.test.Test.Person");System.out.println(c1);//获取类的名字System.out.println(c1.getName()); // 包名+类名;System.out.println(c1.getSimpleName());// 获取类名// 获取类的属性Field[] fields = c1.getDeclaredFields(); //可以找到类下的所有属性包名+属性名for (Field field : fields) {System.out.println(field);}Field[] fields1 = c1.getFields();// 只能获取 公共类的属性;for (Field field : fields1) {System.out.println(field);}Field field = c1.getField("name");//获取指定公共属性System.out.println(field);Field id = c1.getDeclaredField("id"); //获取类中的任意属性System.out.println("field2" + id);// 获取类的方法Method[] methods = c1.getMethods();// 只能获取公共类的方法和父类的方法for (Method method : methods) {System.out.println("method======" + method);}Method[] declaredMethods = c1.getDeclaredMethods();// 获取本类的私有和公共类的方法for (Method declaredMethod : declaredMethods) {System.out.println("declaredMethods====" + declaredMethod);}Method method = c1.getEnclosingMethod();//一个class表示在方法中的一个本地或匿名class, 那么通过java.lang.Class.getEnclosingMethod()方法将返回的底层类的立即封闭方法。 反之则为NULL。System.out.println(method);Method method1 = c1.getMethod("getName");//获取类的指定公共的方法System.out.println(method1);Method getId = c1.getDeclaredMethod("getId", null); //获取私有类的方法System.out.println("getId____"+getId);
    
3.9 动态创建对象执行方法

1.通过Class获取对象属性和结构的作用:

我们通过反射机制获取运行类的属性和结构,无需自身实例化,通过反射机制来例化 newInstance()

  1. ===代码实现:=
//获取类对象Class c1 = Class.forName("com.muzi.test.Test.TsetPerson");// 实例化对象  newInstance()  必须要由无参构造器//Person person = (Person) c1.newInstance();// System.out.println(person);//通过构造器创建对象  ----->有参构造 使用newInstance  这是在无参构造的方法下://Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);// Person2 instance = (Person2) constructor.newInstance("木子", 5, 18);//System.out.println(instance);// 通过方式调用普通方法//先实例化类TsetPerson p2 = (TsetPerson) c1.newInstance();//通过反射获取方法Method setName = c1.getDeclaredMethod("setName", String.class);// invoke(类型名,设置值) 激活 类型名必须声明setName.invoke(p2, "阿木木"); //给方法传入值System.out.println(p2.getName());// 通过实例化对象获取// 通过反射操作属性----->在无参构造的方法情况下TsetPerson person3 = (TsetPerson) c1.newInstance();Field name = c1.getDeclaredField("name");// 通过set Get方法给其赋值name.set(person3, "阿木木2");// 无法输出,因为权限的限定 解除权限name.setAccessible(true);//设置解除对name的权限限定System.out.println(person3.getName());

如果频繁对私有属性的调用,建议开启setAccessible(true),提高反射的效率;

3.10 通过反射获取泛型

泛型:Java采用泛型擦除机制引入泛型,Java中的泛型仅是给Javac使用的,确保数据的安全和免去强制类型转化的问题,且一旦编译完成,就会擦除所有和泛型有关的类型;

为通过反射机制获取泛型,Java新增了很多类型他们不能与class归在一类但是又与class齐名

通过代码来实现:

public static void test01(Map<String, TsetPerson> map, List<TsetPerson> list) {System.out.println("test01");}public Map<String, TsetPerson> test02() {System.out.println("test02");return null;}public static void main(String[] args) throws NoSuchMethodException {//通过类名获取class对象Method test01 = Test_09.class.getMethod("test01", Map.class, List.class);// 通过获取的方法来获取泛型Type[] genericParameterTypes = test01.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {System.out.println(genericParameterType);//将泛型打印出来// 获取泛型的参数信息,利用条件判断//genericParameterType ---->泛型参数类型//ParameterizedType 参数类型if (genericParameterType instanceof ParameterizedType) {//getActualTypeArguments----->获取实际参数类型Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}//通过返回值参数泛型获取Method test02 = Test_09.class.getMethod("test02", null);Type genericReturnType = test02.getGenericReturnType();if (genericReturnType instanceof ParameterizedType) {//genericReturnType----->返回值参数泛型Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println("$$$$$$$" + actualTypeArgument);}}}
3.11 获取注解信息

ORM----->对象关系映射----->Object Relationship Mapping

反射操作注解:getAnnotations 与 getAnnotation

关于类和表的注解关系:

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {//通过反射获取注解信息Class c1 = Class.forName("com.muzi.test.Test.Animal");Annotation[] annotation = c1.getAnnotations();for (Annotation annotation1 : annotation) {System.out.println(annotation1);}//通过getAnnotation反射获取注解内部的值annotation1.value();Table annotation1 = (Table) c1.getAnnotation(Table.class);String value = annotation1.value();System.out.println(value);//获取属性的注解Field name = c1.getDeclaredField("name");Annotation[] annotation2 = name.getAnnotations();for (Annotation annotation3 : annotation2) {System.out.println("$$$$$" + annotation3);}//获取属性内部 的值 通过属性去获取注解的值与方法不同field annotation3 = name.getAnnotation(field.class);System.out.println(annotation3.column());System.out.println(annotation3.type());System.out.println(annotation3.type());}}@Table("db_animal")
class Animal {@field(column = "db_id", type = "int", length = 10)private int id;@field(column = "db_name", type = "String", length = 20)private String name;@field(column = "db_age", type = "int", length = 3)private int age;public Animal(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Overridepublic String toString() {return "Animal{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}public Animal() {}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 field {String column();//列String type();// 类型int length();//长度
}

Java---->强烈安利0_0详解注解和反射机制相关推荐

  1. python反射机制_详解python之反射机制

    一.前言 deff1():print('f1')deff2():print('f2')deff3():print('f3')deff4():print('f4') a= 1 test.py impor ...

  2. Java单元测试之JUnit4详解

    2019独角兽企业重金招聘Python工程师标准>>> Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @B ...

  3. Java编程配置思路详解

    Java编程配置思路详解 SpringBoot虽然提供了很多优秀的starter帮助我们快速开发,可实际生产环境的特殊性,我们依然需要对默认整合配置做自定义操作,提高程序的可控性,虽然你配的不一定比官 ...

  4. Java基础学习总结(24)——Java单元测试之JUnit4详解

    Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @BeforeClass 全局只会执行一次,而且是第一个运行 @Before  ...

  5. java 8 新功能详解_Java 8和Java 14之间的新功能

    java 8 新功能详解 从版本9开始,Java每6个月就有一次新功能,因此很难跟踪这些新更改. 互联网上的大多数信息都描述了最近2个Java版本之间的变化. 但是,如果您的情况与我相似,则说明您使用 ...

  6. Java基准测试工具JMH详解

    Java基准测试工具JMH详解 1.JMH概述 1.1 JMH简介 1.2 JMH与JMeter区别 1.3 JMH注解说明 2.JMH验证 2.1 创建项目 2.2 引入依赖 2.3 启动异常解决 ...

  7. Java线程池ThreadPool详解

    Java线程池ThreadPool详解 1. 线程池概述 1.1 线程池简介 1.2 线程池特点 1.3 线程池解决问题 2. 线程池原理分析 2.1 线程池总体设计 2.6 线程池流转状态 2.2 ...

  8. java -jar 和 -cp详解

    java -jar 和 -cp详解 命令行执行程序 假如我们有一个程序,把它打包成Test.jar,如何运行才能成功输出Hello World package com.test; public cla ...

  9. java访问修饰符详解——学java,零基础不怕,不只要理论,更要实践+项目,a href=http://www.bjweixin.com太原维信科技提供 /a...

    java访问修饰符详解--学java,零基础不怕,不只要理论,更要实践+项目 <a href=http://www.bjweixin.com>太原维信科技提供 </a> pub ...

最新文章

  1. python从入门到精通怎么样-Python 从入门到精通:一个月就够了
  2. Connection to node -1 (Desktop/192.168.0.102:9091) could not be established.
  3. 原生JavaScript第一篇
  4. Linux系统服务之dhcp
  5. 猜数字(HDU-2178)
  6. Android 系统(65)---Android修改分区格式为F2FS
  7. 为什么说堡垒机是企业IT运维的“安全终结者”?
  8. elk平台分析nginx日志的基本搭建
  9. 调整Redmine的用户显示格式
  10. CFA一级考试题型是什么?好不好考?
  11. 京东和淘宝近十年搜索热度对比,发现顶尖者的PK规律
  12. 键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。(C++)(贪心法)
  13. CentOS7和CentOS8 FreeSWITCH 1.10.7 简单图形化界面18--内网的讯时FXO网关SIP对接到内网的FreeSWITCH
  14. MacOS强制卸载第三方输入法(搜狗输入法、百度输入法)
  15. 计算机编程教育资源,风变编程以科技实现教育普惠,俱进教育公平
  16. 《单片机原理及应用》复习提纲
  17. 快捷生成HTML代码的实现
  18. 求近似数最值_求近似数的方法
  19. 关于如何在Termux上安装kali(最好用旧手机)
  20. 「JOISC 2018 Day 3」比太郎的聚会

热门文章

  1. Android下的遥控器DIY
  2. SpringBoot实现用户统一管理与单点登陆
  3. form layui 同时提交多个对象_layui实现form表单同时提交数据和文件的代码
  4. 京东API提取方法-获得JD商品详情API
  5. 光脚丫学LINQ(003):排序结果集
  6. 对称矩阵的特征向量两两正交的证明
  7. checkbox选中和不选中 jqu_jQuery控制checkbox选中状态但是不显示选中
  8. 计算机信息及安全行业必知名词术语
  9. 《三国演义》人物出场统计
  10. DTAS-电机机壳与端盖止口垂直度对电机气隙影响