注解与反射

内置注解

@Override

表示一个方法被重写,如果加了会首先检查父类是否有这个方法如果没有则会报错

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Deprecated

用于修辞方法、属性、类表示此方法已经废弃,暂时可用,后期可能会删除,建议后来人不要调用此类方法

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

@SuppressWarnings

用于抑制编译时的警告信息

使用时需要添加参数:

@SuppressWarnings(“all”)

@SuppressWarnings(“unchekced”)

@SuppressWarnings("value={“unchekced,“deprecation”}”)

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})  // 可作用范围
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();   // 表示传参
}

元注解

负责注解其他的注解,Java 定义了 4 个标准的 meta-annotation 类型,他们被用来提供对其他 annotation 类型做说明

@Target

用于描述注解的使用范围

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Retention

表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

@Document

说明该注解将被包含在 javadoc 中

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inheriteed

说明子类可以继承父类中的该注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

自定义注解

使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口

public class Demo1 {
    // 注解可以显示赋值,如果没有默认值,我们必须给注解赋值
    @MyAnnotation2(name = "xiong")
    public void test(){}

    @MyAnnotation3("value可以省略不写")
    public void test2(){}
}

@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    // 注解的参数: 参数类型 + 参数名 ()
    String name();
    String value() default "xinq";
    int id() default -1; // 如果默认值为 -1,代表不存在
    String[] school() default {"清华大学","北京大学"};
}

@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    // 只有参数名为 value 时,注解中 value 可以省略
    String value();
}

反射机制

Reflection(反射)时 Java 被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

优点

可以实现动态创建对象和编译,体现出巨大的灵活性

缺点

对性能有影响。使用反射基本上是一种解释操作,我们可以告诉 JVM,我们希望做什么并且他满足我们的要求。

public class Reflect {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过反射获取类的 class 对象
        Class aClass = Class.forName("zhujie.User");
        Class aClass1 = Class.forName("zhujie.User");
        System.out.println(aClass);
        // 一个类在内存中只有一个 class 对象
        // 一个类加载后,类的整个结构都会被封装在 calss 对象中
        System.out.println(aClass.equals(aClass1)); // 输出 true

    }
}

class User{

    private String name;
    private String password;
    private int age;

    public User(){}

    public String getName() {
        return name;
    }

    public String getPassword() {
        return password;
    }

    public int getAge() {
        return age;
    }

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

    public void setPassword(String password) {
        this.password = password;
    }

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

Class 类

  • Class 本身也是一个类
  • Class 对象只能有系统建立对象
  • 一个加载的类在 JVM 中只会有一个 Class 实例
  • 一个 Class 对象对应的是一个加载到 JVM 中的一个 class 文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过 Class 可以完整的得到一个类的所有被加载的结构
  • Class 类是 反射 的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class 对象

常用方法

static ClassforName(String name)返回指定类名 name 的 Class 对象
Object newInstance()调用缺省构造函数,返回 class 对象的一个实例
getName()返回此 Class 对象所表示的实体(类,接口,数组类或 void)的名称
Class getSuperClass()返回当前 class 对象的父类 class 对象
Class[] getinterface()获取当前 class 对象的接口
ClassLoader getClassLoader()返回该类的类加载器
Constructor[] getConstructors()返回一个包含某些 construct 对象的数组
Method getMethod(String name,Class… T)返回一个 Method 对象,此对象的形参类型为 ParamType
Field[] getDeclaredField()返回 Field 对象的一个数组

获取 Class 的实例

  • 若已知具体的类,通过 class 属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class
  • 已知某个类的实例,调用该实例的 getClass() 方法获取 class 对象
Class clazz = person.getClass();
  • 已知一个类的全类名,且该类在类路径下,可以通过 class 类的静态方法 forName() 获取
Class clazz = Class.forName("demo01.Student");
  • 内置基本数据类可以直接用 类名.Type
  • 还可以使用 ClassLoader
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        // 通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        // 通过forname 获得
        Class c2 = Class.forName("zhujie.Student");
        System.out.println(c2.hashCode());
        // 通过 类名.class
        Class c3 = Student.class;
        System.out.println(c3.hashCode());

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

        // 获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}

class Person{

    public String name;

    public Person(String name) {
        this.name = name;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

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

class Student extends Person{
    public Student() {
        this.name = "学生";
    }
}

class Teacher extends Person{
    public Teacher(String name) {
        this.name = "老师";
    }
}

所有类型的 Class

public class Test02 {
    public static void main(String[] args) {
        Class c1 = Object.class;        // 类
        Class c2 = Comparable.class;    // 接口
        Class c3 = String[].class;      // 一维数组
        Class c4 = int[][].class;       // 二维数组
        Class c5 = Override.class;      // 注解
        Class c6 = ElementType.class;   // 枚举
        Class c7 = Integer.class;       // 包装类
        Class c8 = void.class;          // void
        Class c9 = Class.class;         // 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);
        System.out.println(c9);
    }
}
/* 输出
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
*/

类的加载过程

占坑

获得类的信息

public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c1 = Class.forName("zhujie.User");

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

        // 获得类的属性
        Field[] fields = c1.getFields();    // 只能获得 public 属性

        fields = c1.getDeclaredFields();    // 获得所有属性
        for (Field field : fields){
            System.out.println(field);
        }

        // 获得类的方法
        Method[] methods = c1.getMethods(); // 获得本类或者父类的 public 方法
        for (Method method : methods){
            System.out.println("正常:"+method);
        }

        methods = c1.getDeclaredMethods();  // 获得本类所有方法
        for (Method method : methods){
            System.out.println("getDeclaredMethods:"+method);
        }

        // 获得指定方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        // 获得指定的构造器
        Constructor[] constructors = c1.getConstructors();  // 获得 public
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        constructors = c1.getDeclaredConstructors();    // 获得全部
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        // 获得指定 填入参数类型的 class
        Constructor constructor = c1.getDeclaredConstructor(String.class, String.class, int.class);
        System.out.println(constructor);
    }
}

反射的使用

public class Test05 {
    //动态创建对象
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = Class.forName("zhujie.User");

        // 构造一个的对象
        User user = (User)c1.newInstance();
        System.out.println(user);

        // 通过构造器创建
        Constructor constructor = c1.getDeclaredConstructor(String.class, String.class, int.class);
        User user1 = (User)constructor.newInstance("xiong", "mao", 12);
        System.out.println(user1.getName());

        // 通过反射调用普通方法
        User user3 = (User)c1.newInstance();
        // 通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        // invoke(对象,参数) 激活此方法
        setName.invoke(user3, "xiongmao");
        System.out.println(user3.getName());

        // 通过反射操作属性
        User user4 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        // 无法直接操作私有属性
        // name.set(user4, "XiongMaoHei");
        // 报错:
        // Class zhujie.Test05 can not access a member of class zhujie.User with modifiers "private"
        name.setAccessible(true);   // 设置可访问
        name.set(user4, "XiongMaoHei");
        System.out.println(user4.getName());
    }
}

性能测试

public class Test06 {
    // 普通方法调用
    public static void test01(){
        User user = new User();

        long startTime = System.currentTimeMillis();
        for (long i = 0; i < 10_0000_0000L; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法执行10亿次"+(endTime-startTime));
    }

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

        long startTime = System.currentTimeMillis();
        for (long i = 0; i < 10_0000_0000L; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法调用执行10亿次"+(endTime-startTime));
    }

    // 反射方法调用 设置可访问
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName",null);
        getName.setAccessible(true);

        long startTime = System.currentTimeMillis();
        for (long i = 0; i < 10_0000_0000L; i++) {
            getName.invoke(user, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法调用执行10亿次"+(endTime-startTime));
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }
}
// 输出:
普通方法执行10亿次622
反射方法调用执行10亿次2853
反射方法调用执行10亿次1621

开启访问权限可以有效提高反射调用的效率

通过反射获取泛型

public class Test07 {
    // 通过反射获取泛型
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test07.class.getMethod("test01", Map.class, List.class);

        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes){
            System.out.println("###"+genericParameterType);
            if(genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments){
                    System.out.println(actualTypeArgument);
                }
            }

        }
        method = Test07.class.getMethod("test02", null);
        Type genericReturnType = method.getGenericReturnType();
        if(genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments){
                System.out.println("return: "+actualTypeArgument);
            }
        }

    }

    public void test01(Map<String, User> map, List<User> list){
        System.out.println("test1");
    }

    public Map<String, User> test02(){
        System.out.println("test2");
        return null;
    }
}

获取注解信息

/**
 * 尝试写一个与数据库相关的映射注解
 */
public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("zhujie.Student2");

        // 通过反射活获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        // 获得注解 value 值
        MyTable myTable = (MyTable) c1.getAnnotation(MyTable.class);
        String value = myTable.value();
        System.out.println(value);

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

@MyTable("db_student")
class Student2{
    @MyField(columnName = "db_id", type = "int", length = 10)
    private int id;
    @MyField(columnName = "db_age", type = "int", length = 10)
    private int age;
    @MyField(columnName = "db_name", type = "int", length = 10)
    private String name;

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

    public Student2() {
    }

    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;
    }
}

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

// 属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyField{
    String columnName();
    String type();
    int length();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值