前言

在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然。

目录

  • 反射机制
  • 反射如何使用
  • 注解定义
  • 注解机制原理
  • 注解如何使用
  • 小结

反射机制

官网定义:

Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.

Reflection is a language's ability to inspect and dynamically call classes, methods, attributes, etc. at runtime.

也就是说:

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能。

主要提供了以下功能: 在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,在运行时调用任意一个对象的方法,生成动态代理。

反射如何使用

通过一个对象获得完整的包名和类名

package Reflect;

/**
 * 通过一个对象获得完整的包名和类名
 * */
class Demo{
    //other codes...
}

class hello{
    public static void main(String[] args) {
        Demo demo=new Demo();
        System.out.println(demo.getClass().getName());
    }
}

我们可以发现,其实所有的类的对象都是Class的实例。

实例化Class类对象

package Reflect;
class Demo{
    //other codes...
}

class hello{
    public static void main(String[] args) {
        Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("Reflect.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=new Demo().getClass();
        demo3=Demo.class;

        System.out.println("类名称   "+demo1.getName());
        System.out.println("类名称   "+demo2.getName());
        System.out.println("类名称   "+demo3.getName());

    }
}

结果:

类名称   Reflect.Demo
类名称   Reflect.Demo
类名称   Reflect.Demo

通过Class实例化其他类的对象

package Reflect;

class Person{

    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;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}

class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per=null;
        try {
            per=(Person)demo.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        per.setName("Rollen");
        per.setAge(20);
        System.out.println(per);
    }
}

结果:

[Rollen  20]

通过Class调用其他类中的构造函数

package Reflect;

import java.lang.reflect.Constructor;

class Person{

    public Person() {

    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}

class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的构造函数
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}

结果:

[null  0]

[Rollen  0]

[null  20]

[Rollen  20]

通过反射调用其他类中的方法

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try{
            //调用Person类中的sayChina方法
            Method method=demo.getMethod("sayChina");
            method.invoke(demo.newInstance());
            //调用Person的sayHello方法
            method=demo.getMethod("sayHello", String.class,int.class);
            method.invoke(demo.newInstance(),"Rollen",20);

        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

hello ,china

Rollen  20

注解定义

官网原话:

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

Annotations have a number of uses, among them:

  • Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
  • Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
  • Runtime processing — Some annotations are available to be examined at runtime.

也就是说:一种代码级别的说明,它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

作用:

  • 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】

  • 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

  • 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

注解机制原理

原理:

Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。

  • Annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。
  • Java语言解释器在工作时会忽略这些annotation,因此在JVM中这些annotation是“不起作用”的,只能通过配套的工具才能对这些annontaion类型的信息进行访问和处理。

Annotation与interface的异同:

  • Annotation类型使用关键字@interface而不是interface。这个关键字声明隐含了一个信息:它是继承了java.lang.annotation.Annotation接口,并非声明了一个interface
  • Annotation类型、方法定义是独特的、受限制的。Annotation 类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用 default和一个默认数值来声明成员的默认值,null不能作为成员默认值,这与我们在非annotation类型中定义方法有很大不同。Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。
  • Annotation类型又与接口有着近似之处。

  它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。

注解如何使用

What’s the use of Annotations?

1) Instructions to the compiler: There are three built-in annotations available in Java (@Deprecated, @Override & @SuppressWarnings) that can be used for giving certain instructions to the compiler. For example the @override annotation is used for instructing compiler that the annotated method is overriding the method. More about these built-in annotations with example is discussed in the next sections of this article.

2) Compile-time instructors: Annotations can provide compile-time instructions to the compiler that can be further used by sofware build tools for generating code, XML files etc.

3) Runtime instructions: We can define annotations to be available at runtime which we can access using java reflection and can be used to give instructions to the program at runtime. We will discuss this with the help of an example, later in this same post.

Annotations basics

An annotation always starts with the symbol @ followed by the annotation name. The symbol @ indicates to the compiler that this is an annotation.

For e.g. @Override

Here @ symbol represents that this is an annotation and the Override is the name of this annotation.

Where we can use annotations?

Annotations can be applied to the classes, interfaces, methods and fields. For example the below annotation is being applied to the method.

@Overridevoid myMethod(){//Do something }

What this annotation is exactly doing here is explained in the next section but to be brief it is instructing compiler that myMethod() is a overriding method which is overriding the method (myMethod()) of super class.

Built-in Annotations in Java

Java has three built-in annotations:

  • @Override
  • @Deprecated
  • @SuppressWarnings

1) @Override:

While overriding a method in the child class, we should use this annotation to mark that method. This makes code readable and avoid maintenance issues, such as: while changing the method signature of parent class, you must change the signature in child classes (where this annotation is being used) otherwise compiler would throw compilation error. This is difficult to trace when you haven’t used this annotation.

Example:

public class MyParentClass{
  public void justaMethod(){
    System.out.println("Parent class method");
  }
}
public class MyChildClass extends MyParentClass{
  @Override
  publicvoid justaMethod(){
    System.out.println("Child class method");
  }
}

I believe the example is self explanatory. To read more about this annotation, refer this article: @Override built-in annotation.

2) @Deprecated

@Deprecated annotation indicates that the marked element (class, method or field) is deprecated and should no longer be used. The compiler generates a warning whenever a program uses a method, class, or field that has already been marked with the @Deprecated annotation. When an element is deprecated, it should also be documented using the Javadoc @deprecated tag, as shown in the following example. Make a note of case difference with @Deprecated and @deprecated. @deprecated is used for documentation purpose.

Example:

/**
 * @deprecated
 * reason for why it was deprecated
 */
@Deprecatedpublicvoid
anyMethodHere(){// Do something}

Now, whenever any program would use this method, the compiler would generate a warning. To read more about this annotation, refer this article: Java – @Deprecated annotation.

3) @SuppressWarnings

This annotation instructs compiler to ignore specific warnings. For example in the below code, I am calling a deprecated method (lets assume that the method deprecatedMethod() is marked with @Deprecated annotation) so the compiler should generate a warning, however I am using @@SuppressWarnings annotation that would suppress that deprecation warning.

@SuppressWarnings("deprecation")
void myMethod(){
    myObject.deprecatedMethod();
}

Creating Custom Annotations

  • Annotations are created by using @interface, followed by annotation name as shown in the below example.
  • An annotation can have elements as well. They look like methods. For example in the below code, we have four elements. We should not provide implementation for these elements.
  • All annotations extends java.lang.annotation.Annotation interface. Annotations cannot include any extends clause.

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Documented
    @Target(ElementType.METHOD)
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyCustomAnnotation{
    int studentAge() default18;
    String studentName();
    String stuAddress();
    String stuStream() default"CSE";
    }

Note: All the elements that have default values set while creating annotations can be skipped while using annotation. For example if I’m applying the above annotation to a class then I would do it like this:

@MyCustomAnnotation(
    studentName="Chaitanya",
    stuAddress="Agra, India")
public class MyClass{...}

As you can see, we have not given any value to the studentAge andstuStream elements as it is optional to set the values of these elements (default values already been set in Annotation definition, but if you want you can assign new value while using annotation just the same way as we did for other elements). However we have to provide the values of other elements (the elements that do not have default values set) while using annotation.

Note: We can also have array elements in an annotation. This is how we can use them:

Annotation definition:

@interface MyCustomAnnotation{
  int      count();
  String[] books();
}

Usage:

@MyCustomAnnotation(
    count=3,
    books={"C++","Java"}
)
public class MyClass{}

Lets back to the topic again: In the custom annotation example we have used these four annotations: @Documented, @Target,@Inherited & @Retention. Lets discuss them in detail.

@Documented

@Documented annotation indicates that elements using this annotation should be documented by JavaDoc. For example:

import java.lang.annotation.Documented
@Documented
public @interface MyCustomAnnotation{
  //Annotation body
}

@MyCustomAnnotation
public class MyClass{
  //Class body
}

While generating the javadoc for class MyClass, the annotation@MyCustomAnnotation would be included in that.

@Target

It specifies where we can use the annotation. For example: In the below code, we have defined the target type as METHOD which means the below annotation can only be used on methods.

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface MyCustomAnnotation{

}

public class MyClass{
  @MyCustomAnnotation
  public void myMethod(){
    //Doing something
  }
}

Note: 1) If you do not define any Target type that means annotation can be applied to any element.

2) Apart from ElementType.METHOD, an annotation can have following possible Target values.

ElementType.METHOD

ElementType.PACKAGE

ElementType.PARAMETER

ElementType.TYPE

ElementType.ANNOTATION_TYPE

ElementType.CONSTRUCTOR

ElementType.LOCAL_VARIABLE

ElementType.FIELD

@Inherited

The @Inherited annotation signals that a custom annotation used in a class should be inherited by all of its sub classes. For example:

import java.lang.annotation.Inherited
  @Inheritedpublic
  @interface
  MyCustomAnnotation{}

@MyCustomAnnotation
public class MyParentClass{...}

public class MyChildClass extends MyParentClass{...}

Here the class MyParentClass is using annotation@MyCustomAnnotation which is marked with @inherited annotation. It means the sub class MyChildClass inherits the@MyCustomAnnotation.

@Retention

It indicates how long annotations with the annotated type are to be retained.

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyCustomAnnotation{}

Here we have used RetentionPolicy.RUNTIME. There are two other options as well. Lets see what do they mean:

RetentionPolicy.RUNTIME: The annotation should be available at runtime, for inspection via java reflection.

RetentionPolicy.CLASS: The annotation would be in the .class file but it would not be available at runtime.

RetentionPolicy.SOURCE: The annotation would be available in the source code of the program, it would neither be in the .class file nor be available at the runtime.

That’s all for this topic “Java Annotation”. Should you have any questions, feel free to drop a line below.

小结

总之,反射和注解的机制在很多应用和开源库上广泛应用,通过了解背后的机制原理和使用方式,对于在开发中或者看一些比较优秀第三方库的源代码有很大的帮助,看看他们实现的思想,看看是否值得借鉴下,对于自我技术的收获想必会有不一样的冲击。

参考地址:

1,http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

Java中的反射和注解的更多相关文章

  1. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

  2. 【Java基础】反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  3. java中的反射机制在Android开发中的用处

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

  4. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  5. java中动态反射

    java中动态反射能达到的效果和python的语法糖很像,能够截获方法的实现,在真实方法调用之前和之后进行修改,甚至能够用自己的实现进行特别的替代,也可以用其实现面向切片的部分功能.动态代理可以方便实 ...

  6. 第89节:Java中的反射技术

    第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...

  7. 【Java入门提高篇】Day13 Java中的反射机制

    前一段时间一直忙,所以没什么时间写博客,拖了这么久,也该更新更新了.最近看到各种知识付费的推出,感觉是好事,也是坏事,好事是对知识沉淀的认可与推动,坏事是感觉很多人忙于把自己的知识变现,相对的在沉淀上 ...

  8. Java中的反射总结

    反射是获取运行时类信息,即常量区中的Class信息. 要获取类信息,必然需要依据,不然系统怎么指定你要获取那个类信息, 类信息在java中就是Class类的一个对象,它是一个java类抽象,换句话说它 ...

  9. java中的反射

    1.何为java反射机制: 在运行过程中,对于任意一个类都能够知道这个类的属性和方法:对于任意一个对象都能调用其属性和方法:这种动态获取信息和动态调用方法 就称为java反射 2.获取Class对象的 ...

随机推荐

  1. Solr4.10.3安装配置

    系统环境 window版本为:windows 8.1 64位 软件环境 JDK版本:1.7 solr版本:4.10.3 tomcat版本:tomcat 7 安装过程 步骤一:将下载好的solr-4.1 ...

  2. sql常见的面试题

    1.用一条SQL语句 查询出每门课都大于80分的学生姓名 name   kecheng   fenshu 张三     语文       81张三     数学       75李四     语文   ...

  3. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q72-Q74)

    Question 72  You are designing a SharePoint 2010 application and a Web application. You need to desi ...

  4. webGL

    WebGL:  是 OpenGL 和 JavaScript 之间的结晶.HTML5 的 canvas 元素里.利用和OpenGL同样的API.可以绘制高精度的三维图像. (OpenGL 能够从任意视点 ...

  5. IOS的UI总结

    一.UIView常见属性 1.frame  位置和尺寸(以父控件的左上角为原点(0,0)) 2.center 中点(以父控件的左上角为原点(0,0)) 3.bounds  位置和尺寸(以自己的左上角为 ...

  6. 微信jssdk已无力吐槽

    微信强大的整合能力让企业公众号的开发迅速窜红.尤其是企业须要个性化定制的一些功能.公司在同一时候上线的app和触屏版的应用中,微信分享自然是不可或缺的重要一环. 纵观如今大多数的微信公众号.分享大都是 ...

  7. RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World

    一.简介      RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到邮筒之时,你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人 ...

  8. [LeetCode] Subarray Product Less Than K 子数组乘积小于K

    Your are given an array of positive integers nums. Count and print the number of (contiguous) subarr ...

  9. Struts2,Spring,Hibernate优缺点

    struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发. 优点: Struts跟Tomcat.Turbine等诸多Apache项目一样,是开源软件,这是它的 ...

  10. 结对开发nabcd

     各位领导/投资人/用户/合作伙伴: 我们的产品校园生活 是为了解决 广大在校师生对于信息难以得到的痛苦,他们需要了解有关于学校开办的各种活动的信息还有各种二手商品的交换信息,他们也需要一个公开的平台 ...