欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java基础--注解、反射

程序员文章站 2023-02-15 15:43:19
一、注解(Annotation) 1、什么是注解? 从JDK5开始,Java增加了Annotation(注解),Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。 2、Annotation与注释的区别: (1)Annotation不是程序本身,可以对 ......

一、注解(annotation)

1、什么是注解?

  从jdk5开始,java增加了annotation(注解),annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

2、annotation与注释的区别:

  (1)annotation不是程序本身,可以对程序进行解释,此处可以理解为注释。但是annotation可以被其他程序(比如编译器)读取,并进行处理。
  (2)注解与注释最大的区别就是注解存在被处理的流程,即注解是会被程序处理的。

3、注解的格式:

  (1)以 “@注释名” 的形式在代码中存在。
  (2)注解可以附加在程序元素( 包、类、构造器、方法、成员变量、参数、局域变量 )上面,为其添加额外的辅助信息,可以通过反射机制访问这些数据。
  (3)annotation不能运行,其只有成员变量,没有方法。annotation与public、final等修饰符地位类似,属于程序元素的一部分,但不能作为程序元素使用。

4、常见注解:

  (1)@override
    定义在java.lang.override中,此注释只用于修饰方法,表示重写一个父类的方法。

【举例:】
 @override
 public string tostring() {
     return "hello";
}

  (2)@deprecated

    定义在java.land.deprecated中,此注释可用于修饰方法、属性、类,表示该方法、类、属性不推荐使用(废弃)。在方法、类、属性上会有一条删除线(形如tostring())。

【举例:】
@deprecated
public string tostring() {
    return "timertaskdemo []";
}

  (3)@suppresswarnings
    定义在java.lang.suppresswarnings中,用来阻止编译时的警告信息。其使用时需要设置参数。

【参数为:】
deprecation,使用了过时的类或方法的警告。
unchecked,执行了未检查的转换时的异常,比如集合未指定泛型。
fallthrough,当在switch语句发生case穿透时的警告。
path,当类路径、源文件路径不存在时的警告。
serial,可序列化类缺少serialversionuid时的警告。
finally,任何finally不能完成时的警告。
all,以上所有警告。

【格式:】
@suppresswarnings("all")
或者
@suppresswarnings(value = { "serial", "unchecked" })

 

5、元注解:

  (1)元注解的作用就是负责注解其他的注解。java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。存在于java.lang.annotation中。

  (2)元注解分类:
    @target
    @retention
    @documented
    @inherited

  (3)@target元注解:
    用于描述注解的使用范围。annotation可被用于 packages、types(类、接口、枚举、annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在annotation类型的声明中使用了target可更加明晰其修饰的目标。

【格式:】
public @interface target
{
  elementtype[] value();
}

【参数:elementtype】
constructor:用于描述构造器
field:用于描述成员变量
local_variable:用于描述局部变量
method:用于描述方法
package:用于描述包
parameter:用于描述参数
type:用于描述类、接口(包括注解类型) 或enum声明

【举例:】
@target({java.lang.annotation.elementtype.type, java.lang.annotation.elementtype.field, java.lang.annotation.elementtype.method, java.lang.annotation.elementtype.parameter, java.lang.annotation.elementtype.constructor, java.lang.annotation.elementtype.local_variable})

  (4)@retention元注解:
    用于描述注解的声明周期。某些annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为annotation与class在使用上是被分离的)。使用这个meta-annotation可以对 annotation的“生命周期”限制。

【格式:】
public @interface retention
{
  retentionpolicy value();
}

【参数:retentionpoicy】
source:在源文件中有效(即源文件保留)
class:在class文件中有效(即class保留)
runtime:在运行时有效(即运行时保留,可以通过反射机制读取)

【举例:】
@retention(retentionpolicy.source)

  (5)@documented元注解:
    用于描述其它类型的annotation应该被作为被标注的程序成员的公共api,因此可以被例如javadoc此类的工具文档化。documented是一个标记注解,没有成员。

  (6)@inherited元注解:
    @inherited 元注解是一个标记注解,@inherited阐述了某个被标注的类型是被继承的。如果一个使用了@inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:
    @inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
    当@inherited annotation类型标注的annotation的retention是retentionpolicy.runtime,则反射api增强了这种继承性。如果我们使用java.lang.reflect去查询一个@inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

 

6、自定义注解:

  (1)自定义注解时,需要使用@interface用来声明一个注解,其会自动继承java.lang.annotation.annotation接口。

【格式:】
public @interface 注解名 {定义体}
【或者:】
public @interface 注解名 {
  类型 value() default 默认值;   //这里是参数,不是抽象方法。
}

其中定义体实质是声明了一个配置参数(注:此处不是抽象方法)。
1、方法名指的是参数名。
2、返回值类型指的是参数的类型(只能为基本类型、class、string、enum、annotation类型、以及以上所有类型的数组)。
3、可以通过default来声明参数的默认值。
4、如果只有一个参数,那么参数名(方法名)一般为value。
5、只能使用public, default两个权限修饰符。  

  (2)方法:

判断类或者方法是否有注解
    boolean isannotationpresent(class<? extends annotation> annotationclass)

获得注解对象
    <a extends annotation> a getannotation(class<a> annotationclass)  //获取指定注解
    annotation[] getannotations()  //获取当前元素上的所有注解
【举例:】
package com.test;

import java.lang.annotation.annotation;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
import java.lang.reflect.field;

@target(elementtype.type)
@retention(retentionpolicy.runtime)
@interface table {
    string value();
}

@target(elementtype.field)
@retention(retentionpolicy.runtime)
@interface fielddemo {
    string columnname() default "";

    string type() default "";

    int length() default 10;
}

@table("student")
class student {
    @fielddemo(columnname = "id", length = 10, type = "int")
    private int id;

    @fielddemo(columnname = "name", length = 20, type = "varchar")
    private string name;

    public int getid() {
        return id;
    }

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

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }
}

public class annotationdemo {
    public static void main(string[] args) {
        try {
            // 获取student类的信息
            class classdemo = class.forname("com.test.student");
            // class<student> classdemo = (class<student>)class.forname("com.test.student");
            system.out.println(classdemo); // 输出class com.test.student

            // 获取当前元素上的所有注解,此时获取的是@table
            annotation[] annotations = classdemo.getannotations();
            for (annotation annotation : annotations) {
                system.out.println(annotation);
            } // 输出@com.test.table(value=student)

            // 直接获取指定的某注解
            table table = (table) classdemo.getannotation(table.class);
            system.out.println(table.value()); // 输出student

            // 获取类的属性的注解
            field field = classdemo.getdeclaredfield("name");
            // 获取指定注解
            fielddemo fielddemo = field.getannotation(fielddemo.class);
            // 输出name varchar 20
            system.out.println(fielddemo.columnname() + " " + fielddemo.type() + " " + fielddemo.length());
        } catch (exception e) {
            e.printstacktrace();
        }
    }
}

 

二、反射机制

1、什么是反射?

  java反射机制指的是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;即这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
  java中与反射相关的类,放在java.lang.reflect包中。

2、class类

  class对象包含了一个类的完整的结构信息。通过class对象,可以对类进行操作,即为反射。
  (1)规则:
    class类拥有泛型作为定义。
    class 类的实例表示正在运行的 java 应用程序中的类和接口。
    class类没有public构造方法。
    class对象是在加载类时由java 虚拟机以及通过调用类加载器中的defineclass 方法自动构造的。
    一个类只有一个class对象。

  (2)内置class实例(class对象):

byte.class, short.class, int.class, long.class, 
char.class, float.class,  double.class, boolean.class, void.class.
注:
int.class != integer.class  。
int.class == integer.type  。

  (3)对于数组类型class实例:
    每个数组属于被映射为 class 对象的一个类,所有具有相同元素类型和维数的数组都共享该class 对象。

int[] a = new int[100];
int[] b = new int[10];
long[] c = new long[10];
int[][] d = new int[10][2];
system.out.println(a.getclass());//输出class [i
system.out.println(b.getclass());//输出class [i
system.out.println(c.getclass());//输出class [j
system.out.println(d.getclass());//输出class [[i
system.out.println(a.getclass() == b.getclass());//输出true

  (4)获取class实例的方法:

【方法1:】
根据传入的参数动态装载一个类,并且做类的初始化。
    class.forname()方法

【方法2:】
获得对象运行时所指的真正对象(多态的场合返回子类的类名)。
    class.getclass() 方法

【方法3:】
jvm将使用类a的类装载器,将类a装入内存(前提是:类a还没有装入内存),不对类a做类的初始化工作.返回类a的class的对象。
    a.class属性

  (5)通过class实例创建对象:

class.newinstance()方法 。调用默认构造函数,获得一个实例

class.newinstance方法与new的区别
newinstance: 弱类型。低效率。只能调用无参构造。
new:强类型。相对高效。能调用任何public构造。

  (6)常用方法:

【获得构造器:】
constructor<t> getdeclaredconstructor(class<?>...)  获得指定构造方法
constructor<?>[] getdeclaredconstructors()    获得所有构造方法(声明顺序)
constructor<t> getconstructor(class<?>...)    获得权限为public的指定构造方法
constructor<?>[] getconstructors()    获得权限为public的所有构造方法

【获得普通方法(成员方法):】
method[] getdeclaredmethods()   获得该类中定义的所有方法(不包含父类继承)
method getdeclaredmethod(string name, class<?>... parametertypes)    根据该类中定义的指定方法(不包含父类继承)
method[] getmethods()  获得权限为public的所有的方法 (包含父类继承)
method getmethod(string name, class<?>... parametertypes)    获得权限为public的指定的方法 (包含父类继承)

【获得属性(成员变量):】
field[] getdeclaredfields()   获得该类中定义的所有属性(不包含继承)
field getdeclaredfield(string name)获得该类中定义的指定属性(不包含继承)
field[] getfields()  获得该类中所有public的属性(包含继承)
field getfield (string name)  获得该类中指定的public属性(包含继承)

【获得内部类:】
class<?>[] getdeclaredclasses()  获得所有内部类 (不包含继承)
class<?>[] getclasses()   获得所有权限为public的内部类(包含继承)

【其他:】
package getpackage()   获得package对象
string getname()     获得类的全称,即包名+类名
string getsimplename()  获得类的简称,即类名
class<? super t> getsuperclass()  获得继承的类
class<?>[] getinterfaces()  获得实现的接口

  (7)获得构造器后,可以进行的操作

Java基础--注解、反射

  (8)获得成员方法后,可以进行的操作

Java基础--注解、反射

  (9)获得成员变量后,可以进行的操作

Java基础--注解、反射

package com.test;

import java.lang.reflect.constructor;
import java.lang.reflect.field;
import java.lang.reflect.method;

class teacher {
    private string name;
    private int age;

    public teacher() {
    }

    public teacher(string name, int age) {
        this.name = name;
        this.age = age;
    }

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }

    public int getage() {
        return age;
    }

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

public class reflectiondemo {
    public static void main(string[] args) {
        try {
            // 加载teacher.class对象
            class<teacher> teacherclass = (class<teacher>) class.forname("com.test.teacher");

            // 获取无参构造器,若teacher类没有无参构造方法,则会报错
            teacher teacher = teacherclass.newinstance();
            system.out.println(teacher + ", " + teacher.getname() + ", " + teacher.getage());

            // 获取有参构造器
            constructor<teacher> constructor = teacherclass.getdeclaredconstructor(string.class, int.class);
            teacher teacher2 = constructor.newinstance("tom", 20);
            system.out.println(teacher2 + ", " + teacher2.getname() + ", " + teacher2.getage());

            // 获取成员方法
            teacher teacher3 = teacherclass.newinstance();
            method method = teacherclass.getdeclaredmethod("setage", int.class);
            method.invoke(teacher3, 30);
            system.out.println(teacher3.getage());

            method method2 = teacherclass.getdeclaredmethod("getage");
            system.out.println(method2.invoke(teacher3));

            // 获取成员变量
            teacher teacher4 = teacherclass.newinstance();
            field field = teacherclass.getdeclaredfield("age");
            field.setaccessible(true);// 忽略安全检查,可以获取private类型的数据,破坏封装性。
            system.out.println(field.get(teacher4));
        } catch (exception e) {
            e.printstacktrace();
        }
    }
}

【结果:】
com.test.teacher@2a139a55, null, 0
com.test.teacher@15db9742, tom, 20
30
30
0

3、反射机制性能问题

  setaccessible,是启用和禁用安全检查的开关,其值为true时,表示禁用java语言访问的安全性检查,为false时,表示启用安全性检查,将其值设为true,可以提高反射的效率。

 

未完待续。。。。