注解和反射(一)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 注解和反射

注解

1. 什么是注解

Annotation是从JDK5.09开始引入的新技术

Annotation的作用:

  • 不是程序本身,可以对程序做出解释
  • 可以被其他程序(如编译器等)读取
  • 例如:JUint框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

Annotation的格式:注解以@注释名在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked")

Annotation在哪里使用:可以附加在package,class,method,filed等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。

2. 内置注解

  • @Override:定义在java.lang.Override中,此注释只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明。
  • @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修饰方法,属性,类;表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择。
  • @SuppressWarnings:定义在java.langSuppressWarnings中,用来抑制编译时的警告信息。与前两个不同,这里需要添加一个参数才能正确的使用,这些参数都是已经定义好的,可以选择:
@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings(value={"uncheched","deprecation"})
等等。。。

例:

import java.util.ArrayList;
import java.util.List;
//镇压所有警告
@SuppressWarnings("all")
public class Test01 extends Object {
    //重写的注解
    @Override
    public String toString() {
        return super.toString();
    }
    //不推荐程序员使用。但是可以使用,或者存在更好的方式
    @Deprecated
    public static void test() {
        System.out.println("Deprecated");
    }
    //镇压test02()的警告
    @SuppressWarnings("all")
    public void test02(){
        List list = new ArrayList();
    }
    public static void main(String[] args){
        test();
    }
}

3. 元注解和自定义注解

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

这些类型和它们所支持的类在java.lang.annotation包中可以找到。

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

MyTest.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//定义一个注解
@Target({ElementType.METHOD, ElementType.FIELD})   //注解的使用范围:方法,成员变量
@Retention(RetentionPolicy.RUNTIME)                //注解的生命周期:一直活着,在运行阶段这个注解也不消失
@interface MyTest {
}
//目标:认识元注解
//@MyTest  //报错,因为只能注解方法和成员变量
public class AnnotationDemo2 {
    @MyTest
    private String name;
    @MyTest
    public void test(){
    }
    public static void main(String[] args) {
    }
}

自定义注解格式:

public @interface 注解名称{
    public 属性类型 属性名() default 默认值;
}

例:

AnnotationDemo1.java

public @interface MyBook {
    String name();
    String[] authors();
    double price();
}
//目标:自定义注解
@MyBook(name="《精通JavaSE》", authors = {"zdb", "zzz"}, price = 199)
public class AnnotationDemo1 {
    @MyBook(name="《精通JavaSE》", authors = {"zdb", "zzz"}, price = 199)
    private AnnotationDemo1(){
    }
    @MyBook(name="《精通JavaSE》", authors = {"zdb", "zzz"}, price = 199)
    public static void main(String[] args) {
        @MyBook(name="《精通JavaSE》", authors = {"zdb", "zzz"}, price = 199)
        int age = 21;
    }
}

注意:如果注解只有一个属性的情况下,使用value表示,使用时可以省略value名称不写。但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation03{
    String value();
}
public class Test03 {
    //这里参数可以省略value=
    @MyAnnotation03("122")
    public void test(){}
}


注解的解析:注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。

bookk.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface bookk {
    String value();
    double price() default 100;
    String[] author();
}

AnnotationDemo3.java

import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
@bookk(value = "<情深深雨濛濛>", price = 99.9, author = {"zzz", "aaa"})
class BookStore{
    @bookk(value = "<三少爷的剑>", price = 22, author = {"zzz", "aaa"})
    public void test(){
    }
}
//目标:完成注解的解析
public class AnnotationDemo3 {
    @Test
    public static void main(String[] args) throws NoSuchMethodException {
        //1. 先得到类对象
        Class c = BookStore.class;
        Method m = c.getDeclaredMethod("test");
        //2. 判断这个类上面是否存在这个注解
        if(c.isAnnotationPresent(bookk.class)){
            //3. 直接获取该注解对象
            bookk book = (bookk)c.getDeclaredAnnotation(bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }
}
<情深深雨濛濛>
99.9
[zzz, aaa]


反射

1. 概述

Java不是动态语言,但Java可称之为准动态语言,可以通过反射机制获得类似动态语言的特性。动态语言是一类在运行时可以改变其结构的语言。

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

加载完类之后,在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。

例:Class c = Class.forName("java.lang.String");

正常方式:引入需要的包类名称->通过new实例化->取得实例化对象

反射方式:实例化对象->getClass()方法->得到完整的包类名称

反射是指对于任何一个Class类,在运行的时候都可以直接得到这个类全部成分。

在运行时,可以直接得到这个类的构造器对象:Constructor

在运行时,可以直接得到这个类的成员变量对象:Field

在运行时,可以直接得到这个类的成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

反射的基本作用:反射是在运行时获取类的字节码文件对象,然后可以解析类中的全部成分。反射的核心思想和关键就是:得到编译以后的class文件对象


2. 获取Class类对象的三种方式

反射的第一步:获取Class类对象,如此才可以解析类的全部成分

//获取Class类的对象的三种方式:
Class c1 = Class.forName("类名");
Class c2 = 类名.class
Class c3 = 对象.getClass();

例:

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //1. Class类中的静态方法:forName(全限名:包名+类名)
        Class c = Class.forName("d2_reflect_class.Student");
        System.out.println(c);  //Student.class
        //2. 类名.class
        Class c1 = Student.class;
        System.out.println(c1);
        //3. 对象.getClass()获取对象对应类的Class对象
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    
    //4.获得父类类型
    Class c3 = c1.getSuperClass();
    }
}
class d2_reflect_class.Student
class d2_reflect_class.Student
class d2_reflect_class.Student

使用反射技术获取构造器对象并使用三部曲:



3. Class类的常用方法

例:

Student.java

package demo03;
public class Student {
    private String name;
    private char sex;
    private int age;
    private String className;
    private String hobby;
    public Student(){}
    public Student(String name, char sex, int age, String className, String hobby) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.className = className;
        this.hobby = hobby;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    public String getHobby() {
        return hobby;
    }
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

Test04.java

package demo03;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("demo03.Student");
        //获取类的名字
        System.out.println("c1.getName(): " + c1.getName());      //获得包+类名
        System.out.println("c1.getSimpleName(): " + c1.getSimpleName() + "\n");//获得类名
        //获取类的属性
        //只能找到public属性
        Field[] fields1 = c1.getFields();
        System.out.println("c1.getFields(): ");
        for(Field field : fields1){
            System.out.println(field);
        }
        //找到全部的属性,包括private
        fields1 = c1.getDeclaredFields();
        System.out.println("c1.getDeclaredFields(): ");
        for(Field field : fields1){
            System.out.println(field);
        }
        //获取指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println("\n" + "c1.getDeclaredField(\"name\"): " + name);
        //获得类的方法
        //获得本类及其分类的全部public方法
        Method[] methods = c1.getMethods();
        System.out.println("\n" + "c1.getMethods(): ");
        for (Method method : methods) {
            System.out.println(method);
        }
        //获得本类的所有方法(包括private),不获取父类
        methods = c1.getDeclaredMethods();
        System.out.println("\n" + "c1.getDeclaredMethods(): ");
        for (Method method : methods) {
            System.out.println(method);
        }
        //获得指定方法
        Method getName = c1.getMethod("getName", null);
        System.out.println("\n" + "c1.getMethod(\"getName\", null): " + getName);
        //获得构造器
        Constructor[] constructors =  c1.getConstructors();
        System.out.println("\n" + "c1.getConstructors(): ");
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        constructors =  c1.getDeclaredConstructors();
        System.out.println("\n" + "c1.getDeclaredConstructors(): ");
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        //获取指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, char.class, int.class, String.class, String.class);
        System.out.println("\n" + "c1.getDeclaredConstructor(): " + declaredConstructor);
    }
}
c1.getName(): demo03.Student
c1.getSimpleName(): Student
c1.getFields(): 
c1.getDeclaredFields(): 
private java.lang.String demo03.Student.name
private char demo03.Student.sex
private int demo03.Student.age
private java.lang.String demo03.Student.className
private java.lang.String demo03.Student.hobby
c1.getDeclaredField("name"): private java.lang.String demo03.Student.name
c1.getMethods(): 
public java.lang.String demo03.Student.getName()
public void demo03.Student.setName(java.lang.String)
public java.lang.String demo03.Student.getClassName()
public int demo03.Student.getAge()
public char demo03.Student.getSex()
public void demo03.Student.setSex(char)
public java.lang.String demo03.Student.getHobby()
public void demo03.Student.setAge(int)
public void demo03.Student.setHobby(java.lang.String)
public void demo03.Student.setClassName(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
c1.getDeclaredMethods(): 
public java.lang.String demo03.Student.getName()
public void demo03.Student.setName(java.lang.String)
public java.lang.String demo03.Student.getClassName()
public int demo03.Student.getAge()
public char demo03.Student.getSex()
public void demo03.Student.setSex(char)
public java.lang.String demo03.Student.getHobby()
public void demo03.Student.setAge(int)
public void demo03.Student.setHobby(java.lang.String)
public void demo03.Student.setClassName(java.lang.String)
c1.getMethod("getName", null): public java.lang.String demo03.Student.getName()
c1.getConstructors(): 
public demo03.Student()
public demo03.Student(java.lang.String,char,int,java.lang.String,java.lang.String)
c1.getDeclaredConstructors(): 
public demo03.Student()
public demo03.Student(java.lang.String,char,int,java.lang.String,java.lang.String)
c1.getDeclaredConstructor(): public demo03.Student(java.lang.String,char,int,java.lang.String,java.lang.String)


反射为何可以给约定了泛型的集合存入其他类型的元素?

  • 编程成Class文件进入运行阶段的时候,泛型会自动擦除
  • 反射是作用在运行时的技术,此时已经不存在泛型了
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
//反射:突破泛型的约束
public class ReflectDemo {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //需求:反射实现泛型擦除后,加入其他类型的元素
        ArrayList<String> lists1 = new ArrayList<>();
        ArrayList<Integer> lists2 = new ArrayList<>();
        System.out.println(lists1.getClass());
        System.out.println(lists2.getClass());
        System.out.println(lists1.getClass() == lists2.getClass());   //true
        System.out.println("--------------------");
        ArrayList<Integer> lists3 = new ArrayList<>();
        lists3.add(23);
        lists3.add(22);
        //list.add("asdas");
        Class c = lists3.getClass();
        //定位c类中的add方法
        Method add = c.getDeclaredMethod("add", Object.class);
        boolean rs = (boolean)add.invoke(lists3, "黑马");  //是否添加成功
        System.out.println(rs);
        System.out.println(lists3);
    
    ArrayList list4 = lists3;    //true
    list4.add("白马");
    list4.add(false);
    }
}
class java.util.ArrayList
class java.util.ArrayList
true
--------------------
true
[23, 22, 黑马]

注解和反射(二)+https://developer.aliyun.com/article/1556636

目录
相关文章
|
10月前
66.【注解与反射】(二)
66.【注解与反射】
30 0
|
10月前
66.【注解与反射】(四)
66.【注解与反射】
26 0
|
2天前
|
Java 编译器
注解和反射(二)
注解和反射
7 0
|
10月前
|
Java
66.【注解与反射】(三)
66.【注解与反射】
31 0
|
10月前
66.【注解与反射】(一)
66.【注解与反射】
30 0
|
12月前
|
编译器
反射、注解和泛型相关的坑
泛型 类型擦除 桥接方法
|
12月前
|
编译器
反射、注解和泛型相关的坑
根据反射来获取方法,很多人觉得获取方法传入参数就可以了,但是遇到方法的重载的时候,怎么能够知道此次执行走的是哪个方法呢?
|
Oracle Java 关系型数据库
反射与自定义注解
反射与自定义注解
反射与自定义注解
|
编译器
注解与反射.1什么是注解?
注解与反射.1什么是注解?
|
程序员
注解和反射2.内置注解
注解和反射2.内置注解