【框架基础】:全面解析Java注解(一)

       Java注解概述

       要了解Java注解要先知道Java的反射,反射是运行时获取类的成员,注解也是类的成员,以此达到动态编码的效

果,多用在框架,或者使用框架时候添加注解让框架调用。

       注解定义:注解(Annotation),也叫元数据。Java提供了一种原程序中的元素关联任何信息和任何元数据的途

径和方法,一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可

以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

       Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译

时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注

解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实

现对这些元数据(用来描述数据的数据)的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,

或者它也能在class文件、或者运行时中出现(SOURCE/CLASS/RUNTIME)。

       注解的作用

       如果要对于注解的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

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

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

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

       为什么学习注解

       1、能够读懂别人写的代码,特别是框架相关的代码,增加代码的阅读性;

       2、让编程更加简洁,代码更加清晰,理清自己的思路;

       3、生成API文档;

       Java中的常见注解

       JDK内置注解

       【框架基础】:全面解析Java注解(一)_第1张图片

       @Override

       它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发

出错误警告。下面的例子是实现类Child实现了接口Person的方法   使用了@Override。

package com.demo.annotation;

/**
 * 测试@Override注解
 * @author Administrator
 * @date 2016年12月9日
 */
public interface Person {
	
	public String name();
	
	public int age();
	
	public void sing();

}

class Child implements Person {

	@Override
	public String name() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int age() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void sing() {
		// TODO Auto-generated method stub
	    
	}
	
}

        @Deprecated

        它的作用是对不应该再使用的方法添加注解,当编程人员使用这些方法时,将会在编译时显示提示信息,它与

javadoc里的@deprecated标记有相同的功能,准确的说,它还不如javadoc @deprecated,因为它不支持参数,

使用@Deprecated的示例代码示例如下:   

package com.demo.annotation;


/**
 * 测试@Deprecated注解
 * @author Administrator
 * @date 2016年12月9日
 */
public interface Person {

	public String name();
	
	public int age();
	
	@Deprecated
	public void sing();

}

class Child implements Person {

	@Override
	public String name() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int age() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void sing() {
		// TODO Auto-generated method stub

	}

}

class Test {
	@SuppressWarnings("deprecation")
	public void sing(){
		Person person = new Child();
		person.sing();//sing()方法已经过时		
	}
	
}

        Person接口使用了@Deprecated修饰了一个已经过时的方法,此时强行调用超类继承来的方法就会有个代码过

时的横线,并且报一个代码过时的警告,但不会影响正常使用。如果要去掉警告可以使用

 @suppressWarings("deprecation")  来忽略这个警告。

       @SuppressWarnings

       其参数有:
       deprecation:使用了过时的类或方法时的警告

       unchecked:执行了未检查的转换时的警告

       fallthrough:当 switch 程序块直接通往下一种情况而没有 break 时的警告

       path:在类路径、源文件路径等中有不存在的路径时的警告

       serial:当在可序列化的类上缺少serialVersionUID 定义时的警告

       finally :任何 finally 子句不能正常完成时的警告

       all:关于以上所有情况的警告

       这里的演示在上面已经出现过。

       【框架基础】:全面解析Java注解(一)_第2张图片

       常见的第三方注解

       【框架基础】:全面解析Java注解(一)_第3张图片

       在这里只是简单的演示一下,在学习框架的过程中再详细说明。

       按照过去的方式就是写一个配置文件:

       【框架基础】:全面解析Java注解(一)_第4张图片

       使用注解方式不再使用配置文件:

       【框架基础】:全面解析Java注解(一)_第5张图片

       Java注解的分类

       按照运行机制分类

       源码注解:注解只在源码中存在,编译成.class文件就不存在了;

       编译时注解:注解在源码和.class文件中都存在,比如@SuppressWarnings、@Override和@Deprecated只在

编译时刻起作用;

       运行时注解:源码、编译后以及运行时都存在的注解,在运行阶段还起作用,甚至会影响运行逻辑的注解,比如

spring框架的@Autowired注解。

       按照来源分类

       来自JDK的注解:@SuppressWarnings、@Override和@Deprecated

       来自第三方的注解:比如spring框架的@Autowired注解

       自定义注解:我们自己定义的注解。

       元注解

       注解的注解:自定义注解中比较常见。

       Java自定义注解

       先来看一个模板:

       【框架基础】:全面解析Java注解(一)_第6张图片

        自定义注解语法要求

       1)使用@Interface关键字定义注解;

       2)成员以无参无异常方式声明;

       3)可以用default为成员指定一个默认值;

       4)成员类型是受限的,合法的类型包括原始类型及String、Class、Annotation、Enumeration;

       5)如果注解只有一个成员,则成员必须取名为value(),在使用时可以忽略成员名和赋值号(=);

       6)注解类可以没有成员,没有成员的注解称为标识注解;

        注解的注解(元注解)

       @Target({ElementType.METHOD,ElementType.TYPE})

       CONSTRUCTOR:构造方法声明
       FIELD:字段声明
       LOACL_VARIABLE:局部变量声明
       METHOD:方法声明
       PACKAGE:包声明
       PARAMETER:参数声明
       TYPE:类或者接口声明

       @Retention(RetentionPolicy.RUNTIME)

       SOURCE:只在源码显示,编译时会丢弃

       CLASS:编译时会记录到class中,运行时忽略

       RUNTIME:运行时存在,可以通过反射读取

       @Inherited

       允许子类继承

       @Documented

       生成javadoc时会包含注解

       使用自定义注解

       使用注解的语法:@<注解名>(<成员名1>=<成员值1>,<成员名2>=<成员值2>,...)

       一个简单的例子:

       定义@Description注解:

package com.demo.annotation;

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;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
	
	String desc();
	
	String author();
	
	int age() default 18;
	
}

       使用注解:

package com.demo.annotation;

@Description(desc="I am class annotation",author="Mooc boy",age=18)
public class AnnotationTest {
	@Description(desc="I am method annotation",author="Mooc boy",age=18)
	public String eyeColor(){
		return "red";
	}
}

       @Description注解在eyeColor()方法上使用,可以在类或者接口上使用

       解析注解

       概念:通过反射获取类,函数或成员上的运行时注解信息,从而实现动态控制控制程序运行的逻辑。

       对于@RetentionRetention表示作用范围,我们知道:SOURCE表示只在源码显示,编译时会丢弃;

CLASS表示编译时会记录到class中,运行时忽略;RUNTIME表示运行时存在,可以通过反射读取。前两个都不会显

示结果,只有最后一个会显示结果。

       一个例子:

package com.demo.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 解析注解
 * @author Administrator
 * @date 2016年12月9日
 */
public class Demo {
	public static void main(String[] args) {
		//1.使用类加载器加载类
		try {
			Class< ?> clazz = Class.forName("com.demo.annotation.AnnotationTest");
		    //2.找到类上面的注解
			boolean flag1 = clazz.isAnnotationPresent(Description.class);
			if(flag1){
				//3.拿到注解实例
				Description description1 = (Description)clazz.getAnnotation(Description.class);
				System.out.println(description1.desc());
				System.out.println(description1.author());
				System.out.println(description1.age());
			}
			
			//4.解析找到方法上的注解
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				boolean flag2 = method.isAnnotationPresent(Description.class);
				if(flag2){
					//5.拿到注解实例
					Description description2 = (Description)method.getAnnotation(Description.class);
					System.out.println(description2.desc());
					System.out.println(description2.author());
					System.out.println(description2.age());
				}
			}
			
			//另外一种解析方法
			for (Method method : methods) {
				Annotation[]  annotations = method.getAnnotations();
				for (Annotation annotation : annotations) {
					if(annotation instanceof Description){
						Description description3 = (Description)annotation;
						System.out.println(description3.desc());
						System.out.println(description3.author());
						System.out.println(description3.age());
					}
				}
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}

}

       运行结果:

       【框架基础】:全面解析Java注解(一)_第7张图片

       关于@Inherited元注解

       父子类继承注解这块分两种情况,一个是注解定义了@Inherited,一个是没定义。在每种情况中又分类上的注

解,子类实现父类抽象方法,继承了父类方法,覆盖了父类方法这四种情况,具体继承规则如下:

       编写自定义注解时未写@Inherited的运行结果:        

       子类的类上能否继承到父类的类上的注解?    否        

       子类方法,实现了父类上的抽象方法,这个方法能否继承到注解?    否        

       子类方法,继承了父类上的方法,这个方法能否继承到注解?    能        

       子类方法,覆盖了父类上的方法,这个方法能否继承到注解?    否        

       编写自定义注解时写了@Inherited的运行结果:

       子类的类上能否继承到父类的类上的注解?     能    

       子类方法,实现了父类上的抽象方法,这个方法能否继承到注解?      否    

       子类方法,继承了父类上的方法,这个方法能否继承到注解?      能    

       子类方法,覆盖了父类上的方法,这个方法能否继承到注解?      否   

        仅供参考!


你可能感兴趣的:(框架基础,SSH框架学习之路)