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();//枚舉值‘女’用此方法描述
}
}
瞌睡了,明天再續...........