http://docs.oracle.com/javase/
http://docs.oracle.com/javase/1.5.0/docs/guide/language/index.html
Generics
Enhanced for Loop
Autoboxing/Unboxing
Typesafe Enums
Varargs
Static Import
Metadata (Annotations)
一、Generics
一点感悟:泛型类就是模板类,泛型方法就是模板方法;如果使用泛型,代码在编译时没有警告和报错,运行时不会出现ClassCastException;
几个术语:
generic class:泛型类
generic method:泛型方法
type parameters :类型参数或类型变量(Pair<T>中T就是类型参数)
parameterized type:参数化类型 (Pair<String>整个),泛型类和泛型接口
wildcard type: 通配符类型
类型变量的限定或边界
raw type:原始类型
erased:擦除
supertype bound:超类型限定
1.泛型类
public class Pair<T>
{
//构造器名不需要加泛型
public Pair(){first = null;second = null;}
public Pair(T first,T second){this.first = first;this.second = second}
public T getFirst(){return first;}
public T getSecond(){return second;}
public void setFirst(T newValue){ first = new Value;}
public void setSecond(T newValue){second=newValue;}
private T first;
private T second;
}
注意点:
a. 泛型类可以有多个类型变量,如Pair<T,U>,用逗号分隔多个类型变量
b.类型变量使用大写形式,且比较短。使用变量E表示集合的元素类型,使用K表示key,使用V表示value。T和其临近的U、S表示“任意类型”
c.类和接口中的类型形参,只有在定义类、接口时才可以使用类型形参,当使用类、接口时应为类型参数传入实际的类型;
eg:
public interface BaseDao<T> {}
public class BaseDaoImpl<T> implements BaseDao<T> {
public interface CustomerDao extends BaseDao<Customer> {}
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {}
2.泛型方法:
public static <E> void swap(E[] a,int i, int j){
E temp = a[i];
a[i] = a[i];
a[j] = temp;
}
注意点:
a.类型变量放在修饰符的后面,返回值的前面;
b.泛型方法可以定义在普通类中,也可以定义在泛型类中;
c.当调用一个泛型方法时,在方法名前,对象或类“.”引用之后的尖括号中放入具体类型;不过大部分时候可以省略,编译器可根据传入方法的参数判断类型;
d.当方法的一个或多个参数之间存在依赖关系,或者方法返回值与参数之间存在依赖关系时,这时候可以使用泛型方法;
3.类型变量的限定:
a.一个类型变量或通配符可以有多个限定,多个限定类型之间用“&”分隔
eg:T extends Comparable & Serializable
b.限定中可以有多个接口,但最多有一个类,且若有类限定时,它必须是限定列表中的第一个
c.为了提高效率,应该将标签(tagging)接口(即没有方法的接口)放在边界列表的末尾;
4.类型擦除:
虚拟机中没有泛型,只有普通的类和方法;虚拟机中,所有类型参数都用他们的第一个限定类型替换;没有限定的类型变量用Object替换。这一过程就是“类型擦除”;
5.泛型的约束和限制:
a.不能用基本类型实例化类型参数;
b.类型查询只产生原始类型;
eg:if(a instanceof Pair<String>) 等价于 if(a instanceof Pair)
eg2:
Pair<String> strPair= ...
Pair<Employ> employPair=...
if(strPair.getClass()==employPair.getClass()){//这个条件return true
}
c.不能抛出也不能捕获泛型类实例,但在异常声明中可以使用类型变量;
正确例子:
public static <T extends Throwable> void doWork(T t) throws T//OK{
try{
}catch(Throwable realCause){
t.initCause(realCause);
throw t;
}
}
d:不能声明参数化类型的数组
e:不能实例化类型变量
f:禁止使用带有类型变量的静态域和方法
eg:
static T getInstance(); //error
static T instance;//error
g:禁止一个类或类型变量不能同时成为两个接口类型(这两个接口是同一接口的不同参数化)的子类;
h:定义泛型方法时,注意考虑方法擦除后,是否与已有方法重复;
L:S extends T ,但Pare<S>与Pare<T>没有继承关系;类型变量之间是否存在继承关系,与参数化类之间的继承关系无关;
5.通配符类型
Pair<? extends Employee>
6.通配符的超类型限定
Pair<? super Manager>
带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。
? super Manager这样的带有上边界的类型变量可以作为方法参数,但不能作为方法的返回值;
7.无限定通配符
Pair<?>:问号表示未知的任意类型,Pair<?>只可以作为方法参数使用,不可以用来extends和implements;
Pair<?>只能调Pair的get方法;
List<?>中的元素为Object类型;
8.通配符不是类型变量,不可以作为返回值类型:? t= p.getFirst();//Error
9.Class类是泛型的,String.classs实际是一个Class<String>类的对象;
10.泛型的反射:
Type接口(表达泛型类型)
Class类 implements Type(具体类型)
TypeVariable接口(类型变量:T extends Comparable<? super T>)extends type
WildcardType接口(通配符:? super T)extends type
ParameterizedType接口(泛型类和泛型接口:Comparable<? super T>)extends type
GenericArrayType接口(泛型数组:T[])extends type
=========================
metadata annotation
=========================
Metadata (Annotations)
术语:
APT:annotation processing tool 访问和处理annotation的工具
annotation:注解
meta annotation元注解:@Target和@Retention是元注解,用在注解的定义中
marked annotation标识注解:
single value annotation单值注解:
一、最常见的三个Annotation:
1.@Override:
检查该方法是否覆盖了某一个超类方法
package java.lang;
import java.lang.annotation.*;
/**
* Indicates that a method declaration is intended to override a
* method declaration in a superclass. If a method is annotated with
* this annotation type but does not override a superclass method,
* compilers are required to generate an error message.
*
* @author Joshua Bloch
* @since 1.5
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
说明:
@Override这个注解的作用是告诉编译器检查这个方法,
并从父类中查找是否包含一个被该方法重写的方法,否则编译器报错;
这个Annotation的作用是为了避免重写父类方法时,没有正确覆盖,但编译期并不抛错这种情况;
2.@Deprecated:
标记为已过时
package java.lang;
import java.lang.annotation.*;
/**
* A program element annotated @Deprecated is one that programmers
* are discouraged from using, typically because it is dangerous,
* or because a better alternative exists. Compilers warn when a
* deprecated program element is used or overridden in non-deprecated code.
*
* @author Neal Gafter
* @version 1.5, 11/17/05
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}
说明:
@Deprecated表示某个程序元素(接口、类、方法等)已过时,当其它程序使用已过时的类时,编译器将会给出警告;
3.@SuppressWarnings:
阻止某个给定类型的警告信息
eg:@SuppressWarnings("unchecked")
package java.lang;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import static java.lang.annotation.ElementType.*;
/**
* Indicates that the named compiler warnings should be suppressed in the
* annotated element (and in all program elements contained in the annotated
* element). Note that the set of warnings suppressed in a given element is
* a superset of the warnings suppressed in all containing elements. For
* example, if you annotate a class to suppress one warning and annotate a
* method to suppress another, both warnings will be suppressed in the method.
*
* <p>As a matter of style, programmers should always use this annotation
* on the most deeply nested element where it is effective. If you want to
* suppress a warning in a particular method, you should annotate that
* method rather than its class.
*
* @since 1.5
* @author Josh Bloch
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
/**
* The set of warnings that are to be suppressed by the compiler in the
* annotated element. Duplicate names are permitted. The second and
* successive occurrences of a name are ignored. The presence of
* unrecognized warning names is <i>not</i> an error: Compilers must
* ignore any warning names they do not recognize. They are, however,
* free to emit a warning if an annotation contains an unrecognized
* warning name.
*
* <p>Compiler vendors should document the warning names they support in
* conjunction with this annotation type. They are encouraged to cooperate
* to ensure that the same names work across multiple compilers.
*/
String[] value();
}
说明:
@SuppressWarnings指示被annotation标识的程序元素(以及在该程序元素中的所有子元素)取消显示指定的编译器警告;
@SuppressWarnings会一直作用于该程序元素的所有子元素;例如使用@SuppressWarnings标识一个类来取消显示某个编译器警告,
同时又标识该类里某个方法取消显示另一个编译器警告,那么将在此方法中同时取消显示这两个编译器警告;
通常,如果集合没有使用泛型,编译器会警告,这时可以用@SuppressWarnings;
二、自定义Annotation:
语法:
[修饰符] @interface [注解名称]{
[java类型] elementName();
[java类型] elementName() default value;
}
使用时@AnnotationName(name1=value1,name2=value2,name3={arrayValue1,arrayValue2,...}...)
注解元素的类型:
基本类型、String、Class(具有一个可供选择的类型参数,如Class<?>或Class<? extends MyClass>)、enum、注解、
由上述类型组成的数组;
下面的注解都位于java.lang.annotation包中;
1.@Target :
package java.lang.annotation;
/**
* Indicates the kinds of program element to which an annotation type
* is applicable. If a Target meta-annotation is not present on an
* annotation type declaration, the declared type may be used on any
* program element. If such a meta-annotation is present, the compiler
* will enforce the specified usage restriction.
*
* For example, this meta-annotation indicates that the declared type is
* itself a meta-annotation type. It can only be used on annotation type
* declarations:
* <pre>
* @Target(ElementType.ANNOTATION_TYPE)
* public @interface MetaAnnotationType {
* ...
* }
* </pre>
* This meta-annotation indicates that the declared type is intended solely
* for use as a member type in complex annotation type declarations. It
* cannot be used to annotate anything directly:
* <pre>
* @Target({})
* public @interface MemberType {
* ...
* }
* </pre>
* It is a compile-time error for a single ElementType constant to
* appear more than once in a Target annotation. For example, the
* following meta-annotation is illegal:
* <pre>
* @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
* public @interface Bogus {
* ...
* }
* </pre>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
说明:
1.@Target元注解可以应用于一个注解,以限制该注解可以应用到哪些项上;
@Target注解的元素类型:
ElementType.ANNOTATION_TYPE:在注解这种类型上使用,Annotation type declaration;
ElementType.PACKAGE:在包上使用,Package declaration
ElementType.LOCAL_VARIABLE:在局部变量上使用,Local variable declaration
ElementType.CONSTRUCTOR:在构造器上使用,Constructor declaration
ElementType.PARAMETER:在方法或构造器参数上使用,Parameter declaration
ElementType.METHOD:在方法上使用,Method declaration
ElementType.FIELD:在成员变量上使用,Field declaration (includes enum constants)
ElementType.TYPE:在类、接口、注解类、枚举类上使用,Class, interface (including annotation type), or enum declaration
一条没有@Target的限制的注解可以应用于任何项上。
编译器只检查你是否将一条注解应用到了某个允许的的项上。
2.@Retention:
/**
* Indicates how long annotations with the annotated type are to
* be retained. If no Retention annotation is present on
* an annotation type declaration, the retention policy defaults to
* <tt>RetentionPolicy.CLASS</tt>.
*
* <p>A Target meta-annotation has effect only if the meta-annotated
* type is use directly for annotation. It has no effect if the meta-annotated
* type is used as a member type in another annotation type.
*
* @author Joshua Bloch
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
说明:
@Retention元注解用于指定一条注解应该保留多长时间。其默认值是RetentionPolicy.CLASS;
@Retention的保留策略:
RetentionPolicy.SOURCE:
Annotations are to be discarded by the compiler.
不被编译器保留,源码级别,未被包含在类文件中,无法反射访问
RetentionPolicy.CLASS:
Annotations are to be recorded in the class file by the compiler
but need not be retained by the VM at run time. This is the default
behavior.
保留到编译期,类文件级别,编译器会将他们置于类文件中
RetentionPolicy.RUNTIME:
Annotations are to be recorded in the class file by the compiler and
retained by the VM at run time, so they may be read reflectively.
保留到运行期,编译器会将他们置于类文件中,并且虚拟机会将它们载入
3.enum ElementType:
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE
}
4.enum RetentionPolicy:
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
5.@Documented
/**
* Indicates that annotations with a type are to be documented by javadoc
* and similar tools by default. This type should be used to annotate the
* declarations of types whose annotations affect the use of annotated
* elements by their clients. If a type declaration is annotated with
* Documented, its annotations become part of the public API
* of the annotated elements.
*
* @author Joshua Bloch
* @version 1.6, 11/17/05
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
说明:
@Documented元注解,被@Documented标识的注解,称为文档化注解,当注解到目标上时,生成的文档中将显示注解信息;
即:被元注解@Documented修饰的Annotation类将被javadoc工具提取成文档;
6.@Inherited:
只能应用于对类的注解,
如果一个类具有继承注解,那么这个类的所有子类都自动具有该注解;
/**
* Indicates that an annotation type is automatically inherited. If
* an Inherited meta-annotation is present on an annotation type
* declaration, and the user queries the annotation type on a class
* declaration, and the class declaration has no annotation for this type,
* then the class's superclass will automatically be queried for the
* annotation type. This process will be repeated until an annotation for this
* type is found, or the top of the class hierarchy (Object)
* is reached. If no superclass has an annotation for this type, then
* the query will indicate that the class in question has no such annotation.
*
* <p>Note that this meta-annotation type has no effect if the annotated
* type is used to annotate anything other than a class. Note also
* that this meta-annotation only causes annotations to be inherited
* from superclasses; annotations on implemented interfaces have no
* effect.
*
* @author Joshua Bloch
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
三、注解的用途:
自动生成包含程序额外信息的“附文件”。
附属文件的自动生成,例如部署描述符或者bean信息类;
测试、日志、事务语义等代码的自动生成;
四、注意点:
1.注解不会改变对编写的程序的编译方式。java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令;
2.注解当做修饰符来使用,
3.Javadoc注解出现在/**..*/定界符的内部,而注解是代码的一部分;
4.注解可用在方法、类、包、接口、成员变量、局部变量、构造器、枚举类上;
5.注解可以放在修饰符所在的任意位置,但通常放在最前面并且置于上一行处;
6.@interface前只能有两种修饰符,public或不加(即default),还有abstract
7.@interface隐式的实现了接口java.lang.annotation.Annotation;这个接口含有方法:equals、hashCode()、toString、 Class<? extends Annotation> annotationType(),java.lang.annotation.Annotation是正规接口,开发者不能扩展此接口;
8.注解接口中的元素的顺序无关紧要;
9.如果使用注解时,某个元素的值并未指定,那么就是用声明的默认值;
10.简化的形式:
如果没有指定元素,要么是因为注解中没有任何元素,要么是因为所有元素都是用默认值,那么你就不需要使用括号了;这样的注解叫“marked annotation”
11.单值注解:如果注解中只有一个元素,且元素名字是value;那么在使用时,你可以不写元素名和等号;
12.注解接口的元素声明实际上就是方法的声明,一个注解接口的方法可以没有任何参数,没有任何throws语句,并且他们也不能是泛型的;
13.一个注解元素不能设置为null,默认值也不能设置为null,但可以设置默认值为Void.class
14.注解中可以修饰:
包、类(包括enum)、接口(包含注解接口)、方法、构造器、实例成员(包含enum常量)、本地变量、参数变量
对本地变量的注解只能在源码级别上进行处理;
15.元注解:用于描述注解接口的行为属性;
16.要用反射处理的注解,应该定义为@Retention(RetentionPolicy.RUNTIME)
17.@Retention(RetentionPolicy.SOURCE)表示:被修饰的注解仅在class文件中保留,运行时不能通过反射来读取该注解的信息;
eg:
public @interface ActionListenerFor{
String value();
}
使用时,@ActionListenerFor("redButton")
五、注解的解析:
1.运行时注解的解析:
接口:AnnotatedElement-->表示注解可标识的目标元素
其实现类有:
Class:类定义;
Contructor:构造器定义;
Field:类的成员变量的定义;
Method:类的方法的定义;
Package:类的包的定义;
public interface AnnotatedElement {
//判断该程序元素上是否包含指定的注释,存在返回true,否则false
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
//返回该程序元素上存在的、指定类型的注释,如果该类型的注释不存在,则返回null;
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
//返回该程序元素上存在的所有注释
Annotation[] getAnnotations();
Annotation[] getDeclaredAnnotations();
}
获得某个类的某个方法的所有注解:
Annotation[] anns = Class.forName("XXXClass").getMethod("XXXMethod").getAnnotations();
2.源码级注解的处理:
使用APT解析;
利用jdk下的tools.jar,它包含4个包:
com.sun.mirror.apt.*:和APT交互的接口
com.sun.mirror.declaration.*:包含各种封装类成员、类方法、类声明的接口;
com.sun.mirror.type.*:包含各种封装源代码中程序元素的接口
com.sun.mirror.util.*:提供了用于处理类型和声明的一些工具;
也可利用doclet API(即Javadoc API),也位于tools.jar中
eg:
源码级annotation:
package com.gavin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface CodeTag {
String authorName();
String lastModificationDate();
String bugfixes() default "";
}
应用此注解:
package com.gavin.annotation;
@CodeTag(authorName="gavin",lastModificationDate="Aug 16, 2003")
public class Test3 {
@CodeTag(authorName="sophia",lastModificationDate="May 16, 2003",bugfixes="BUG0001")
public void setName(){
System.out.println("setName");
}
@CodeTag(authorName="alen",lastModificationDate="Mar 16, 2003",bugfixes="BUG0002")
public void setCode(){
System.out.println("setCode");
}
}
利用doclet api分析Test3文件中的注解:
package com.gavin.annotation;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doclet;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;
public class SourceTypeMetadataDoclet2 extends Doclet {
public static boolean start(RootDoc root){
ClassDoc[] classes = root.classes();
for(ClassDoc cd : classes){
showAnnotations(cd);
}
return true;
}
private static void showAnnotations(ClassDoc cd) {
process(cd.annotations());
for(MethodDoc md : cd.methods()){
process(md.annotations());
}
}
private static void process(AnnotationDesc[] annotations) {
for(AnnotationDesc ad : annotations){
AnnotationDesc.ElementValuePair evp[] = ad.elementValues();
for(AnnotationDesc.ElementValuePair e :evp){
System.out.println("name:"+e.element()+" ,value="+e.value());
}
}
}
}
利用javadoc命令,运行结果:
3.字节码级注解的处理
示例:
eg1:点击面板中不同的按钮切换不同的颜色:
package com.gavin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionListenerFor {
String source();
}
package com.gavin.annotation;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonFrame extends JFrame{
JPanel panel = null;
JButton blueBtn = null;
JButton redBtn = null;
JButton yellowBtn = null;
public ButtonFrame(){
setTitle("ButtonTest");
panel = new JPanel();
add(panel);
yellowBtn = new JButton("yellow");
blueBtn = new JButton("blue");
redBtn = new JButton("red");
panel.add(yellowBtn);
panel.add(blueBtn);
panel.add(redBtn);
try {
ActionListenerInstaller.processAnnotations(this);
} catch (Exception e) {
e.printStackTrace();
}
}
@ActionListenerFor(source="yellowBtn")
public void yellowBackground(){
panel.setBackground(Color.yellow);
}
@ActionListenerFor(source="blueBtn")
public void blueBackground(){
panel.setBackground(Color.blue);
}
@ActionListenerFor(source="redBtn")
public void redBackground(){
panel.setBackground(Color.red);
}
public static void main(String[] args) {
ButtonFrame frame = new ButtonFrame();
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
package com.gavin.annotation;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 解析@ActionListenerFor,实现根据事件源名称,
* 自动调用被注解的方法
*/
public class ActionListenerInstaller {
/**
* @param obj 要处理的类的实例,这里是ButtonFrame的实例this;
* @throws Exception
*/
public static void processAnnotations(Object obj) throws Exception {
Class<?> cl = obj.getClass();
for(Method m : cl.getDeclaredMethods()){
ActionListenerFor a = m.getAnnotation(ActionListenerFor.class);
if(a != null){
String fieldName = a.source();
Field f = cl.getDeclaredField(fieldName);//获得成员变量
f.setAccessible(true);//避免private不可访问;
//为obj中成员变量的实际值或实例,这里是各个JButton,添加被注解的方法,这里是setBackground()
addListener(f.get(obj),obj,m);
}
}
}
/**
* 为事件源添加ActionListener,并在listener中动态调用被注解的方法,
* 相当于实现了actionPerform方法
* @param source 事件源
* @param param 方法的调用者
* @param m 被注解的方法
* @throws Exception
*/
private static void addListener(Object source,final Object param, final Method m) throws Exception {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return m.invoke(param);
}
};
/*
Returns an instance of a proxy class for the specified interfaces
that dispatches method invocations to the specified invocation handler.
返回一个给定的接口ActionListener代理类的实例,这个接口将分发mehtod给指定的handler处理
This method is equivalent to:
Proxy.getProxyClass(loader, interfaces).
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
*/
Object listener = Proxy.newProxyInstance(null, new Class[]{java.awt.event.ActionListener.class}, handler);
Method adder = source.getClass().getMethod("addActionListener", ActionListener.class);
adder.invoke(source, listener);
}
}
eg2:用注解生成Person.hibernate.xml:
cmd命令:apt -factory HibernateAnnotationFactory Person.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Persistent {
String table();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Property {
String column();
String type();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface IDProperty {
String column();
String type();
String generator();
}
@Persistent(table = "persons_table")
public class Person {
@IDProperty(column="person_id",type="integer",generator="identity")
private int id;
@Property(column="person_name",type="string")
private String name;
@Property(column="person_age",type="integer")
private int age;
...
}
package com.gavin.annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
public class HibernateAnnotationFactory implements AnnotationProcessorFactory {
@Override
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> arg0,
AnnotationProcessorEnvironment env) {
return new HibernateAnnotationProcessor(env);
}
@Override
public Collection<String> supportedAnnotationTypes() {
return Arrays.asList("Property","IDProperty","Persistent");
}
@Override
public Collection<String> supportedOptions() {
return Arrays.asList(new String[0]);
}
}
package com.gavin.annotation;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
public class HibernateAnnotationProcessor implements AnnotationProcessor {
private AnnotationProcessorEnvironment env;
public HibernateAnnotationProcessor(AnnotationProcessorEnvironment env){
this.env = env;
}
@Override
public void process() {
for(TypeDeclaration t : env.getSpecifiedTypeDeclarations()){
FileOutputStream fos = null;
String clazzName = t.getSimpleName();
Persistent per = t.getAnnotation(Persistent.class);
if(per != null){
try {
fos = new FileOutputStream(clazzName + ".hbm.xml");
PrintStream ps = new PrintStream(fos);
ps.println("<?xml version=\"1.0\"?>");
ps.println("<!DOCTYPE hibernate-mapping");
ps.println(" PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"");
ps.println("<hibernate-mapping>");
ps.println("<class name=\""+t);
ps.println("\" table =\"" + per.table() + "\">");
for(FieldDeclaration f : t.getFields()){
IDProperty id = f.getAnnotation(IDProperty.class);
if(id!=null){
ps.println("<id name=\"" + f.getSimpleName() +
"\" column=\"" + id.column() +
"\" type=\"" + id.type() +
"\">");
ps.println("<generator class=\""+id.generator()+"\"/>");
ps.println(" </id>");
}
Property p = f.getAnnotation(Property.class);
if(p!=null){
ps.println("<property name=\"" + f.getSimpleName() +
"\" column=\"" + id.column() +
"\" type=\"" + id.type() +
"\"/>");
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
==============================
Typesafe Enums
==============================
一、术语:
enum constant:枚举常量,即枚举类的实例
enum type:枚举类或枚举类的镜像
二、枚举的内部实现:
枚举是指一个经过排序的,被打包成一个单一实体的项列表;
package com.gavin.enums;
public class Sex {
//属性为final类型,属性不可变的
private final String name;
public static final Sex MALE = new Sex("男");
public static final Sex FEMALE = new Sex("女");
//构造器为private
private Sex(String name){
this.name = name;
}
public static Sex getSex(int index){
switch(index){
case 1:
return MALE;
case 2:
return FEMALE;
default:
return null;
}
}
public String getName(){
return name;
}
}
三、枚举的优点:
1.可以使程序更加健壮,避免创建对象的随意性;
四、枚举与常量(public static final int或其它类型)的比较:
1.常量由于可以运算,类型不安全;
2.没有命名空间
3.打印输出的意义不明确
4.枚举可用于switch语句中;
五、枚举类与普通类的区别:
枚举类构造器是私有的;
枚举类继承于Enum类而不是Object类
枚举类的所有实例必须在枚举类中显示列出;这些实例系统会自动添加public static final修饰,
枚举类不可以继承,但可以实现接口
枚举类都提供了values()静态方法,用于遍历所有枚举常量
枚举类的实例只能是枚举值,而不是随意的通过new来创建枚举对象;
六、枚举的注意点:
1.比较两个枚举的值时,永远不要用equals,而直接使用“==”就可以了;
2.所有的枚举类都是Enum类的子类;隐式的,自定义枚举时,不需要显示继承;
它们继承了Enum类的toString等大多数方法,toString方法能够返回枚举常量名;
toString()的逆方法是valueOf()静态方法,它根据枚举常量名和枚举类的镜像,返回枚举类的实例;
WorkDayEnum w = (WorkDayEnum)Enum.valueOf(WorkDayEnum.class,"Tuesday")
3.枚举是一个特殊的类,所以可以有构造器、方法、属性,可以实现接口;
4.每个枚举类都有一个静态的values方法,它将返回一个包含全部枚举值的数组;
WorkDayEnum[] workdayArray = WorkDayEnum.values();
5.ordinal()方法:int position = WorkDayEnum.Tuesday.ordinal();
6.枚举类的实例就是各个枚举常量;
7.枚举类默认继承的Enum类,而不是Object类;
8.枚举类的构造器只能是private,省略了修饰符,默认表示用private修饰;
9.Switch语句里的表达式可以是枚举值
10.使用时,通过WorkdayEnum.Tuesday这样引用;
11.不能标记一个enum为abstract的,除非每一个常量都有一个类主体,而且这些类主体覆盖了enum中的抽象方法;
eg:switch(Sex s){
case MALE:
case FEMALE:
}
七、示例:
eg1:
package com.gavin.enums;
public class Sex {
//属性为final类型,属性不可变的
private final String name;
public static final Sex MALE = new Sex("男");
public static final Sex FEMALE = new Sex("女");
//构造器为private
private Sex(String name){
this.name = name;
}
public static Sex getSex(int index){
switch(index){
case 1:
return MALE;
case 2:
return FEMALE;
default:
return null;
}
}
public String getName(){
return name;
}
}
eg2:
package com.gavin.enums;
public enum Gender {
MALE,FEMALE;
public String name;
public static void main(String[] args){
Gender g = Enum.valueOf(Gender.class, "MALE");
g.name = "男";
System.out.println(g + g.name);//MALE男
}
}
eg3:
package com.gavin.enums;
public enum Gender2 {
//在枚举类中列出枚举值的过程就是调用构造器创建枚举对象的过程
MALE("男"),FEMALE("女");
/*
相当于:
public static final Gender2 MALE = new Gender2("男");
public static final Gender2 FEMALE = new Gender2("女");
*/
private final String name;
private Gender2(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public static void main(String[] args){
Gender2 g = Enum.valueOf(Gender2.class, "MALE");
System.out.println(g + g.getName());//MALE男
}
}
eg4:
package com.gavin.enums;
public enum Gender3 implements Info{
//在枚举类中列出枚举值的过程就是调用构造器创建枚举对象的过程
MALE("男"),FEMALE("女");
/*
相当于:
public static final Gender2 MALE = new Gender2("男");
public static final Gender2 FEMALE = new Gender2("女");
*/
private final String name;
private Gender3(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public static void main(String[] args){
Gender3 g = Enum.valueOf(Gender3.class, "MALE");
System.out.println(g + g.getName());//MALE男
g.info();
Gender3.FEMALE.info();
}
@Override
public void info() {
System.out.println("每个枚举值即枚举实例都用此方法描述");
}
}
interface Info{
void info();
}
eg5:
package com.gavin.enums;
public enum Gender4 implements Info{
//在枚举类中列出枚举值的过程就是调用构造器创建枚举对象的过程
MALE("男"){
@Override
public void info() {
System.out.println("枚举值‘男’用此方法描述");
}
@Override
public boolean canGiveBirth2Child() {
System.out.println("这个真没有");
return false;
}
},FEMALE("女"){
@Override
public void info() {
System.out.println("枚举值‘女’用此方法描述");
}
@Override
public boolean canGiveBirth2Child() {
System.out.println("这个可以有");
return true;
}
};
/*
相当于:
public static final Gender2 MALE = new Gender2("男"){
@Override
public void info() {
System.out.println("枚举值‘男’用此方法描述");
}
};
public static final Gender2 FEMALE = new Gender2("女"){
@Override
public void info() {
System.out.println("枚举值‘男’用此方法描述");
}
};
*/
private final String name;
private Gender4(String name){
this.name = name;
}
public String getName(){
return this.name;
}
//该抽象方法由不同枚举值提供不同的实现;
public abstract boolean canGiveBirth2Child();
public static void main(String[] args){
Gender4 g = Enum.valueOf(Gender4.class, "MALE");
System.out.println(g + g.getName());//MALE男
g.info();//枚举值‘男’用此方法描述
Gender4.FEMALE.info();//枚举值‘女’用此方法描述
}
}
瞌睡了,明天再续...........