Java和C#中的自定义元数据
Java的annotation和C#的Attribute,可用来为语言增加语义,定义元数据。
转自:http://rednaxelafx.iteye.com/blog/464889
http://blog.sina.com.cn/s/blog_69a4df530100p8w3.html
C#里要自定义attribute类型,可以直接或间接继承System.Attribute类,并通过AttributeUsageAttribute来指定attribute的应用范围,然后像定义普通的public类一样定义attribute的内容。
指定应用范围的AttributeTargets有以下成员:
| Assembly | Attribute can be applied to an assembly. |
| Module | Attribute can be applied to a module. |
| Class | Attribute can be applied to a class. |
| Struct | Attribute can be applied to a structure; that is, a value type. |
| Enum | Attribute can be applied to an enumeration. |
| Constructor | Attribute can be applied to a constructor. |
| Method | Attribute can be applied to a method. |
| Property | Attribute can be applied to a property. |
| Field | Attribute can be applied to a field. |
| Event | Attribute can be applied to an event. |
| Interface | Attribute can be applied to an interface. |
| Parameter | Attribute can be applied to a parameter. |
| Delegate | Attribute can be applied to a delegate. |
| ReturnValue | Attribute can be applied to a return value. |
| GenericParameter | Attribute can be applied to a generic parameter. |
| All | Attribute can be applied to any application element. |
一个简单的attribute的例子:
- using System;
- // define a custom attribute
- [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
- public class LazyPopulateAttribute : Attribute {
- Type _propType;
- public LazyPopulateAttribute(Type propType) {
- _propType = propType;
- }
- public Type PropertyType {
- get { return _propType; }
- }
- }
- public class Singleton {
- static Singleton _instance;
- private Singleton() { }
- // use the custom attribute
- [LazyPopulate(typeof(Singleton))]
- public static Singleton Instance {
- get { return _instance; }
- }
- }
- static class Program {
- static void Main(string[] args) {
- var instance = Singleton.Instance;
- // ...
- }
- }
上面的代码光是这么写的话,_instance没人赋过值,用起来显然有问题。但我们可以写一个程序在postbuild时分析程序集,提取出其中的attribute,并且让LazyPopulateAttribute指定的属性展开为典型的double-check初始化,Instance展开后应该变为:
- public static Singleton Instance {
- get {
- var instance = _instance;
- if (null == instance) {
- lock(_lockObj) { // _lockObj是应该生成的成员
- if (null == _instance) {
- _instance = instance = new Singleton();
- }
- }
- }
- return instance;
- }
- }
在运行时通过反射,PropertyInfo.GetCustomAttributes()就可以得到针对property的attribute信息。具体要如何实现这个例子里的postbuild处理,下一篇再写。
Java方面,支持3种内建的annotation,包括@Override、@Deprecated、@SuppressWarnings。
指定应用范围的ElementType枚举类型有以下成员:
| ANNOTATION_TYPE | Annotation type declaration |
| CONSTRUCTOR | Constructor declaration |
| FIELD | Field declaration (includes enum constants) |
| LOCAL_VARIABLE | Local variable declaration |
| METHOD | Method declaration |
| PACKAGE | Package declaration |
| PARAMETER | Parameter declaration |
| TYPE | Class, interface (including annotation type), or enum declaration |
在Java中自定义annotation类型的方法很简单,跟定义接口类似。使用@interface关键字来声明annotation类型,然后像声明方法一样声明其中的成员。与定义接口不同的是,annotation类型的成员可以带有default默认值声明。
- public @interface NotImplemented {
- public enum Severity { CRITICAL, HIGH, MEDIUM, LOW, NONE }
- Severity severity() default Severity.NONE;
- }
要说C# attribute跟Java annotation有什么关系,相同点是它们都是元数据的载体,差别恐怕主要在于两者的可应用范围不同了。可以看到,两者受到C#和Java语言本身的差异的影响,可应用的范围已经有所不同,例如C#可以对程序集或者模块应用attribute,但不能对命名空间应用;Java可以对包应用annotation,但不能对例如说JAR文件之类的不属于Java语言本身所支持的组织范围应用。
除去语言差异的影响,Java annotation有一个显著的特点就是它可以限定在别的annotation类型的定义上应用,也就是@Target({ElementType.ATTRIBUTE})。Java的@interface声明是extends java.lang.annotation.Annotation的语法糖,所以有@Target({ElementType.TYPE})的annotation也可以应用在annotation类型的定义上。在C#中,有[AttributeUsage(AttributeTarget.Class)]的attribute可以应用在任意类的定义上,而attribute本身就是个普通的类,所以自然也可以应用。不过在C#里无法直接定义出只能作用于attribute类型定义上的attribute,也就是说没有@Target({ElementType.ATTRIBUTE})的对应物,因而无法直接定义出专用的meta-annotation。这应该算是两者最大的区别了吧?
还有一个差异:C#的attribute总是能带到运行时的;Java的annotation则可以选择RetentionPolicy,可以是CLASS、RUNTIME或者SOURCE,所以不一定会带到运行时,甚至不一定会带到编译出来的.class文件里。javac可以挂上一些钩子,可以将annotation处理直接挂在编译过程中,所以SOURCE级的annotation很有意义。Project Lombok把这种能力发挥到了极致……最近不停看到它的消息,但一直没深入调查,真是罪过啊 =v=
不知道今天被问孤城的问题这样解答算不算对呢……?
说真的,上面提到的两个差异里,第二个我是前几天才刚看了一次的,不过被问的时候没想起来 T T 而第一个差异我一直没从“限制”的角度看,如果从“所有可应用范围”来看的话,我觉得还是C#的attribute范围大些,所以也是这么回答的。仔细想想,其实很难说谁大谁小,只能说设计得比较不同……
Java自定义注解小结
作者:谢伟伦
学习java有两年之余了,在很久之前,已经有位系统分析师告诉我,学习java,看java编程思想就够了。其言下之意,就是说,任何一切java框架,都是浮云,只有精通核心java,才是王道!
现在回想起来,这句话真的十分正确,一年多的工作,都只徘徊于学习java框架,造成自己是一个只会使用,不能原理的人。
趁着现在工作不忙,静下心来,好好学习一下核心java的基础。
今天早上,学习了java注解,这家伙以前经常用,但就是不知道其实现过程是如何,现在总算有所体会。
在一个java Project里,新建了三个类,其中有一个是java注解类,它们的源码如下:
package comm.annotation.test;
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.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
String author() default "william"; //定义"作者"参数
int size(); //定义"大小"参数
}
package comm.annotation.test;
@Description(author="helloworld",size=200)
public class DescriptionTest {
@SuppressWarnings(value="unchecked")
public static void main(String[] args) {
Class clazz = DescriptionTest.class;
if(clazz.isAnnotationPresent(Description.class)){
Description desc = (Description)clazz.getAnnotation(Description.class);
System.out.println("desc.author:" + desc.author());
System.out.println("desc.size:" + desc.size());
}else{
System.out.println("没有在DescriptionTest上使用注解!");
}
}
}
package comm.annotation.test;
public class SubDescriptionTest extends DescriptionTest{
@SuppressWarnings(value="unchecked")
public static void main(String[] args) {
Class clazz = DescriptionTest.class;
if(clazz.isAnnotationPresent(Description.class)){
Description desc = (Description)clazz.getAnnotation(Description.class);
System.out.println("desc.author:" + desc.author());
System.out.println("desc.size:" + desc.size());
}else{
System.out.println("没有在subDescriptionTest上使用注解!");
}
}
}
运行DescirptionTest和SubDescriptionTest两个java class,其输出的结果如下:
desc.author:helloworld
desc.size:200
我想说有三点:
(1) java annotation的基础语法
(2) java annotation的继承
(3) 关于对基于annotation框架的思考
第一点, 在源码里面,都说得十分简明了。更详尽的信息,请google一下。
第二点, 想的话就是“annotation与annotation之间没有继承关系”,只能用在类或接口里,由于在annotation类Description里面增加了@Inherited,因此,SubDescriptionTest直接拥有DescriptionTest其注解。
第三点, 在我古老的做法里,都用xml配置文件来让框架加载信息的,现在人们已经慢慢转向基于annotation方式来开发项目了,个人认为,利用java反射api,从注解处获得足够信息后,即可生成对象,与基于xml的配置效果是一样的。
接下来的时间,希望学习泛型这家伙,不能只看到外皮了。
Java和C#中的自定义元数据的更多相关文章
- Salesforce 自定义元数据类型
自定义元数据类型的优点 Salesforce中的设定都是以元数据(Metadata)存在的.在Salesforce中,用户可以新建自定义对象.自定义字段等,这些数据结构都以元数据的形式存储在系统中.当 ...
- Java:集合,对列表(List)中的自定义对象按属性(字段)排序(正序、倒序)的方法
1. 要求 对列表(List)中的自定义对象,要求能够按照对象的属性(字段)进行排序(正序.倒序). 如:用户对象(Member)有用户名(username).级别(level).出生日期(birth ...
- [转]Java中实现自定义的注解处理器
Java中实现自定义的注解处理器(Annotation Processor) 置顶2016年07月25日 19:42:49 阅读数:9877 在之前的<简单实现ButterKnife的注解功能& ...
- Java中的自定义注解
## 元注解 要声明一个注解, 我们需要元注解, 元注解是指注解的注解,包括@Retention, @Target, @Document, @Inherited. @Retention 注解的保留位置 ...
- Java基础__Java中自定义集合类
Java基础__Java中集合类 传送门 自定义MyArrayList集合实现:增加数据.取数据.查看集合中数据个数方法 package com.Gary; public class MyArrayL ...
- Java注解Annotation的用法 - 自定义Annotation实现
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据. Java语言中的类.方法.变量.参数和包等都可以被标注.和Javadoc不同,Java标注可以通过反射获取标 ...
- Android XML中引用自定义内部类view的四个why
今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑.虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结. 使用自定义内部类v ...
- .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)
阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
随机推荐
- uva 10125 二分
https://vjudge.net/problem/UVA-10125 和之前做过的一道a+b+c=X的问题类似,不过这个要求多了a+b+c=d-->a+b=d-c 且abcd互不相等 我们 ...
- Mac环境下Android Studio配置Git以及最基本使用
Git是分布式版本管理工具,现在使用十分广泛,相对于SVN,GIT的使用更加方便,在离线环境下,仍然可以进行版本控制工作.且速度十分快.在Windows下,先需要自行安装Git程序,网址git-scm ...
- python匿名函数 与 内置函数
一.匿名函数 1.定义: 匿名函数顾名思义就是指:是指一类无需定义标识符(函数名)的函数或子程序. 2.语法格式:lambda 参数:表达式 lambda语句中,开头先写关键字lambda,冒号 ...
- 异步请求(ajax,http) 之 逐渐完善的大全
异步请求在我们的开发之中是经常需要学习和理解的内容,我们将会在这一篇文章中依据不同的语言和环境内容进行归类讲解. JS: ajax是我们最为常用的页面异步请求,在只需要修改部分页面内容而不需要更换全部 ...
- 双系统在Linux下查看win的硬盘(Ubuntu 16.04 挂载Windows的 硬盘)
一般情况下,Linux的桌面系统能够直接查看到计算机各个硬盘的文件情况 但是,当我们想通过命令行查看Windows下的硬盘的时候,会发现在 /media/ (一般Windows下的盘会挂载到这里)文件 ...
- Android 中Activity,Window和View之间的关系
转自:http://hi.baidu.com/xiaofanqing/blog/item/8261ac114ab14f64cb80c435.html 我这里根据我个人的理解来讲讲我个人对这3个概念的理 ...
- dubbo常见报错
1. java.io.IOException: Can not lock the registry cache file C:\Users\Administrator\.dubbo\dubbo-reg ...
- Django与数据库操作
Django与数据库操作 数据库连接的方法 web 框架 django --- 自己内部实现 (ORM) + pymysql(连接) Flask,tornado --- pymysql SQLArch ...
- Android以root起一个process[shell脚本的方法]
有时候我们写的app要用uid=0的方式启动一个process,framework层和app层是做不到的,只有通过写脚本,利用am来实现.下面是具体步骤: 1.创建一个包含Main()方法Java p ...
- POJ1251 Jungle Roads
解题思路:看懂题意是关键,Kruskal算法,最小生成树模板. 上代码: #include<cstdio> #include<cstring> #include<algo ...