JavaEnhance——枚舉、註解及泛型

枚舉


一、概述

如果一個變量的取值要被限定在一定的範圍內,例如星期的取值,限定在1~7的範圍內,並且想要在編譯期就能指出變量取值超出範圍的錯誤,就可以使用枚舉。枚舉相當於一個類,其中也可以定義構造方法,成員變量,普通方法和抽象方法。

二、枚舉的應用

1.使用普通類模擬枚舉

使用普通類模擬枚舉的時候,首先將構造方法私有化,然後在類的內部創建常量,那麼其他類在調用這個類的時候,只能得到模擬枚舉類中的常量,不能new出新的值。

示例代碼:

package com.heisejiuhuche.javaenhance;

public abstract class WeekDay {
    //私有化構造方法
    private WeekDay() {}
    //創建靜態常量
    public static final WeekDay SUN = new WeekDay();

    public static final WeekDay MON = new WeekDay();

}

package com.heisejiuhuche.javaenhance;

public class EnumTest {
    public static void main(String[] args) {
    //通過類名得到靜態常量,賦值給WeekDay的對象
    WeekDay weekDay = WeekDay.MON;
}

這樣就實現了一個最基本的枚舉類,除了類中定義的兩個常量外,不可能再爲weekDay賦另外的值。接下來,可以在模擬枚舉類中加入方法。

示例代碼:

package com.heisejiuhuche.javaenhance;

public abstract class WeekDay {
    private WeekDay() {}

    public static final WeekDay SUN = new WeekDay();

    public static final WeekDay MON = new WeekDay();

    /* nextDay()方法返回下一天 */
    public WeekDay nextDay() {
        if(this == SUN) {
            return MON;
        } else {
            return SUN;
        }
    }

    /* toString()方法打印信息 */
    public String toString() {
        return this == SUN ? "SUN" : "MON";
    }
}

這裏只寫了兩個常量,如果有七個,那麼這個nextDay()方法中的if else語句就會很長,爲了避免長代碼,可以將nextDay()定義爲抽象方法,由每個子類對象去實現。

示例代碼:

package com.heisejiuhuche.javaenhance;

public abstract class WeekDay {
    private WeekDay() {}

    public static final WeekDay SUN = new WeekDay() {
        //每個對象實現抽象方法
        public WeekDay nextDay() {
            return MON;
        }
    };

    public static final WeekDay MON = new WeekDay() {
        public WeekDay nextDay() {
            return SUN;
        }
    };

    /* nextDay()聲明爲抽象方法 */
    public abstract WeekDay nextDay();

}

用抽象方法可以將大量的if else語句轉換成由一個個獨立的子類來實現該抽象方法,簡化了代碼。

2.定義枚舉類
在用普通類模擬了枚舉類之後,現在定義一個真正的枚舉類。在類中定義一個內部枚舉類。

示例代碼:

package com.heisejiuhuche.javaenhance;

public class EnumTest {
    public static void main(String[] args) {
        /* 定義枚舉變量 */
        WeekDay weekDay2 = WeekDay.FRI;
        System.out.println(weekDay2);
        /* 得到weekDay2的名字 */
        System.out.println(weekDay2.name());
        /* 得到weekDay2的位置 */
        System.out.println(weekDay2.ordinal());
        /* 得到weekDay2的字節碼文件 */
        System.out.println(weekDay2.getClass());
        /* 將字符串SUN轉換成枚舉成員 */
        System.out.println(WeekDay.valueOf("SUN"));
        /* 將枚舉成員轉換成枚舉數組 */
        System.out.println(WeekDay.values().length);

    }

    /* 聲明枚舉類 */
    public enum WeekDay {
        SUN, MON, TUE, WED, THU, FRI, SAT;

    }
}

枚舉類內部實現了toString()方法。下面爲枚舉類定義構造方法。

示例代碼:

public enum WeekDay {
    SUN, MON, TUE, WED, THU, FRI, SAT;
    private WeekDay() {

    }
}

//聲明有參數的構造方法:
public enum WeekDay {
    SUN, MON, TUE, WED, THU, FRI, SAT;
    private WeekDay() {

    }

    private WeekDay(int day) {

    }
}

默認情況下,枚舉的成員使用的都是無參構造方法。只要用到枚舉類,裏面的所有靜態成員都會被初始化。如果指定要調用有參構造方法,只需在枚舉成員後加上小括號,寫入參數即可。

示例代碼:

public enum WeekDay {
    //調用指定構造方法
    SUN(1), MON, TUE, WED, THU, FRI, SAT;
    private WeekDay() {
        System.out.println("first");
    }

    private WeekDay(int day) {
        System.out.println("second");
    }
}

最最複雜的枚舉,就是帶有抽象方法的枚舉,下面運用枚舉實現一個交通燈系統。

示例代碼:

public enum TrafficLight {
    //三個枚舉對象,分別實現nextLight()方法
    RED {
        public TrafficLight nextLight() {
            return GREEN;
        }
    },

    GREEN {
        public TrafficLight nextLight() {
            return YELLOW;
        }
    },

    YELLOW {
        public TrafficLight nextLight() {
            return RED;
        }
    };
    //聲明nextLight()抽象方法,由子類對象去實現
    public abstract TrafficLight nextLight();
}

三、枚舉總結

1.枚舉元素必須位於枚舉體中的最開始部分,枚舉元素列表的後面要有分號與其他成員分隔。把枚舉中的成員方法或變量等放在枚舉元素的前面, 編譯器會報錯。

2.帶構造方法的枚舉

(1) 構造方法必須定義成私有
(2) 如果有多個構造方法,在枚舉元素後面加上小括號來調用指定的構造方法
(3) 枚舉元素MONMON()的效果一樣,都是調用默認的構造方法

3.帶抽象方法的枚舉

每個元素都是由枚舉類的子類來生成的實例對象,這些子類可以採用類似內部類的方式來定義並實現枚舉中的抽象方法。

4.枚舉只有一個成員時,就可以作爲一個單例的實現方式。


註解


一、概述

註解是JDK1.5開始的新特性,一個註解就是一個類,運用註解的時候就是創建了一個註解的實例對象。現行的框架,如HibernateSpringEJB以及Struts2的一部分,都是基於註解技術。註解相當於一個標記,可以添加在包、類、字段、方法、方法的參數以及局部變量上。

二、常見註解

1.@SuppressWarnings
該註解用於去除編譯期出現的警告提示,如調用了過時方法時的警告提示

2.@Deprecated
該註解用於標識一個方法等已經過時,不建議使用;添加了該註解的方法等,或被一根橫線劃過

3.@Override
該註解用於標識一個方法是其父類中方法的複寫;如果方法與父類中的方法不一致,會得到報錯提示

三、元註解

元註解就是添加在註解類上的註解,用於標識該註解的生命週期以及可以添加的位置等。

1.@Retention

@Retention註解有三個取值,分別對應着註解的生命週期,它們是:
@RetentionPolicy.SOURCE@RetentionPolicy.CLASS@RetentionPolicy.RUNTIME
由於javac在編譯源文件的時候或是classLoaderclass文件加載到內存的過程中,會將一些註解去掉,會導致註解失效

2.@Target
@Target元註解接收一個ElementType數組作爲參數,指定某個註解類能被添加到哪些地方
@Target({ElementType.METHOD, ElementType.TYPE})表示這個註解能被添加到方法和類上

四、註解的應用

1.創建自定義註解
註解是一個類似接口的類,用@interface + 類名來表示。

示例代碼:

package com.heisejiuhuche.javaenhance;

public @interface MyAnnotation {}

將自定義註解類添加到一個類上

示例代碼:

package com.heisejiuhuche.javaenhance;

@MyAnnotation
public class AnnotationTest {

    public static void main(String[] args) {
        if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation ma = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);

            System.out.println(ma);
        }
    }
}

程序無打印結果,是因爲自定義註解上沒有添加標識該註解聲明週期的元註解。

添加元註解:

package com.heisejiuhuche.javaenhance;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

這樣,就可以打印出註解信息。

五、爲註解添加屬性

Java可以爲註解增加屬性,以便更好地使用註解。註解是一個類似接口的類,屬性以抽象方法形式出現。

示例代碼:

package com.heisejiuhuche.javaenhance;

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.METHOD, ElementType.TYPE})
public @interface MyAnnotation {
    /* 字符串屬性 */
    String color() default "blue";
    String value();
    /* 數組屬性 */
    int[] arrayAttr() default {3, 4, 5};
    /* 枚舉屬性 */
    TrafficLight light() default TrafficLight.RED;
    /* 註解屬性 */
    Anno anno() default @Anno("itheima");
}

爲屬性賦值並調用:

package com.heisejiuhuche.javaenhance;


@MyAnnotation(color = "red", value = "abc", arrayAttr=1, anno=@Anno("mars")) //數組類型的屬性只有1個元素的時候可以不加大括號
public class AnnotationTest {
    @MyAnnotation("abc")
    public static void main(String[] args) {
        if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation ma = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
            System.out.println(AnnotationTest.class.getAnnotation(MyAnnotation.class));
            System.out.println(ma);
            System.out.println(ma.arrayAttr().length); //大印數組長度
            System.out.println(ma.light().nextLight()); //調用枚舉方法
            System.out.println(ma.anno()); //打印註解屬性
        }
    }
}

泛型高級應用


泛型高級應用中,演示如何通過反射的方法拿到泛型的類型。想要直接通過一個帶有泛型的類來獲取該泛型的類型是不行的,只有通過一個接收該泛型類的方法來實現。

示例代碼:

package com.heisejiuhuche.javaenhance;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Vector;

public class GenericTest {
    public static void main(String[] args) throws Exception {
        //得到所有泛型參數的類型數組
        Type[] types = GenericTest.class.getMethod("applyGeneric", Vector.class).getGenericParameterTypes();
        //得到泛型類型的對象
        ParameterizedType paraType = (ParameterizedType)types[0];
        //打印泛型類型對象的原始類型
        System.out.println(paraType.getRawType());
        //打印泛型類型對象的泛型的類型,getActualTypeArguments方法返回的是一個類型數組,所以要指定下標打印相應的類型
        System.out.println(paraType.getActualTypeArguments()[0]);
    }

    public static void applyGeneric(Vector<Date> v) {

    }
}

程序輸出結果:

class java.util.Vector
class java.util.Date
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章