Java注解与反射学习笔记

news/2024/5/19 6:03:35 标签: java, 反射

注解与反射

1.什么是注解

  • Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metada)与程序元素(类、方法、成员变量)进行关联。为程序的元素(类、方法。成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
  • Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明和配置的功能。注解不会影响代码的实际逻辑,仅仅起到辅助性的作用。包含在java.lang.annotation包中。

2.注解的用处

  1. 生产文档。这是最常见的,也是Java最早提供的注解,如@param@return等
  2. 跟踪代码依赖性,实现替代配置文件功能。比如Dragger 2依赖注入,未来Java开发,将大量注解配置,具有很大用处
  3. 在编译时进行格式检查。如@Override放在方法前,如果你这个方法并不是覆盖了超类的方法,则编译时就能检查出

3.内置注解

  • @Override:定义在java.lang.Override中,此注释只用于修饰方法,表示一个方法申明打算重写超类中的另一个方法声明。
  • @Deprecated:定义在java.lang.Deprcated中,此注释可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择。
  • @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告。
java">package com.chen.AnnotationTest;

public class InnerAnnotation {
   @Override
   public String toString(){
   return "override";
   }

   @Deprecated
   public static void test()
   {
       System.out.println("deprecated");
   }

   @SuppressWarnings("All")
    public void test1(int i)
    {
        int a;
    }
    public static void main(String[] args) {
        test();
    }
}

4.元注解

  • 元注解的作用是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来对其他annotation类型作说明
  • 这些类型和它们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited)
  • @Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
  • @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE<CALSS<RUNTIME)
  • @Documented:说明该注解被包含在javadoc中
  • @Inherited:说明子类可以继承父类中的该注解
java">package com.chen.AnnotationTest;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.SOURCE;

public class ElementTest {

@myAnnotation
public void test(){

    }
}

//作用范围:方法
@Target(value =METHOD )

//声明周期:源代码
@Retention(value = SOURCE)

//注解被包含在文档中
@Documented

//子类可以继承该注解
@Inherited
 @interface myAnnotation{
}

5.自定义注解

  • 使用@interface自定义注解时,自动继承了java.lang.Annotation接口
  • 分析:
    1. @interface用来声明一个注解,格式:public @interface 注解名{定义内容}
    2. 其中每一个方法实际上是生命了一个配置参数
    3. 方法的名称就是参数的名称
    4. 返回类型就是参数的类型(返回值只能是基本类型:Class,String,enum)
    5. 可以通过default来声明参数的默认值
    6. 如果只有一个参数成员,一般参数名为value
    7. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
java">package Test.example1;

import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class Test1 {

	@myAnnotation(name="xiaochen",id=1)
	public void test(){
		
	}
}

@Target(value= {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation{
	String name();
	int id();
	String[] school() default "";
}

6.理解反射

  • Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个类就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象称之为“反射”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeOhLD1F-1605353778709)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201029151444584.png)]

7.获得反射对象

java">package com.chen.AnnotationTest;

public class Test1 {
    public static void main(String[] args) {
        Class c1=null;
        Class c2=null;
        Class c3=null;
        Class c4=null;
        try
        {
            c1=Class.forName("com.chen.AnnotationTest.Demo");
            c2=Class.forName("com.chen.AnnotationTest.Demo");
            c3=Class.forName("com.chen.AnnotationTest.Demo");
            c4=Class.forName("com.chen.AnnotationTest.Demo");
        }
       catch (Exception e)
       {
           e.printStackTrace();
       }
        System.out.println(c1);
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

    }
}

class Demo{
    private int id;
    private String name;
}

8.获取Class类的几种方法

java">package com.chen.AnnotationTest;

//获取Class对象的多种方法
public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person p=new Student();
        System.out.println(p);

        //1.通过类名获取
        Class c1=Student.class;
        System.out.println(c1);

        //2.通过对象调用getClass()方法获取
        Class c2=p.getClass();
        System.out.println(c2);

        //3.通过Class.forName(类全路径名)获取
        Class c3=Class.forName("com.chen.AnnotationTest.Student");
        System.out.println(c3);

        //4.基本内置类型包装类的TYPE属性
        Class c4=Integer.TYPE;
        System.out.println(c4);

        //5.获取父类Class对象
        Class c5=c1.getSuperclass();
        System.out.println(c5);
    }
}

class Person{
    public String name;
    public Person()
    {

    }
    public Person(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="老师";
    }
}

9.可以有Class对象的类型

  • Class:外部类,成员(成员内部类、静态内部类、局部内部类、匿名内部类)
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void
java">package com.chen.AnnotationTest;

public class Test3 {

    public static void main(String[] args) {
        Class c1=Class.class;
        Class c2=String[].class;
        Class c3=int[][].class;
        Class c4=Comparable.class;
        Class c5=Override.class;
        Class c6=int.class;
        Class c7=void.class;
        Class c8=Enum.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);
    }


}

10.类的加载与ClassLoader的理解

  • 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象

  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程

    1. 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
    2. 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
    3. 解析:虚拟机常量池的符号引用(变量名)替换为直接引用(地址)的过程
  • 初始化:

    1. 执行类构造器()方法的过程。类似()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的(类构造器是构造类信息的,不是构造该类对象的构造器)

    2. 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化

    3. 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步

      代码示例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-upmtv94a-1605353778733)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201029234310756.png)]

java">package com.chen.AnnotationTest;

public class Test4 {
    public static void main(String[] args) {
        A a=new A();
        System.out.println(a.m);
    }
}

class A{
    static{
        System.out.println("A的静态初始代码块初始化");
        m=300;
    }
    static int m=100;
    public A(){
        System.out.println("A类无参构造器初始化");
    }
}

11.类的初始化

  • 类的主动引用(一定会发生类的初始化)

    1. 当虚拟机启动,先初始化main方法所在的类
    2. new一个类的对象
    3. 调用类的静态成员(除了final常量)和静态方法
    4. 使用java.lang.reflect包的方法对类进行反射调用
    5. 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
  • 类的被动引用(不会发生类的初始化)

    1. 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
    2. 通过数组定义类引用,不会触发此类的初始化
    3. 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

java">package com.chen.AnnotationTest;

public class Test5 {
    static {
        System.out.println("加载main()方法类");
    }

    public static void main(String[] args) throws ClassNotFoundException {
//主动引用
        //new 一个类对象
//        Son son=new Son();

        //调用静态成员
//        System.out.println(Son.s);

        //进行反射调用
//        Class.forName("com.chen.AnnotationTest.Son");

//被动引用
        //通过子类引用父类静态变量
//          System.out.println(Son.f);

        //通过数组定义类引用
//        Son[] sonArry=new Son[10];

        //引用常量
        System.out.println(Son.m);
    }
}

class Father{
    static int f=9;
    static{
        System.out.println("加载父类");
    }
}

class Son extends Father{

    static{
        System.out.println("加载子类");
    }
    static int s=8;
    final static int m=1;
}

12.类加载器

  • 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库。该加载器无法直接获取
  • 拓展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
  • 系统加载器:负责java -classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载类

java">package com.chen.AnnotationTest;

public class Test6 {
    public static void main(String[] args) throws ClassNotFoundException {

        //系统加载器
        ClassLoader cl=ClassLoader.getSystemClassLoader();
        System.out.println(cl);

        //拓展类加载器
        ClassLoader cl1=cl.getParent();
        System.out.println(cl1);

        //引导类加载器
        ClassLoader cl3=cl1.getParent();
        System.out.println(cl3);

        //测试当前类是哪个加载器加载的
        System.out.println(Class.forName("com.chen.AnnotationTest.Test6").getClassLoader());

        System.out.println(Class.forName("java.lang.String").getClassLoader());

        //获取系统类可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

13.获取类运行时的结构

  • 实现的全部接口
  • 所继承的父类
  • 全部的构造器
  • 全部的方法
  • 全部的Field
  • 注解

  • 带Declared ——public
  • 不带Declared ——当前类全部
java">package com.chen.AnnotationTest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test7 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1=Class.forName("com.chen.AnnotationTest.User");

        //获取类名
        System.out.println(c1.getName());

        System.out.println("====================================");
        //获取public 修饰的成员变量
        Field[] fields=c1.getFields();
        for(Field f : fields )
        {
            System.out.println(f);
        }
        //获取当前类中public 修饰的指定字段的值
        Field field=c1.getField("name");
        System.out.println(field);

        System.out.println("====================================");
        //获取全部成员变量
        fields=c1.getDeclaredFields();
        for(Field f : fields)
        {
            System.out.println(f);
        }
        //获取当前类指定字段值
        field=c1.getDeclaredField("position");
        System.out.println(field);

        System.out.println("========================================");
        //获取子类及其父类全部的 public 修饰的方法
        Method[] methods=c1.getMethods();
        for(Method m : methods)
        {
            System.out.println(m);
        }

        System.out.println("===========================================");
        //获取当前类全部的方法
        methods=c1.getDeclaredMethods();
        for(Method m : methods)
        {
            System.out.println(m);
        }

        System.out.println("===========================================");
        Constructor[] constructors=c1.getConstructors();
        for(Constructor c : constructors)
        {
            System.out.println(c);
        }

        System.out.println("===========================================");
        constructors=c1.getDeclaredConstructors();
        for(Constructor c : constructors)
        {
            System.out.println(c);
        }

    }


}

14.动态创建对象、执行方法、访问字段

java">package com.chen.AnnotationTest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test8 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1= Class.forName("com.chen.AnnotationTest.User");

        //通过反射创建对象
        User user=(User)c1.newInstance(); //实质上是调用无参构造器
        System.out.println(user);

        System.out.println("============================");
        //通过获取构造器创建对象
        Constructor constructor=c1.getConstructor(int.class,String.class);
        user=(User)constructor.newInstance(1,"xiaoChen");
        System.out.println(user);

        System.out.println("============================");
        //通过反射调用方法
        Method method=c1.getDeclaredMethod("setId", int.class);
        method.invoke(user,18);
        System.out.println(user);

        System.out.println("============================");
        //通过反射调用字段
        Field field=c1.getDeclaredField("id");
        field.setAccessible(true); //无访问权限必须开放 访问权限(方法,构造器同)
        field.set(user,22);
        System.out.println(user);
    }

}

15.性能对比分析

new 对象 —优于— 禁用安全访问开关的反射 —优于— 开启安全访问开关的反射

java">package com.chen.AnnotationTest;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test9 {
    private static void test01()
    {
        User user=new User(22,"xiaoChen");
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getId();
        }
        long endTime=System.currentTimeMillis();
        System.out.println("new 对象调用执行消耗时间:"+(endTime-startTime)+"ms");
    }

    private static void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        User user=new User();
        Class c1=user.getClass();
        Method method=c1.getDeclaredMethod("getId");
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            method.invoke(user);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("启用安全访问开关的 反射 调用执行消耗时间:"+(endTime-startTime)+"ms");
    }

    private static void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        User user=new User();
        Class c1=user.getClass();
        Method method=c1.getDeclaredMethod("getId");
        method.setAccessible(true);
        long startTime=System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            method.invoke(user);
        }
        long endTime=System.currentTimeMillis();
        System.out.println("禁用安全访问开关的 反射 调用执行消耗时间:"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        test01();
        test02();
        test03();
    }
}

16.获取泛型信息

  • ParameterizedType:表示一种参数化类型,比如Collection

  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

  • TypeVariable:是各种类型变量的公共父接口

  • WildcardType:代表一种通配符类型表达式

    java">package com.chen.AnnotationTest;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Test10 {
    
        public void test01(Map<Integer,String> map, List<String> list)
        {
    
        }
    
        public Map<Integer,String> test02()
        {
            return new HashMap();
        }
    
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class c1 = Class.forName("com.chen.AnnotationTest.Test10");
    
            //获取方法参数 泛型
            Method method01 = c1.getMethod("test01", Map.class, List.class);
            Type[] types = method01.getGenericParameterTypes();
            for (Type type : types) {
                System.out.println(type);
                if (type instanceof ParameterizedType) {
                    Type[] types02 = ((ParameterizedType) type).getActualTypeArguments();
                    for (Type type02 : types02) {
                        System.out.println(type02);
                    }
                }
            }
    
            System.out.println("============================");
            //获取方法返回值 泛型
            Method method = c1.getDeclaredMethod("test02");
    
            Type types02 = method.getGenericReturnType();
            if(types02 instanceof ParameterizedType)
            {
                Type[] types002=((ParameterizedType) types02).getActualTypeArguments();
                for(Type type : types002)
                {
                    System.out.println(type);
                }
            }
        }
    
    }
    
    

    获得注解信息

    java">package com.chen.AnnotationTest;
    
    import java.lang.annotation.*;
    import java.lang.reflect.Field;
    
    public class Test11 {
    
        public static void main(String[] args) throws Exception{
            Class c1=Class.forName("com.chen.AnnotationTest.Dog");
    
            //获取注解
            Annotation[] annotations=c1.getAnnotations();
            for(Annotation a : annotations)
            {
    
                System.out.println(a);
            }
    
            //获取类注解值
            Classchen a1=(Classchen)c1.getAnnotation(Classchen.class);
            System.out.println(a1.value());
    
            //获取字段注解值
            Field f=c1.getDeclaredField("id");
            Fieldchen f1=f.getAnnotation(Fieldchen.class);
            System.out.println(f1.name());
            System.out.println(f1.type());
            System.out.println(f1.length());
        }
    }
    @Classchen(value = "db_dog")
    class Dog{
        @Fieldchen(name = "db_id",type="int",length=10)
        private int id;
        @Fieldchen(name="db_name",type="varchar",length=5)
        private  String name;
        @Fieldchen(name="db_age",type="int",length=3)
        private int age;
        public Dog(int id,String name,int age)
        {
            this.id=id;
            this.name=name;
            this.age=age;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getId() {
            return id;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    @Target(value = ElementType.TYPE)
    @Retention(value = RetentionPolicy.RUNTIME)
    @interface Classchen{
        String value();
    }
    
    @Target(value = ElementType.FIELD)
    @Retention(value = RetentionPolicy.RUNTIME)
    @interface Fieldchen{
        String name();
        String type();
        int length();
    }
    

http://www.niftyadmin.cn/n/1846908.html

相关文章

QDU校内排位赛第三场 D 于老师发生什么事了 (字典树+逆序对)

题链&#xff1a;https://pintia.cn/problem-sets/1330210570443206656/problems/1330211663055204354 题目&#xff1a; 思路1&#xff1a;字典树思想&#xff0c;插入一个数时&#xff0c;如果当前这一位是0&#xff0c;那么&#xff0c;之前插入的这一位是1的数都与他构成逆…

基本dos命令学习笔记

基本dos命令 1.跳转目录 不同磁盘&#xff1a; C:\Users\Administrator>d:D:\>同一磁盘&#xff0c;不同文件夹&#xff1a; D:\>cd JAVATESTD:\JAVATEST>不同磁盘&#xff0c;不同文件夹&#xff1a; D:\JAVATEST>cd /d c:\Usersc:\Users>2.查看当前目…

[湖南大学程序设计实训训练作业一]2.错误的里程碑(进制转换问题!)

2.错误的里程碑【问题描述】【输入形式】【输出形式】【样例输入】【样例输出】题解思路分析代码一代码二【问题描述】 三月八日&#xff0c;小明买了台新车。但很快小明发现汽车的里程表有问题&#xff1a;里程表上每一位都不显示数字3和数字8&#xff0c;也就是说直接从数字…

Mysql学习笔记(十四)备份与恢复

原文:Mysql学习笔记&#xff08;十四&#xff09;备份与恢复学习内容&#xff1a; 1.数据库的重要数据备份... 2.什么时候需要使用到数据库备份.. 3.如何恢复备份的数据.. 1.备份&#xff1a; 说到备份&#xff0c;相比大家都不应该陌生&#xff0c;比如说我们平时在为我们的电…

QDU校内排位赛第三场 G 搞算法要以和为贵 (dp)

题链&#xff1a;https://pintia.cn/problem-sets/1330210570443206656/problems/1330211663055204355 题目&#xff1a; 思路&#xff1a; 唯一需要注意的是&#xff0c;有负数。 #include <bits/stdc.h> #define ll long long using namespace std; const ll mod 99…

[湖南大学程序设计实训训练作业一]3.拳王阿里

3.拳王阿里【问题描述】【输入形式】【输出形式】【样例输入】【样例输出】题解思路代码【问题描述】 阿里是上个世纪美国最著名的拳击手&#xff0c;阿里在20年的时间里多次获得重量级拳王称号。不过不幸的是&#xff0c;他在之后患上了帕金森氏病。他参加了许多比赛&#xff…

使用阿里云服务器的总结二-----目录权限

项目在本地windows上运行好好地&#xff0c;上传到linux系统上就各种权限问题&#xff0c;很是烦恼&#xff0c;当时就想&#xff1a;哪里有问题&#xff0c;哪里777~~~ 虽然这样当时是没有问题的&#xff0c;但是在安全性上是也就降低了&#xff0c;找了个时间找了一些资料&am…

QDU校内排位赛第三场 K 闪电鞭曲线

题链&#xff1a;https://pintia.cn/problem-sets/1330210570443206656/problems/1330211663051010048 题目&#xff1a; 思路&#xff1a;希尔伯特曲线&#xff0c;直接递归球即可。按主对角线对称&#xff0c;交换x&#xff0c;y&#xff1b;副对角线对称&#xff0c;假设正…