Java中的注解与反射(笔记)

一、注解

1、注解(Annotation)是什么?

  • Annotation是从JDK5.0开始引入的新技术。
  • Annotation的作用: 不是程序本身,可以对程序作出解释。可以被其他程序(比如编译器等)读取。
  • Annotation的格式: 注解是"@注释名"在代码中存在的,还可以添加一些参数值。

2、内置的注解

  • @Override:用作修辞方法,表示一个方法声明打算重写超类中的另一个声明
  • @Deprecated:不推荐使用,但是可以使用,或存在更好的方式。
  • @SuppressWarnings: 用来抑制编译时的警告信息,必须要添加参数。

//SuppressWarnings 用来抑制编译时的警告信息,必须要添加参数
@SuppressWarnings("all")
public class test1 extends parent{
    
    
    public static void main(String[] args) {
    
    
    }
    //Override 重写的注解
    @Override
    public void test1() {
    
    
        super.test1();
    }
    //Deprecated 不推荐使用,但是可以使用,或存在更好的方式。
    @Deprecated
    public static void test2(){
    
    
        System.out.println("这是Deprecated");}
}

3、元注解
元注解的作用就是负责注解其他注解, Java定义了4个标准的meta -annotation类型,他们被用来
提供对其他annotation类型作说明 。

  • @Target :用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
  • @Retention :表示需要在什么级别保存该注释信息,用于描述注解的生命周期 (SOURCE < CLASS < RUNTIME)
  • @Document:说明该注解将被包含在javadoc中
  • @Inherited: 说明子类可以继承父类中的该注解
public class Test2 {
    
    
    @MyAnnotation
    public void test(){
    
    

    }
}

//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {
    
    ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@interface  MyAnnotation{
    
    

}

4、自定义注解

  • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
  • @ interface用来声明一个注解,格式: public @ interface注解名{定义内容}。
  • 其中的每一个方法实际上是声明了一个配置参数。
  • 方法的名称就是参数的名称。
  • 返回值类型就是参数的类型(返回值只能是基本类型,Class , String , enum )。
  • 可以通过default来声明参数的默认值。
  • 如果只有一一个参数成员, - -般参数名为value。
  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值。
public class Test3 {
    
    
    //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值。
    @MyAnnotation2(age=23)
    public void test1(){
    
    

    }

}
@Target({
    
    ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    
    
    //注解的参数:参数类型+参数名();
    String name() default "";
    int age();

}

二、反射

1.什么是反射?
反射指的是我们可以在运行期间加载、探知、使用编译期间完全未知的类。是一个动态的机制,允许我们通过字符串来指挥程序实例化,操作属性、调用方法。使得代码提高了灵活性,但是同时也带来了更多的资源开销。
加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。

2、如何获取反射的类?
先创建个User实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private String id;
    public String name;
    private Integer age;
}

通过三种方法获取到

//获取反射
public class Test1 {
    
    
    //通过Class.forName()获取(最常用)
    public static void main(String[] args) {
    
    
        try {
    
    
            Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
        //通过getClass()获取
        User  user = new User();
        Class aClass1 = user.getClass();

        //通过.class来获取
        Class<User> userClass = User.class;
    }
}

2、如何使用反射?

  • 获取类名、变量、字段、还有方法
public class Test2 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取全类名
        String name = aClass.getName();
        System.out.println(name);
        //获取简单类名
        String simpleName = aClass.getSimpleName();
        System.out.println(simpleName);
        //获取类的字段、某些变量
        //获取该类的所有public字段,包括父类的
        Field[] fields = aClass.getFields();
        for ( Field field: fields ){
    
    
            System.out.println(field.getName());
        }
        //根据字段名获取该类的public字段
        Field name1 = aClass.getField("name");
        //根据字段名获取该类的字段
        aClass.getDeclaredField("age");


    }
 Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取该类的所有public方法,包括父类的
        Method[] methods = aClass.getMethods();
        //根据方法名获取该类的public方法
        Method method = aClass.getMethod("getName");

        //如果该类为重写方法,可以在第二个参数加上重写方法的参数类型,不写为无参数的方法
        Method paramMethod = aClass.getMethod("getName",String.class);

        //获取该类的所有方法,不包括父类(仅自定义)
        Method[] declaredMethods = aClass.getDeclaredMethods();
        //根据方法名获取该类的方法
        Method declaredMethod = aClass.getDeclaredMethod("getName");
    }
  • 获取类的构造器
//获取类的构造器
public class Test4 {
    
    
    public static void main(String[] args) throws Exception {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取该类的所有构造器,包括父类
        Constructor[] constructors = aClass.getConstructors();

        //根据构造器的参数类型来获取指定构造器,不写为无参构造器
        Constructor constructor = aClass.getConstructor();
        Constructor constructor1 = aClass.getConstructor(String.class,int.class);

        //获取该类的所有构造器,不包括父类
        Constructor[] declaredConstructors = aClass.getDeclaredConstructors();

        //根据构造器的参数类型来获取指定的自定义构造器,不写为无参构造器
        Constructor declaredConstructor = aClass.getDeclaredConstructor();
        Constructor declaredConstructor1 = aClass.getDeclaredConstructor(String.class, int.class);

    }
}
  • 实例化一个类
//类的实例化
public class Test5 {
    
    
    public static void main(String[] args) throws Exception {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //通过class类直接实例化,使用的是User类的无参构造器
        User user = (User) aClass.newInstance();
        //获取构造器来进行实例化,这里获取有参构造器
        Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class,String.class,Integer.class);
        //根据构造器进行实例化
        User user1 = (User) declaredConstructor.newInstance("12", "admin",44);
        System.out.println(user1);
    }
}
  • 运行结果

在这里插入图片描述

  • 使用发射来调用方法
public class Test6 {
    
    
    public static void main(String[] args) throws Exception{
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        User user = (User) aClass.newInstance();
        Method setName = aClass.getMethod("setName", String.class);
        //第一个是调用底层方法的对象,也就是通过哪个对象来调用方法
        //第二个为可变参数,是用于方法调用的参数
        setName.invoke(user,"admin1");
        System.out.println(user);
    }
}
  • 运行结果
    在这里插入图片描述
  • 使用反射修改字段的值(使用id.setAccessible(true)跳过安全检查)
public class Test7 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");

        User o = (User) aClass.newInstance();
        Field id = aClass.getDeclaredField("id");
        //使用id.setAccessible(true)跳过安全检查
         id.setAccessible(true);
        //第一个参数为修改的字段的对象
        //第二个为被修改字段的新值
        id.set(o,"123");
        System.out.println(o);
    }
}
  • 运行结果
    在这里插入图片描述

3、注解与反射的使用

  • 注解是之前创建的一个自定义注解
//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {
    
    ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
public @interface  MyAnnotation{
    
    
     String name() default "";
}
  • 要拿注解的值,先利用反射获取到注解修饰的那个类,然后通过调用***getDeclaredAnnotation(注解名字.class)***才能获取到注解的值。
//注解与反射
public class Test8 {
    
    

    public static void main(String[] args) throws Exception {
    
    
        Class aClass = Class.forName("com.example.dci.annotation.test1");
        Method test1 = aClass.getDeclaredMethod("test2");
        MyAnnotation declaredAnnotation = test1.getDeclaredAnnotation(MyAnnotation.class);
        String value = declaredAnnotation.name();
        System.out.println(value);


    }

}

猜你喜欢

转载自blog.csdn.net/lzfaq/article/details/122105249