一、注解概述

注解是代码中对代码解释和说明,区别于注释(注释不参与运行完全是给开发者看的),注解除了解释和说明,更为重要的是可以携带数据,可以在程序运行时提取(发射)。

注解的核心使命,1.用于标识一个事物(属性 方法 类型)有特殊含义。 2.用于消灭配置文件。

二、JDK内置注解

1 @Deprecated 注解

可以修饰类、方法、变量,在java源码中被@Deprecated修饰的类、方法、变量等表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等,如果现在使用,则在以后使用了这些类、方法的程序在更新新的JDK、jar包等就会出错,不再提供支持。
个人程序中的类、方法、变量用@Deprecated修饰同样是不希望自己和别人在以后的时间再次使用此类、方法。当编译器编译时遇到了使用@Deprecated修饰的类、方法、变量时会提示相应的警告信息。

2 @Override 注解

指明被注解的方法需要覆写超类中的方法,如果某个方法使用了该注解,却没有覆写超类中的方法(如大小写写错了,或者参数错了,或者是子类自己定义的方法),编译器就会生成一个错误。
在子类中重写父类或接口的方法,@Overide并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写的子类方法将不再属于重写,如果没有@Overide,你将不会察觉到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息。

3 @Suppresswarnings 注解

@SuppressWarnings用来抑制编译器生成警告信息,可以修饰的元素为类,方法,方法参数,属性,局部变量。它可以达到抑制编译器编译时产生警告的目的,使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。所属范围越小越好,因为范围大了,不利于发现该类下其他方法的警告信息。
但是很不建议使用@SuppressWarnings注解,使用此注解,开发人员看不到编译时编译器提示的相应的警告,不能选择更好、更新的类、方法或者不能编写更规范的编码。同时后期更新JDK、jar包等源码时,使用@SuppressWarnings注解的代码可能受新的JDK、jar包代码的支持,出现错误,仍然需要修改。

@SuppressWarnings(“all”) 镇压全部警告
@SuppressWarnings(“unchecked”) 镇压未检查警告
@SuppressWarnings(“unchecked”,”deprecation”) 传递多个参数

三、元注解

用来j解释注解的注解

1. @Target

表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:

  • ElemenetType.CONSTRUCTOR构造器声明
  • ElemenetType.FIELD 域声明
  • ElemenetType.LOCAL_VARIABLE局部变量声明
  • ElemenetType.METHOD方法声明
  • ElemenetType.PACKAGE包声明
  • ElemenetType.PARAMETER 参数声明
  • ElemenetType.TYPE类、接口、enum

    2. @Retention

    表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:

  • RetentionPolicy.SOURCE注解将被编译器丢弃

  • RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
  • RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息

    3. @Documented

    将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。

4 .@Inherited

允许子类继承父类中的注解。

@Target( {ElementType.FIELD , ElementType.TYPE } ) 一个参数就是 value = ElemenetType.FIELD
//标识将来 @Value 可以用在哪些地方
@Retention( RetentionPolicy.RUNTIME )

四、自定义注解

4.1 语法

  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5. @Target({ElementType.METHOD,ElementType.TYPE})
  6. @Retention(RetentionPolicy.RUNTIME)
  7. public @interface myannotation {
  8. String value() ; //名为value时 在注解处 可以省略 value=
  9. int age() default -1;
  10. }

例子

  1. //反射操作注解
  2. import javax.swing.*;
  3. import java.lang.annotation.*;
  4. import java.lang.reflect.Field;
  5. @SuppressWarnings("all")
  6. public class fanshe2 {
  7. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
  8. Class c = Class.forName("Student_table");
  9. Annotation[] annotation = c.getAnnotations();
  10. for (Annotation annotation1 : annotation) {
  11. System.out.println(annotation1);//@Table(value=Student_table)
  12. }
  13. Table t = (Table) c.getAnnotation(Table.class);
  14. System.out.println(t.value()); //Student_table
  15. Field f = c.getDeclaredField("id");
  16. Fields an = f.getAnnotation(Fields.class);
  17. System.out.println(an.columname()); //db_id
  18. System.out.println(an.len()); //10
  19. System.out.println(an.type()); //int
  20. }
  21. }
  22. @Target(value = ElementType.TYPE)
  23. @Retention(RetentionPolicy.RUNTIME)
  24. @interface Table{
  25. String value();
  26. }
  27. @Target(value = ElementType.FIELD)
  28. @Retention(RetentionPolicy.RUNTIME)
  29. @interface Fields{
  30. String columname();
  31. String type();
  32. int len();
  33. }
  34. @Table(value = "Student_table")
  35. class Student_table{
  36. @Fields(columname = "db_name",type="varchar",len = 3)
  37. private String name;
  38. @Fields(columname = "db_age",type="int",len = 10)
  39. private int age;
  40. @Fields(columname = "db_id",type="int",len = 10)
  41. private int id;
  42. public Student_table(String name, int age, int id) {
  43. this.name = name;
  44. this.age = age;
  45. this.id = id;
  46. }
  47. public String getName() {
  48. return name;
  49. }
  50. public void setName(String name) {
  51. this.name = name;
  52. }
  53. public int getAge() {
  54. return age;
  55. }
  56. public void setAge(int age) {
  57. this.age = age;
  58. }
  59. public int getId() {
  60. return id;
  61. }
  62. public void setId(int id) {
  63. this.id = id;
  64. }
  65. }

4.2 可定义成分

image.png

4.3 属性默认值

为属性给定默认值,的好处就是,使用注解的时候,不要求强制赋值,反射解析的时候可以使用默认值。

4.4 反射解析注解

五.类对象:

Class 对象 里面存的是类的所有信息
一个Class对象代表一个.class文件

5.1.获取:

  1. **1.通过类的对象,获取类对象**<br /> Student s1 = new Student();<br /> Class c = s1.getClass();<br /> **2.通过类名来获取类对象**<br /> Class c2 = Student.class;<br /> **3.通过静态方法来获取**<br /> Class c1 = Class.forName("包名+类名");

*常用的方法:

  1. static ClassforName(String name)返回指定类名的CLass对象<br /> getName()返回此Class对象所表示的实体类的名称<br /> getSimpleName() 返回实体类的简单名字<br /> Object newInstabce() 调用无参构造, 返回CLass 的对象的实例<br /> Class getSuperClass() 获取当前CLass对象的父类<br /> Class[] getInterfaces() 返回当前class对象的接口<br /> Constructor[] getConstructors() 返回构造器对象数组<br /> Method getMethod(String name, class..t)返回方法对象<br /> Field[] getFields() 返回cLass 对象所有公共的属性<br /> <br />获取类运行时的完整结构:<br /> Fields属性 method方法 constructor构造器 superClass父类 interfaces接口 Annotation注解 <br />类的对象:new 出来的<br /> <br />

反射:Reflection API 取得类的任何信息 并且直接操作任意对象的属性和方法

目标:理解class类 并获取Class实例,创建运行时类对象,获取运行时类的完整结构,调用运行时类的指定结构

  1. @SuppressWarnings("all")
  2. public class fanshe {
  3. public static void main(String[] args) {
  4. Class c1 = Object.class;
  5. Class c2 = Comparable.class;
  6. Class c3 = String[] .class;
  7. Class c4 = String[][].class;
  8. Class c5 = Annotation.class;
  9. Class c6 = ElementType.class;
  10. Class c7 = void.class;
  11. Class c8 = Class.class;
  12. System.out.println(c1);
  13. System.out.println(c2);
  14. System.out.println(c3);
  15. System.out.println(c4);
  16. System.out.println(c5);
  17. System.out.println(c6);
  18. System.out.println(c7);
  19. System.out.println(c8);
  20. //只要数组的维度是一样的 他们就是同一个Class
  21. }
  22. }
  1. <br />前置需求:<br />**动态语言**:在运行运行过程中可以改变接受的语言,如引进新的函数、对象、甚至是代码都可以改变程序运行时可以改变自身结构<br /> **javascript C# PHP Python**<br />**静态语言**:<br />与动态相反** java C C++** <br /> <br />java拥有了反射机制后 Java被称为准动态语言 但同时也增加了不安全性 有利有弊<br /> <br />Class c1 = Class.forName("包名+类名");<br />Class 加载完类之后,在内存的方法区就产生了Class类型的对象,一个类只有一个Class对象这个对象就包含了完整的类的信息,我们可以通过这个对象看到类的结构:就像一面镜子,透过这个镜子看到类的结构,我们称为反射<br /> java反射机制提供的功能:<br /> 在运行时是判断任意一个对象所属类<br /> 在运行时可以构建任意一- 个类的对象<br /> 在运行是判断任意一个类所具 有的成录变量和方法<br /> 在运行时获取泛型信息<br /> 在运行时调用任意的成员变量和方法<br /> 在运行时处理注释<br /> 生成动态代理<br /> <br />**优点**:可以实现动态创建对象和编译,体现出很大的灵活性<br />**缺点**:对性能有影响、使用反射基本上就是一种解释操作, 我们可以告诉jvm,我们希望做什么并且它满足<br /> 我们的要求。这类操作总是慢于直接操作<br /> 反射的主要API:<br /> java. Lang.Class :代表一个类<br /> java. Lang. reflect . Method:代表类的方法I<br /> java. lang.reflect. Field:代表类的成员变量
  1. import com.sun.xml.internal.bind.v2.runtime.reflect.opt.Const;
  2. import java.lang.annotation.Annotation;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.reflect.Constructor;
  5. import java.lang.reflect.Field;
  6. import java.lang.reflect.InvocationTargetException;
  7. import java.lang.reflect.Method;
  8. @SuppressWarnings("all")
  9. class method{
  10. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException {
  11. Class cq = Class.forName("zhuejie");
  12. System.out.println("注解类:"+cq.getName());
  13. Field[] fields1 = cq.getFields();//这个只能找到 公共的
  14. for (Field field : fields1) {
  15. System.out.println("公共的字段"+field);
  16. }
  17. Field[] fields = cq.getDeclaredFields();//这个能找到全部的
  18. for (Field field:fields) {
  19. System.out.println("全部字段"+field);
  20. }
  21. System.out.println("========================");
  22. Field f1 = cq.getDeclaredField("name");
  23. System.out.println("获取指定的字段"+f1);
  24. System.out.println("========================");
  25. Method[] methods1 = cq.getMethods();//公共方法 本类及其父类所有的公共方法
  26. for (Method method : methods1) {
  27. System.out.println("公共方法"+method);
  28. }
  29. Method[] methods = cq.getDeclaredMethods();
  30. for (Method method:methods) {
  31. System.out.println("本类的所有方法"+method);
  32. }
  33. Method m1 = cq.getDeclaredMethod("m3");
  34. System.out.println("获取指定的方法:"+m1);
  35. System.out.println("========================");
  36. System.out.println("获取构造器");
  37. Constructor[] constructor = cq.getConstructors();
  38. for (Constructor cons: constructor ) {
  39. System.out.println("公共的构造器"+cons);
  40. }
  41. Constructor[] constructors1 = cq.getDeclaredConstructors();
  42. for (Constructor con1 : constructors1) {
  43. System.out.println("所有的构造器:"+con1);
  44. }
  45. Constructor con3 = cq.getConstructor(String.class,String.class);
  46. System.out.println("指定的构造器"+con3);
  47. }
  48. }
  49. @SuppressWarnings("all")
  50. class method2{
  51. public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
  52. Class c1 = Class.forName("zhuejie");
  53. System.out.println("========================");
  54. System.out.println("通过反射构建对象");
  55. zhuejie z = (zhuejie)c1.newInstance();//调用无参构造创建对象 , 必须要有无参构造
  56. System.out.println(z.toString());
  57. System.out.println("========================");
  58. System.out.println("有参构造创建对象");
  59. Constructor con = c1.getConstructor(String.class,String.class);
  60. zhuejie z1 = (zhuejie) con.newInstance("yangqin","male");
  61. System.out.println(z1);
  62. System.out.println("========================");
  63. System.out.println("通过反射获取指定方法");
  64. zhuejie z2 = (zhuejie) c1.newInstance();
  65. Method setage = c1.getDeclaredMethod("setAge", int.class);
  66. setage.invoke(z2,12);
  67. System.out.println(z2.getAge());
  68. System.out.println("========================");
  69. System.out.println("通过反射对字段赋值");
  70. zhuejie z3 = (zhuejie)c1.newInstance();
  71. Field field = c1.getDeclaredField("name");
  72. field.setAccessible(true);//不能直接操作私有属性 需要关闭安全检测 设置setAccessible为true
  73. field.set(z3,"杨钦");
  74. System.out.println(z3.getName());
  75. /*
  76. * setAccessible(true)
  77. * 方法 属性 构造器 都有此方法
  78. * 提高反射效率 如果代码中必须使用反射,且频繁调用 则设为true
  79. * 使原本私有化的成员 可以访问
  80. * 反射非常影响效率
  81. * */
  82. }
  83. }
  84. @SuppressWarnings("all")
  85. class Three_sort{
  86. public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  87. t1();
  88. t2();
  89. t3();
  90. }
  91. public static void t1(){
  92. zhuejie z = new zhuejie();
  93. long before = System.currentTimeMillis();
  94. for (int i = 0; i < 1000000000; i++) {
  95. z.getAge();
  96. }
  97. long end = System.currentTimeMillis();
  98. System.out.println("普通方法执行时间:"+(end-before)+"ms");
  99. }
  100. public static void t2() throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
  101. zhuejie z1 = new zhuejie();
  102. Class c1 = z1.getClass();
  103. Method method = c1.getDeclaredMethod("setAge", int.class);
  104. long before = System.currentTimeMillis();
  105. for (int i = 0; i < 1000000000; i++) {
  106. method.invoke(z1,12);
  107. }
  108. long end = System.currentTimeMillis();
  109. System.out.println("反射方法执行时间:"+(end-before)+"ms");
  110. }
  111. public static void t3() throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
  112. zhuejie z2 = new zhuejie();
  113. Class c1 = z2.getClass();
  114. Method method = c1.getDeclaredMethod("setAge", int.class);
  115. method.setAccessible(true);
  116. long before = System.currentTimeMillis();
  117. for (int i = 0; i < 1000000000; i++) {
  118. method.invoke(z2,18);
  119. }
  120. long end = System.currentTimeMillis();
  121. System.out.println("关闭安全方法执行时间:"+(end-before)+"ms");
  122. }
  123. }
  124. class zhuejie{
  125. private String name;
  126. private int age;
  127. public String getName() {
  128. return name;
  129. }
  130. public void setName(String name) {
  131. this.name = name;
  132. }
  133. public int getAge() {
  134. return age;
  135. }
  136. public void setAge(int age) {
  137. this.age = age;
  138. }
  139. }

类加载机制【面试题】

2.1、类加载器

  类加载器(ClassLoader),顾名思义,即加载类的东西。在我们使用一个类之前,JVM需要先将该类的字节码文件(.class文件)从磁盘、网络或其他来源加载到内存中,并对字节码进行解析生成对应的Class对象,这就是类加载器的功能。我们可以利用类加载器,实现类的动态加载。

2.2、双亲委派机制

  在Java中,采用双亲委派机制来实现类的加载。那什么是双亲委派机制?在Java Doc中有这样一段描述:
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine’s built-in class loader, called the “bootstrap class loader”, does not itself have a parent but may serve as the parent of a ClassLoader instance.
从以上描述中,我们可以总结出如下四点:
1、类的加载过程采用委托模式实现
2、每个 ClassLoader 都有一个父加载器。
3、类加载器在加载类之前会先递归的去尝试使用父加载器加载。
4、虚拟机有一个内建的启动类加载器(bootstrap ClassLoader),该加载器没有父加载器,但是可以作为其他加载器的父加载器。
15.反射与注解 - 图2

根类加载器(bootstrap class loader):它用来加载 Java 的核心类,是用原生代码来实现的,并不继承自 java.lang.ClassLoader(负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

扩展类加载器(extensions class loader):它负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现,ExtClassLoader的父加载器为Bootstrp loader。

系统类加载器(app class loader):被称为系统(也称为应用)类加载器,它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。

如果所有的类加载都都无法加载这包ClassNotFoundException

2.3、类生命周期

15.反射与注解 - 图3

  • 加载 : 类加载器加载字节码流
  • 验证 : 验证字节码合法性
  • 准备 : 分配静态资源空间
  • 解析 : 引用替换(符号引用替换地址直接引用)
  • 初始化:赋值
  • 使用:创建对象或者访问静态属性方法
  • 卸载:移除
  1. Class cls = Class.forName("com.yq.jdbc.entity.User");
  2. // Field[] fields = cls.getDeclaredFields();
  3. // for (int i = 0; i < fields.length; i++) {
  4. // System.out.println(fields[i].getType().getSimpleName()+"\t"+fields[i].getName());
  5. // getType 会获得class java.lang.Integer
  6. // .getType().getSimpleName() 就会获得他的简单名 Integer
  7. // fields[i].getName() 获得字段名
  8. // }
  9. //
  10. //
  11. //
  12. // 代理访问属性
  13. //
  14. // Class cls2 = Class.forName("com.yq.jdbc.entity.User");
  15. // //获得的指定字段
  16. // Field fd = cls2.getDeclaredField("username");
  17. // fd.setAccessible(true);
  18. // fd.set(cls2,"dml".toString());
  19. // System.out.println(fd.get(cls2));