`
suhuanzheng7784877
  • 浏览: 704268 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Ff8d036b-05a9-33b5-828a-2633bb68b7e6
读金庸故事,品程序人生
浏览量:47749
社区版块
存档分类
最新评论

Java基础复习笔记12Java自定义注解Annotation的使用

阅读更多

1.       前言

JDK1.5以后,推出了注解新特性。注解的推出其实最主要的目的是为了让广大的用户认知EJB3.0,因为EJB2.X广受大多数开发者的诟骂和质疑。为了减少配置、让注解替代配置。有了注解,我们以前看似一般的、普通的JavaBean就有了活力,有了内涵,有了新的契机。配合SunJPA规范,EJB3.X又再次在企业级开发中大放异彩,让很多开发者赞不绝口。也许是无心插柳,这种“零配置”思维也影响着Java其他的开源项目——像StrutsSpringHibernate(也就是咱们耳熟能详的SSH)不都是具有“零配置”支持嘛!Java现在也是往动态、敏捷的方向发展着。有可能将来配置文件越来越少、规范、约定、注解代替了繁琐的配置信息。而XML估计会回归原始的使命——数据传输与数据交换。

2.       自定义注解

至于已有的注解,比如:JPAEJBSpring零配置等等怎么使用相信各位读者都能掌握,这里主要是说如何自定义自己的注解,自己使用自定义的注解。

我们先用一个简单的例子来看

package annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 注解
 * 
 * @author Administrator
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {

	String isAop() default "false";

}
 用关键字@interface定义一个注解标记,使用@interface关键字实际上的意思就是该接口继承自java.lang.annotation.Annotation接口。

String isAop() default "false";

 这句话代表的意思就是在Test注解中可以含有属性名为isAop,此属性的类型是字符串类型。客户端使用的时候可以根据需要自己指定相关的属性值。如果客户端不指定值,默认值是false

@Retention(RetentionPolicy.RUNTIME)
package use;

import annotation.Test;
import annotation.TestImpl.TestProcess;

@Test(isAop = "true")
public class UseTest {

	/**
	 * @param args
	 * @throws ClassNotFoundException
	 */
	public static void main(String[] args) throws ClassNotFoundException {

		TestProcess.process("use.UseTest");

	}

}

 在客户端调用中在类UseTest上使用了@Test(isAop = "true")注解。仅仅定义了注解就像《三国杀》里,刘备是主公,他有“激将”的主公计,下了个命令:“蜀将何在?”,刘备的这句话太抽象了,蜀将相当于一个注解。在场的所有蜀将就像加了此注解的类,都会受到这句话的影响。具体替不替刘备出杀,~~~~个人表现不同(得先看看自己的身份啊)反贼的表现是:“这个真没有”;忠臣的表现是,先看看手上有杀吗?有,出击吧!没有就说:“这个……真没有!”;内奸的反应是:“唉,先保命还是装一装忠臣?比较纠结!”。这里的身份就好像是注解的属性的不同值。具体的处理就相当于针对注解的处理实现类。注解的具体实现类就是处理注解的业务逻辑,它需要Java的反射机制来处理客户目标类的具体注解,我们就来看看这个注解处理实现类。

package annotation.TestImpl;

import java.lang.annotation.Annotation;

public class TestProcess {

	public static void process(String str) throws ClassNotFoundException {

		Class clazz = Class.forName(str);

		Annotation[] annotations = clazz.getAnnotations();

		for (Annotation annotation : annotations) {
			System.out.println(annotation);
		}
	}

}

 以上的处理逻辑很简单,就是根据一个字符串类名找到类。获得类的所有注解,所有注解是一个对象数组。遍历注解数组,输出相关注解信息。运行以上的程序结果如下

@annotation.Test(isAop=true)

 如果我们使用注解的客户端代码替换一下

@Test
public class UseTest {
……………………
}

 对于注解的isAop并不特别指定。运行效果如下

@annotation.Test(isAop=false)

 可以看到使用的是默认值false。如果注解中Annotation并没有指定默认值,而在客户端使用中也没指定值,那么不会通过编译。

 @Retention(RetentionPolicy.XXXXXX)上面说到了是保留注解的有效期。

//会将注解保留到编译后的class中,加载类的时候不生效
@Retention(RetentionPolicy.CLASS)
//仅仅在代码保留,编译后的class不会保留
@Retention(RetentionPolicy.SOURCE)
//在编译后的class会有,通过反射也会获得注解信息
@Retention(RetentionPolicy.RUNTIME)

 比如Override注解的源码

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

 因为复写在使用者使用的时候就可以看出来,所以没必要保留到运行期。

比如SuppressWarnings注解的源码

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

 以上的不提示警告的注解也是在编译一个类前检查即可。

以上还使用了@Target注解,它代表着注解的修饰范围,类型是java.lang.annotation.ElementType枚举类型。

public enum ElementType {
    TYPE,//可以修饰类、接口、枚举、注解
    FIELD,//可以修饰成员变量
    METHOD,//可以修饰方法
    PARAMETER,//可以修饰参数
    CONSTRUCTOR,//可以修饰构造方法
    LOCAL_VARIABLE,//可以修饰局部变量
    ANNOTATION_TYPE,// 可以修饰Annotation
    PACKAGE//可以修饰包
}

 Deprecated源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}

 Deprecated代表已过时的意思,这是一个保持到运行期的注解,在运行期可以通过反射获取此注解。这里还使用了@Documented这个元注解。它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。

还有一个注解就是Inherited,如果使用了该标记,那么使用该注解的子类也会继承该注解的特性。

3.       实例

很多人有疑问,你说这些有什么用?对于开发有什么促进吗?EJB注解、JPA注解我们会使用完成业务不就得了。下面再来看一个程式例子

注解Pojo

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Pojo {
	String table();
}

 注解Colum

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Colum {
	String columName();
	boolean isNULL() default true;
	String Type() default "";
}

 处理注解的逻辑实现类

package annotation.TestImpl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import annotation.Colum;
import annotation.Pojo;

public class MyJPAProcess {

	public static void process(Object object) throws ClassNotFoundException {

		// 所有注解
		Annotation[] annotationsClass = object.getClass().getAnnotations();

		Field[] fields = object.getClass().getDeclaredFields();

		// 遍历注解元素
		for (Annotation annotation : annotationsClass) {
			if (annotation instanceof Pojo) {
				System.out.println("--------处理POJO实体--------");
				Pojo pojo = (Pojo) annotation;
				System.out.println("存储表名:" + pojo.table());
			}

		}

		for (Field field : fields) {
			
			//field.setAccessible(true);

			Annotation[] annotationsMethos = field.getAnnotations();

			// 遍历注解元素
			for (Annotation annotation : annotationsMethos) {
				if (annotation instanceof Colum) {
					System.out.println("--------处理Colum字段--------");
					Colum colum = (Colum) annotation;
					System.out.println("字段名:" + colum.columName());
					System.out.println("字段类型:" + colum.Type());
					System.out.println("是否能为空:" + colum.isNULL());
				}
			}
		}

	}

}

 以上是定义了简单的2个注解PojoColum。之后为这2个注解提供了逻辑处理。下面我们来看看客户端是怎么使用的吧。

一般的实体类

package use;

import annotation.Colum;
import annotation.Pojo;

@Pojo(table = "person")
public class PersionPOJO {

	public PersionPOJO() {
		super();
	}

	@Colum(columName = "id", isNULL = false, Type = "varchar")
	private String id;

	@Colum(columName = "name", isNULL = false, Type = "varchar")
	private String name;

	@Colum(columName = "age", isNULL = true, Type = "int")
	private int age;

	//省略set/get

}

 这是一个普通的实体对象+自定义的注解。针对于这个POJO我们再定义一个DAO类操作这个POJO类。

package use;

import annotation.TestImpl.MyJPAProcess;

public class PersionDAO {

	public void save(PersionPOJO persionPOJO) throws ClassNotFoundException {
		MyJPAProcess.process(persionPOJO);
	}

	public static void main(String[] args) throws ClassNotFoundException {

		PersionDAO persionDAO = new PersionDAO();
		PersionPOJO persionPOJO = new PersionPOJO();
		persionDAO.save(persionPOJO);
	}
}

 上面程序就定义了一个保存方法,测试一下,调用这个save方法。控制台输出如下信息。

--------处理POJO实体--------
存储表名:person
--------处理Colum字段--------
字段名:id
字段类型:varchar
是否能为空:false
--------处理Colum字段--------
字段名:name
字段类型:varchar
是否能为空:false
--------处理Colum字段--------
字段名:age
字段类型:int
是否能为空:true

 DAO中调用了注解逻辑实现类的方法。这个时候我们稍微修改一下注解逻辑实现类的方法,配合一个ORM中间件,就可以将数据保存到数据库了。

4.       总结

其实自定义注解一般是公司或者团队觉得一些原有的配置比较麻烦,加上注解是为了减少配置。还有一个目的:自己开发框架,让自己的团队更敏捷、更快速的相应纷繁错杂的客户需求。其实还有一个目的:就是制定规范,JPA是规范、EJB是规范……至于底层对于这些注解规范的实现则因不同的容器决定的。所谓容器就是JBoss或者Weblogic这种JavaEE容器的自己的jar包,像Java SDK也是提出了相应的规范,不同的组织对这个规范的实现也是仁者见仁智者见智,像上面提出的JDK内的注解就是提出了规范,我自己sun有一套实现机制,其他的组织用我sunJDK实现不爽也可以自行实现这套注解机制。这样通过反射机制获取本应该在配置文件中配置的一些信息。减少了冗余的配置文件。至于效率嘛~~~有人说反射机制比解析配置慢、有人说配置文件要是过长会比反射慢很多。这个笔者觉得仁者见智者见智,没有绝对的答案,到底使用哪个?还是得因环境而异。

 

 

 

  • 大小: 41.9 KB
分享到:
评论
5 楼 suhuanzheng7784877 2011-08-15  
不过衣服挺漂亮的!下不为例
4 楼 suhuanzheng7784877 2011-08-15  
http://kblessed24.taobao.com/
blessed24 写道
http://kblessed24.taobao.com/

兄弟!!!你是在做广告吗???这里最好不要做广告
3 楼 blessed24 2011-08-15  
http://kblessed24.taobao.com/
2 楼 suhuanzheng7784877 2011-08-15  
tan4836128 写道
混了些年月,还没有专门针对Java 的注解进行过开发。

不过倒是进行类似这样的功能的编码还是做过:
@Colum(columName = "age", isNULL = true, Type = "int")  
    private int age; 

那也是在程序生成pojo类代码的情况下,通过数据库获取到表字段信息,然后再注释里面进行编排,比较过程化,很显然没有本文讨论的注解那么强大!

又一次扫盲了.....功在千秋哦

唉~~~说哪里话~~~
1 楼 tan4836128 2011-08-15  
混了些年月,还没有专门针对Java 的注解进行过开发。

不过倒是进行类似这样的功能的编码还是做过:
@Colum(columName = "age", isNULL = true, Type = "int")  
    private int age; 

那也是在程序生成pojo类代码的情况下,通过数据库获取到表字段信息,然后再注释里面进行编排,比较过程化,很显然没有本文讨论的注解那么强大!

又一次扫盲了.....功在千秋哦

相关推荐

    硅谷java基础每日复习eDiary

    以下是基于描述中提到的两个文件——"Java基础每日复习笔记-JavaSE基础阶段.edf"和"Java基础每日复习笔记-JavaSE高级阶段.edf"——所包含的知识点的详细阐述: 1. **Java SE基础阶段**: - **Java简介**:了解Java...

    全网Java最全笔记合计

    17. **注解(Annotation)**:了解注解的使用,学习元注解和自定义注解。 18. **枚举(Enum)**:掌握枚举的定义和使用,理解其在Java中的特殊地位。 19. **Lambda表达式**:Java 8引入的新特性,用于简化函数式...

    面向对象程序设计Java听课笔记

    - 自定义注解:定义元数据,用于编译时或运行时检查,增强代码功能。 - 预定义注解:如@Override、@Deprecated、@ SuppressWarnings等,简化编码。 以上是根据翁恺老师Java课程整理的面向对象程序设计Java的核心...

    mldn 李兴华笔记

    也可能讨论了注解(Annotation)的使用和自定义注解。 8. **笔记018.pdf**:这部分可能涉及Java的模块系统(Jigsaw),Java 9及以上版本的新特性,以及如何构建和管理大型项目中的模块依赖。 9. **笔记019.pdf**:...

    学习笔记——资料

    - **注解(Annotation)**:为代码添加元数据,可以用于编译时或运行时的处理。 这份"学习笔记——资料"是Java学习的宝贵资源,涵盖了从基础到进阶的各个层面。通过深入学习和实践,不仅可以掌握Java语法,还能...

    JavaSE总结文档.rar

    - **注解(Annotation)**:注解的定义、元注解的使用,自定义注解以及在编译和运行时的处理。 - **IO/NIO**:传统IO流与非阻塞IO(NIO)的区别和应用场景,通道(Channel)、缓冲区(Buffer)的概念。 这份笔记...

    SCJP-065 资料

    12. **枚举与注解**:理解枚举类型(enum)的特性,以及如何创建和使用注解(annotation),包括元注解和自定义注解。 以上是SCJP 6认证考试的主要知识点,通过深入学习和实践这些内容,可以为通过考试打下坚实的...

    becajava.revisao1

    11. **注解(Annotation)**:理解注解的作用,以及如何自定义和使用注解。 12. **设计模式**:可能会涉及单例模式、工厂模式、观察者模式等常见设计模式的实现。 13. **单元测试**:如JUnit框架的使用,编写测试...

    sf-class-7-2015:7月SF课程的课程示例

    10. **注解(Annotation)**:注解的作用,自定义注解及其处理器。 11. **Java标准库**:使用Java SE API中的各种类和方法,例如日期时间API、数学运算、字符串处理等。 12. **单元测试**:JUnit框架的使用,编写...

Global site tag (gtag.js) - Google Analytics