Java注解和反射

一.注解Annotation

1.1 基本介绍

  • 注解Annotation是JDK5.0开始引入的技术
  • 作用:可以对程序进行解释,且能被其他程序识别读取
  • 格式:注解以“@注解名”,并可以添加一些参数,例如:@SuppressWarnings(value = “unchecked”),@Override
  • 作用域:可以附加再package,class,method,field等上面。我们可以通过反射机制实现对这些元数据的访问。

1.2 内置注解

  • @Override:表示一个方法声明打算重写超类中的另一个方法声明
  • @Deprecated:表示不鼓励程序员使用这样的元素
  • @SuppressWarnings:用来抑制编译时的警告信息,需要添加参数
    - @SuppressWarnings(“all”)
    - @SuppressWarnings(“unchecked”)
    - @SuppressWarnings(value={“unchecked”,“deprecation”})
    在这里插入图片描述

1.3 元注解

元注解用来对定义的注解进行说明

  • @Target:描述注解使用范围,可以用在什么范围,例如:方法上或类上
  • @Retention:用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
  • @Document:说明该注解将被包含在Javadoc中
  • @Inherited:说明子类可以继承父类的注解

1.4 自定义注解

  • 使用@interface声明注解,格式:public @interface 注解名 {定义内容}
  • 其中的每一个方法实际上是声明了一个配置参数
  • 方法的名称就是参数的名称
  • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
  • 可以通过 default 来声明参数的默认值
  • 如果只有一个参数成员,一般参数名为 value
  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0 作为默认值
  • 在这里插入图片描述
    在这里插入图片描述

二.反射Reflection

2.1 基本介绍

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
在这里插入图片描述
在这里插入图片描述

2.2 Class类

  • Class 本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在 JVM 中只会有一个 Class 实例
  • 一个 Class 对象对应的是一个加载到 JVM 中的一个 .class 文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过 Class 可以完整地得到一个类中的所有被加载的结构
  • Class 类是 Reflection 的根源,针对任何你想动态加载、运行的类、唯有先获得响应的 Class 对象
    哪些类型可以有Class类:
    class外部类,成员,局部内部类,匿名内部类;interface接口;[]数组;enum枚举;annotation注解;primitive type基本数据类型;void
    在这里插入图片描述

2.3 获取Class类的几种方式

在这里插入图片描述
(1)已知具体的类,通过类的class属性获取,该方法最安全可靠,程序性能最高。

Class clazz = Person.class;

(2)已知某个类的实例,调用getClass()方法获取Class对象

Class clazz = person.getClass();

(3)已知一个类的全类名,且该类在类的路径下,可通过forName()获取,可能抛出ClassNotFoundException

Class clazz = Class.forNmae("com.example.User2");

(4)内置基本数据类型可以直接用类名.Type

Integer.Type;

(5)利用ClassLoader

2.4 获取类的运行时结构

首先设定一个User2类
在这里插入图片描述

(1)获取类的属性

package com.example;

import java.lang.reflect.Field;

public class TextReflection {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的Class对象
        Class c1 = Class.forName("com.example.User2");

        //获取类的名字
        System.out.println(c1.getName());   //获得包名+类名
        System.out.println(c1.getSimpleName());    //获得类名

        System.out.println("----------------------------------");
        //获取类的属性
        Field[] fields = c1.getFields();    //getFields只能找到public属性
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("==================================");
        fields = c1.getDeclaredFields();    //getDeclaredFields能找到全部属性
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);
   }
}

在这里插入图片描述

(2)获取类的方法

package com.example;

import java.lang.reflect.Field;

public class TextReflection {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
   		//通过反射获取类的Class对象
        Class c1 = Class.forName("com.example.User2");
   		//获取类的方法
        Method[] methods = c1.getMethods(); //获得本类和父类全部public方法
        for (Method method : methods) {
            System.out.println("原本"+method);
        }

        methods = c1.getDeclaredMethods();  //获得本类所有方法
        for (Method method : methods) {
            System.out.println("Declared:"+method);
        }
        
		 //获取指定方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
   }
}

在这里插入图片描述
(3)获取类的构造器

package com.example;

import java.lang.reflect.Field;

public class TextReflection {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        //通过反射获取类的Class对象
        Class c1 = Class.forName("com.example.User2");
		//获取类的构造器
        Constructor[] constructors = c1.getConstructors();  //获取public构造方法
        for (Constructor constructor : constructors) {
            System.out.println("原:"+constructor);
        }

        constructors = c1.getDeclaredConstructors();        //获取全部构造方法
        for (Constructor constructor : constructors) {
            System.out.println("后:"+constructor);
        }

        //获取指定构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定"+declaredConstructor);
        
   }
}

在这里插入图片描述

2.5 动态创建对象执行方法

动态创建对象只能通过反射
(1)动态创建对象

package com.example;

public class TextReflection02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //获取Class对象
        Class c1 = Class.forName("com.example.User2");
        //构造一个对象
        User2 user2= (User2) c1.newInstance();//本质是调用了无参构造函数
        System.out.println(user2);
        
    }
}

此处修改了User2中无参构造函数为public,否注会报错
在这里插入图片描述
同时java9之后不推荐使用newInstance(),而是clazz.getDeclaredConstructor().newInstance()

package com.example;

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

public class TextReflection02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //获取Class对象
        Class c1 = Class.forName("com.example.User2");
        
        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User2 user = (User2) constructor.newInstance("bandit", 001, 18);
        System.out.println(user);

    }
}

在这里插入图片描述
(2)通过反射调用方法

package com.example;

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

public class TextReflection02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //获取Class对象
        Class c1 = Class.forName("com.example.User2");
        
        User2 user2 = (User2) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);

        //invoke:激活
        //(对象,“方法的值”)
        setName.invoke(user2,"bandit");
        System.out.println(user2.getName());
    }
}
        

在这里插入图片描述
(3)通过反射操作属性

package com.example;

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

public class TextReflection02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获取Class对象
        Class c1 = Class.forName("com.example.User2");
        User2 user2 = (User2) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.set(user2,"BANDIT");
        System.out.println(user2.getName());
    }
}

需要注意的是,上面会报错,因为name属性为private,所以需要关闭权限检测setAccessible(true);
在这里插入图片描述
关闭权限检测后:

package com.example;

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

public class TextReflection02 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获取Class对象
        Class c1 = Class.forName("com.example.User2");
        User2 user2 = (User2) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); 	//关闭权限检测
        name.set(user2,"BANDIT");
        System.out.println(user2.getName());
    }
}

在这里插入图片描述
成功输出

2.6 三种调用方法性能分析

package com.example;

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

public class text {
    //普通方法调用
    public static void test01(){
        User2 user2 = new User2();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user2.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方式10亿次:"+(endTime-startTime)+"ms");
    }

    //反射方法调用
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User2 user2 = new User2();
        Class c1 = user2.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user2,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方式10亿次:"+(endTime-startTime)+"ms");
    }

    //关闭权限检测反射
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User2 user2 = new User2();
        Class c1 = user2.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user2,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭检测后10亿次:"+(endTime-startTime)+"ms");
    }

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

在这里插入图片描述
setAccessible(true);可以提高反射效率

三.通过反射获取注解

首先定义两个注解

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableBandit{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldBandit{
    String columnName();
    String type();
    int length();
}

将注解应用到Student2类上

@TableBandit("db_Student")
class Student2{
    @FieldBandit(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldBandit(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldBandit(columnName = "db_name",type = "varchar",length = 3)
    private String name;

    public Student2() {
    }

    public Student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

获得指定注解值

package com.example;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class text01 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.example.Student2");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获取注解的value值
        TableBandit tableBandit = (TableBandit) c1.getAnnotation(TableBandit.class);
        System.out.println(tableBandit.value());

        //获得类指定注解
        Field field = c1.getDeclaredField("name");
        FieldBandit annotation = field.getAnnotation(FieldBandit.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }

}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值