欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中的枚舉類型詳細(xì)介紹

 更新時間:2012年11月15日 09:30:04   作者:  
枚舉中有values方法用于按照枚舉定義的順序生成一個數(shù)組,可以用來歷遍;接下來將詳細(xì)介紹
枚舉中有values方法用于按照枚舉定義的順序生成一個數(shù)組,可以用來歷遍。我們自定義的枚舉類都是繼承自java.lang.Enum,擁有一下實例中的功能:
復(fù)制代碼 代碼如下:

//: enumerated/EnumClass.java
// Capabilities of the Enum class
import static net.mindview.util.Print.*;
enum Shrubbery { GROUND, CRAWLING, HANGING }
public class EnumClass {
  public static void main(String[] args) {
    for(Shrubbery s : Shrubbery.values()) {
      print(s + " ordinal: " + s.ordinal());
      printnb(s.compareTo(Shrubbery.CRAWLING) + " ");
      printnb(s.equals(Shrubbery.CRAWLING) + " ");
      print(s == Shrubbery.CRAWLING);
      print(s.getDeclaringClass());
      print(s.name());
      print("----------------------");
    }
    // Produce an enum value from a string name:
    for(String s : "HANGING CRAWLING GROUND".split(" ")) {
      Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
      print(shrub);
    }
  }
} /* Output:
GROUND ordinal: 0
-1 false false
class Shrubbery
Joshua Bloch was extremely helpful in developing this chapter.
GROUND
----------------------
CRAWLING ordinal: 1
true true
class Shrubbery
CRAWLING
----------------------
HANGING ordinal: 2
false false
class Shrubbery
HANGING
----------------------
HANGING
CRAWLING
GROUND
*///:~

我們還可以使用靜態(tài)的枚舉引用:
復(fù)制代碼 代碼如下:

//: enumerated/Spiciness.java
package enumerated;
public enum Spiciness {NOT, MILD, MEDIUM, HOT, FLAMING} ///:~
//: enumerated/Burrito.java
package enumerated;
import static enumerated.Spiciness.*;
public class Burrito {
  Spiciness degree;
  public Burrito(Spiciness degree) { this.degree = degree;}
  public String toString() { return "Burrito is "+ degree;}
  public static void main(String[] args) {
    System.out.println(new Burrito(NOT));
    System.out.println(new Burrito(MEDIUM));
    System.out.println(new Burrito(HOT));
  }
} /* Output:
Burrito is NOT
Burrito is MEDIUM
Burrito is HOT
*///:~

向枚舉添加方法
除了不能被繼承之外,枚舉可以當(dāng)作一般的類來看待,這意味著可以向枚舉添加方法,還可以在枚舉中定義main方法:
復(fù)制代碼 代碼如下:

//: enumerated/OzWitch.java
// The witches in the land of Oz.
import static net.mindview.util.Print.*;
public enum OzWitch {
  // Instances must be defined first, before methods:
  WEST("Miss Gulch, aka the Wicked Witch of the West"),NORTH("Glinda, the Good Witch of the North"),EAST("Wicked Witch of the East, wearer of the Ruby " + "Slippers, crushed by Dorothy's house"),SOUTH("Good by inference, but missing");
  private String description;
  // Constructor must be package or private access:
  private OzWitch(String description) {
    this.description = description;
  }
  public String getDescription() { return description; }
  public static void main(String[] args) {
    for(OzWitch witch : OzWitch.values())
      print(witch + ": " + witch.getDescription());
  }
} /* Output:
WEST: Miss Gulch, aka the Wicked Witch of the West
NORTH: Glinda, the Good Witch of the North
EAST: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house
SOUTH: Good by inference, but missing
*///:~

復(fù)制代碼 代碼如下:

//: enumerated/SpaceShip.java
public enum SpaceShip {
  SCOUT, CARGO, TRANSPORT, CRUISER, BATTLESHIP, MOTHERSHIP;
  public String toString() {
    String id = name();
    String lower = id.substring(1).toLowerCase();
    return id.charAt(0) + lower;
  }
  public static void main(String[] args) {
    for(SpaceShip s : values()) {
      System.out.println(s);
    }
  }
} /* Output:
Scout
Cargo
Transport
Cruiser
Battleship
Mothership
*///:~

switch語句中的枚舉
  枚舉的一種重要作用就是在switch語句中,通常switch語句僅對整型值起作用,但是枚舉中有內(nèi)置的整型順序,因此實例的順序可以通過某種方法獲得,因此enums就可以在switch語句中使用:
復(fù)制代碼 代碼如下:

//: enumerated/TrafficLight.java
// Enums in switch statements.
import static net.mindview.util.Print.*;
// Define an enum type:
enum Signal { GREEN, YELLOW, RED, }
  public class TrafficLight {
    Signal color = Signal.RED;
    public void change() {
    switch(color) {
      // Note that you don't have to say Signal.RED
      // in the case statement:
      case RED: color = Signal.GREEN;
            break;
      case GREEN: color = Signal.YELLOW;
            break;
      case YELLOW: color = Signal.RED;
            break;
    }
  }
  public String toString() {
    return "The traffic light is " + color;
  }
  public static void main(String[] args) {
    TrafficLight t = new TrafficLight();
    for(int i = 0; i < 7; i++) {
      print(t);
      t.change();
    }
  }
} /* Output:
The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED
*///:~

values()的秘密
  雖然我們之前使用了values方法,但是如果查看Enum,我們并沒有發(fā)現(xiàn)values方法,那么是不是還有其他隱藏的方法呢?我們可以通過一個簡單的反射代碼來查看一下:
復(fù)制代碼 代碼如下:

//: enumerated/Reflection.java
// Analyzing enums using reflection.
import java.lang.reflect.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
enum Explore { HERE, THERE }
public class Reflection {
  public static Set<String> analyze(Class<?> enumClass) {
    print("----- Analyzing " + enumClass + " -----");
    print("Interfaces:");
    for(Type t : enumClass.getGenericInterfaces())
      print(t);
    print("Base: " + enumClass.getSuperclass());
    print("Methods: ");
    Set<String> methods = new TreeSet<String>();
    for(Method m : enumClass.getMethods())
      methods.add(m.getName());
    print(methods);
    return methods;
  }
  public static void main(String[] args) {
    Set<String> exploreMethods = analyze(Explore.class);
    Set<String> enumMethods = analyze(Enum.class);
    print("Explore.containsAll(Enum)? " +
    exploreMethods.containsAll(enumMethods));
    printnb("Explore.removeAll(Enum): ");
    exploreMethods.removeAll(enumMethods);
    print(exploreMethods);
    // Decompile the code for the enum:
    OSExecute.command("javap Explore");
  }
} /* Output:
----- Analyzing class Explore -----
Interfaces:
Base: class java.lang.Enum
Methods:
[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
----- Analyzing class java.lang.Enum -----
Interfaces:
java.lang.Comparable<E>
interface java.io.Serializable
Base: class java.lang.Object
Methods:
[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
Explore.containsAll(Enum)? true
Explore.removeAll(Enum): [values]
Compiled from "Reflection.java"
final class Explore extends java.lang.Enum{
public static final Explore HERE;
public static final Explore THERE;
public static final Explore[] values();
public static Explore valueOf(java.lang.String);
static {};
}
*///:~

我們可以看到values方法是被編譯器添加的。valueOf方法也是在創(chuàng)建枚舉的時候由編譯器添加的,但是在Enum類中也有一個valueOf方法,但是這個方法有兩個參數(shù),而由編譯器添加的valueOf方法只有一個參數(shù)。枚舉被編譯器解釋為final,因此枚舉不能被繼承。因為values方法是被編譯器添加的靜態(tài)方法,因此如果你將枚舉上塑造型到Enum的時候,values方法將會不可用,但是在Class中有g(shù)etEnumConstants方法,因此雖然values方法在Enum中不可用,但是還是可以通過Class對象獲取枚舉的實例:
復(fù)制代碼 代碼如下:

//: enumerated/UpcastEnum.java
// No values() method if you upcast an enum
enum Search { HITHER, YON }
public class UpcastEnum {
  public static void main(String[] args) {
    Search[] vals = Search.values();
    Enum e = Search.HITHER; // Upcast
    // e.values(); // No values() in Enum
    for(Enum en : e.getClass().getEnumConstants())
      System.out.println(en);
  }
} /* Output:
HITHER
YON
*///:~

實現(xiàn)而不繼承
  因為我們定義的枚舉類型都繼承自java.lang.Enum,而且Java又不支持多重繼承,因此不同通過繼承創(chuàng)建枚舉,但是可以通過繼承一個或多個接口創(chuàng)建枚舉:
復(fù)制代碼 代碼如下:

//: enumerated/cartoons/EnumImplementation.java
// An enum can implement an interface
package enumerated.cartoons;
import java.util.*;
import net.mindview.util.*;
enum CartoonCharacter implements Generator<CartoonCharacter> {
  SLAPPY, SPANKY, PUNCHY, SILLY, BOUNCY, NUTTY, BOB;
  private Random rand = new Random(47);
  public CartoonCharacter next() {
    return values()[rand.nextInt(values().length)];
  }
}
public class EnumImplementation {
  public static <T> void printNext(Generator<T> rg) {
    System.out.print(rg.next() + ", ");
  }
  public static void main(String[] args) {
    // Choose any instance:
    CartoonCharacter cc = CartoonCharacter.BOB;
    for(int i = 0; i < 10; i++)
      printNext(cc);
  }
} /* Output:
BOB, PUNCHY, BOB, SPANKY, NUTTY, PUNCHY, SLAPPY, NUTTY, NUTTY, SLAPPY,
*///:~

隨機(jī)選取
  后面我們很多例子中都會用到從枚舉實例中隨機(jī)選取對象,我們創(chuàng)建一個公用類來實現(xiàn):
復(fù)制代碼 代碼如下:

//: net/mindview/util/Enums.java
package net.mindview.util;
import java.util.*;
public class Enums {
  private static Random rand = new Random(47);
  public static <T extends Enum<T>> T random(Class<T> ec) {
    return random(ec.getEnumConstants());
  }
  public static <T> T random(T[] values) {
    return values[rand.nextInt(values.length)];
  }
} ///:~

復(fù)制代碼 代碼如下:

//: enumerated/RandomTest.java
import net.mindview.util.*;
enum Activity { SITTING, LYING, STANDING, HOPPING, RUNNING, DODGING, JUMPING, FALLING, FLYING }
public class RandomTest {
  public static void main(String[] args) {
    for(int i = 0; i < 20; i++)
      System.out.print(Enums.random(Activity.class) + " ");
  }
} /* Output:
STANDING FLYING RUNNING STANDING RUNNING STANDING LYING DODGING SITTING RUNNING HOPPING HOPPING HOPPING RUNNING STANDING LYING FALLING RUNNING FLYING LYING
*///:~

使用接口進(jìn)行組織
  枚舉不能被繼承,這一點(diǎn)有時候會給我們造成不方便,因為有些時候我們想要通過繼承來擴(kuò)展枚舉的數(shù)量,有些時候我們需要對枚舉進(jìn)行分組。對于后者我們可以通過在接口內(nèi)定義分組的枚舉,然后在通過繼承自這個接口來創(chuàng)建枚舉,如下我們有不同的食物類需要創(chuàng)建為枚舉,但是我們又需要將每個種類定義為Food的類型,如下:
復(fù)制代碼 代碼如下:

//: enumerated/menu/Food.java
// Subcategorization of enums within interfaces.
package enumerated.menu;
public interface Food {enum Appetizer implements Food {SALAD, SOUP, SPRING_ROLLS;}
  enum MainCourse implements Food {LASAGNE, BURRITO, PAD_THAI,LENTILS, HUMMOUS, VINDALOO;}
  enum Dessert implements Food {TIRAMISU, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;}
  enum Coffee implements Food {BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;}
} ///:~

因為每個枚舉都定義為接口的實現(xiàn),因此每個枚舉都是Food類型,如下:
復(fù)制代碼 代碼如下:

//: enumerated/menu/TypeOfFood.java
package enumerated.menu;
import static enumerated.menu.Food.*;
public class TypeOfFood {
  public static void main(String[] args) {
    Food food = Appetizer.SALAD;
    food = MainCourse.LASAGNE;
    food = Dessert.GELATO;
    food = Coffee.CAPPUCCINO;
  }
} ///:~

但是接口不能像枚舉一樣操作多種類型,因此如果你需要一個枚舉的枚舉,那么你可以在一個枚舉里面封裝每個枚舉類型的一個實例:
復(fù)制代碼 代碼如下:

//: enumerated/menu/Course.java
package enumerated.menu;
import net.mindview.util.*;
public enum Course {
  APPETIZER(Food.Appetizer.class),MAINCOURSE(Food.MainCourse.class),DESSERT(Food.Dessert.class),COFFEE(Food.Coffee.class);
  private Food[] values;
  private Course(Class<? extends Food> kind) {
    values = kind.getEnumConstants();
  }
  public Food randomSelection() {
    return Enums.random(values);
  }
} ///:~

每個枚舉使用了Class對象作為對應(yīng)的構(gòu)造器參數(shù),我們就可以從這個參數(shù)里面使用getEnumConstants來獲得枚舉實例,這個實例可以用在randomSelection方法中生成隨機(jī)的餐點(diǎn):
復(fù)制代碼 代碼如下:

//: enumerated/menu/Meal.java
package enumerated.menu;
public class Meal {
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++) {
      for(Course course : Course.values()) {
        Food food = course.randomSelection();
        System.out.println(food);
      }
      System.out.println("---");
    }
  }
} /* Output:
SPRING_ROLLS
VINDALOO
FRUIT
DECAF_COFFEE
---
SOUP
VINDALOO
FRUIT
TEA
---
SALAD
BURRITO
FRUIT
TEA
---
SALAD
BURRITO
CREME_CARAMEL
LATTE
---
SOUP
BURRITO
TIRAMISU
ESPRESSO
---
*///:~

下面是一種更加緊湊的實現(xiàn)方法:
復(fù)制代碼 代碼如下:

//: enumerated/SecurityCategory.java
// More succinct subcategorization of enums.
import net.mindview.util.*;
enum SecurityCategory {
  STOCK(Security.Stock.class), BOND(Security.Bond.class);
  Security[] values;
  SecurityCategory(Class<? extends Security> kind) {
    values = kind.getEnumConstants();
  }
  interface Security {
    enum Stock implements Security { SHORT, LONG, MARGIN }
    enum Bond implements Security { MUNICIPAL, JUNK }
  }
  public Security randomSelection() {
    return Enums.random(values);
  }
  public static void main(String[] args) {
    for(int i = 0; i < 10; i++) {
      SecurityCategory category = Enums.random(SecurityCategory.class);
      System.out.println(category + ": " +
      category.randomSelection());
    }
  }
} /* Output:
BOND: MUNICIPAL
BOND: MUNICIPAL
STOCK: MARGIN
STOCK: MARGIN
BOND: JUNK
STOCK: SHORT
STOCK: LONG
STOCK: LONG
BOND: MUNICIPAL
BOND: JUNK
*///:~

復(fù)制代碼 代碼如下:

//: enumerated/menu/Meal2.java
package enumerated.menu;
import net.mindview.util.*;
public enum Meal2 {
  APPETIZER(Food.Appetizer.class),MAINCOURSE(Food.MainCourse.class),DESSERT(Food.Dessert.class),COFFEE(Food.Coffee.class);
  private Food[] values;
  private Meal2(Class<? extends Food> kind) {
    values = kind.getEnumConstants();
  }
  public interface Food {
    enum Appetizer implements Food {SALAD, SOUP, SPRING_ROLLS;}
    enum MainCourse implements Food {LASAGNE, BURRITO, PAD_THAI,LENTILS, HUMMOUS, VINDALOO;}
    enum Dessert implements Food {TIRAMISU, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;}
    enum Coffee implements Food {BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;}
  }
  public Food randomSelection() {
    return Enums.random(values);
  }
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++) {
      for(Meal2 meal : Meal2.values()) {
        Food food = meal.randomSelection();
        System.out.println(food);
      }
      System.out.println("---");
    }
  }
} /* Same output as Meal.java *///:~

使用EnumSet而不是標(biāo)志位
  在Java SE5中添加了EnumSet來將枚舉和Set組合用于替換基于整型的位標(biāo)志。位標(biāo)志通常用來指示某種信息的開關(guān),但是在代碼中是對位進(jìn)行操作而不是有意義的概念,因此不容易理解。EnumSet的效率比位標(biāo)志要快,在內(nèi)部使用long性表示一個位向量,然后就可以使用更加概念化的語言來表示某個位的開關(guān),而不用擔(dān)心效率。EnumSet中的元素必須來自同一個枚舉,下面定義一個報警器位置的枚舉:
復(fù)制代碼 代碼如下:

//: enumerated/AlarmPoints.java
package enumerated;
public enum AlarmPoints {STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,OFFICE4, BATHROOM, UTILITY, KITCHEN} ///:~

然后使用EnumSet類跟蹤報警的狀態(tài):
復(fù)制代碼 代碼如下:

//: enumerated/EnumSets.java
// Operations on EnumSets
package enumerated;
import java.util.*;
import static enumerated.AlarmPoints.*;
import static net.mindview.util.Print.*;
public class EnumSets {
  public static void main(String[] args) {
    EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class); // Empty set
    points.add(BATHROOM);
    print(points);
    points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
    print(points);
    points = EnumSet.allOf(AlarmPoints.class);
    points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
    print(points);
    points.removeAll(EnumSet.range(OFFICE1, OFFICE4));
    print(points);
    points = EnumSet.complementOf(points);
    print(points);
  }
} /* Output:
[BATHROOM]
[STAIR1, STAIR2, BATHROOM, KITCHEN]
[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]
[LOBBY, BATHROOM, UTILITY]
[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]
*///:~

EnumSet是建立在long型上的,有64位,那么如果我們的枚舉類型超過了這個數(shù)字呢?
復(fù)制代碼 代碼如下:

//: enumerated/BigEnumSet.java
import java.util.*;
public class BigEnumSet {
  enum Big { A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10,A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21,A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32,
A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43,A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54,A55, A56, A57, A58, A59, A60, A61, A62, A63, A64, A65,
A66, A67, A68, A69, A70, A71, A72, A73, A74, A75 }
  public static void main(String[] args) {
    EnumSet<Big> bigEnumSet = EnumSet.allOf(Big.class);
    System.out.println(bigEnumSet);
  }
} /* Output:
[A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75]
*///:~

我們可以看到程序正常運(yùn)行,那么很有可能是內(nèi)部又添加了一個long型來幫助容納枚舉類型
使用EnumMap
  EnumMap是一種特殊類型的Map,他的鍵的值只能是同一個枚舉中的類型,因為這一點(diǎn)在內(nèi)部可以通過數(shù)組來實現(xiàn)EnumMap,效率非常高。
復(fù)制代碼 代碼如下:

//: enumerated/EnumMaps.java
// Basics of EnumMaps.
package enumerated;
import java.util.*;
import static enumerated.AlarmPoints.*;
import static net.mindview.util.Print.*;
interface Command { void action(); }
public class EnumMaps {
  public static void main(String[] args) {
    EnumMap<AlarmPoints,Command> em = new EnumMap<AlarmPoints,Command>(AlarmPoints.class);
    em.put(KITCHEN, new Command() {
      public void action() { print("Kitchen fire!"); }
    });
    em.put(BATHROOM, new Command() {
      public void action() { print("Bathroom alert!"); }
    });
    for(Map.Entry<AlarmPoints,Command> e : em.entrySet()) {
      printnb(e.getKey() + ": ");
      e.getValue().action();
    }
    try { // If there's no value for a particular key:
      em.get(UTILITY).action();
    } catch(Exception e) {
      print(e);
    }
  }
} /* Output:
BATHROOM: Bathroom alert!
KITCHEN: Kitchen fire!
java.lang.NullPointerException
*///:~

特定常量方法
  Java的枚舉有一個非常有趣的特性,那就是可以為每一個枚舉實例定義不同的行為,為了實現(xiàn)這一點(diǎn),我們定義一個或者多個抽象方法作為枚舉的一部分,然后為每個枚舉實例定義方法:
復(fù)制代碼 代碼如下:

//: enumerated/ConstantSpecificMethod.java
import java.util.*;
import java.text.*;
public enum ConstantSpecificMethod {
  DATE_TIME {String getInfo() {return DateFormat.getDateInstance().format(new Date());}},
  CLASSPATH {String getInfo() {return System.getenv("CLASSPATH");}},
VERSION {String getInfo() {return System.getProperty("java.version");}};
  abstract String getInfo();
  public static void main(String[] args) {
    for(ConstantSpecificMethod csm : values())
      System.out.println(csm.getInfo());
  }
} /* (Execute to see output) *///:~

上面的代碼卡起來似乎是每個枚舉元素都是不同的元素,而所有的元素都繼承自ConstantSpecificMethod基類,但是我們不能真的這樣理解,因為我們不能將枚舉元素當(dāng)作類型來看待:
復(fù)制代碼 代碼如下:

//: enumerated/NotClasses.java
// {Exec: javap -c LikeClasses}
import static net.mindview.util.Print.*;
enum LikeClasses {WINKEN { void behavior() { print("Behavior1"); } },BLINKEN { void behavior() { print("Behavior2"); } },NOD { void behavior() { print("Behavior3"); } };
  abstract void behavior();
}
public class NotClasses {
  // void f1(LikeClasses.WINKEN instance) {} // Nope
} /* Output:
Compiled from "NotClasses.java"
abstract class LikeClasses extends java.lang.Enum{
public static final LikeClasses WINKEN;
public static final LikeClasses BLINKEN;
public static final LikeClasses NOD;
...
*///:~

考慮另外一個例子,有一個洗車的菜單,客戶根據(jù)不同的菜單選擇不同的服務(wù),可以使用特定常量方法來將菜單與服務(wù)相關(guān)聯(lián),使用EnumSet來維護(hù)客戶的選擇,如下:
復(fù)制代碼 代碼如下:

//: enumerated/CarWash.java
import java.util.*;
import static net.mindview.util.Print.*;
public class CarWash {
  public enum Cycle {UNDERBODY {void action() { print("Spraying the underbody"); }},
WHEELWASH {void action() { print("Washing the wheels"); }},
         PREWASH {void action() { print("Loosening the dirt"); }},
         BASIC {void action() { print("The basic wash"); }},
         HOTWAX {void action() { print("Applying hot wax"); }},
         RINSE {void action() { print("Rinsing"); }},
         BLOWDRY {void action() { print("Blowing dry"); }};
         abstract void action();
  }
  EnumSet<Cycle> cycles = EnumSet.of(Cycle.BASIC, Cycle.RINSE);
  public void add(Cycle cycle) { cycles.add(cycle); }
  public void washCar() {
    for(Cycle c : cycles)
      c.action();
  }
  public String toString() { return cycles.toString(); }
  public static void main(String[] args) {
    CarWash wash = new CarWash();
    print(wash);
    wash.washCar();
    // Order of addition is unimportant:
    wash.add(Cycle.BLOWDRY);
    wash.add(Cycle.BLOWDRY); // Duplicates ignored
    wash.add(Cycle.RINSE);
    wash.add(Cycle.HOTWAX);
    print(wash);
    wash.washCar();
  }
} /* Output:
[BASIC, RINSE]
The basic wash
Rinsing
[BASIC, HOTWAX, RINSE, BLOWDRY]
The basic wash
Applying hot wax
Rinsing
Blowing dry
*///:~

我們還可以對默認(rèn)的特定常量方法進(jìn)行重寫,而不是使用繼承抽象方法,如下:
復(fù)制代碼 代碼如下:

//: enumerated/OverrideConstantSpecific.java
import static net.mindview.util.Print.*;
public enum OverrideConstantSpecific {
  NUT, BOLT,WASHER {void f() { print("Overridden method"); }};
  void f() { print("default behavior"); }
  public static void main(String[] args) {
    for(OverrideConstantSpecific ocs : values()) {
      printnb(ocs + ": ");
      ocs.f();
    }
  }
} /* Output:
NUT: default behavior
BOLT: default behavior
WASHER: Overridden method
*///:~

有些時候我們希望對特定的請求在鏈條中進(jìn)行傳遞,知道鏈條中的某個對象能夠處理請求,使用特定常量方法可以很輕松的實現(xiàn),如下是一個處理郵件的實例:
復(fù)制代碼 代碼如下:

//: enumerated/PostOffice.java
// Modeling a post office.
Enumerated Types 743
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
class Mail {
  // The NO's lower the probability of random selection:
  enum GeneralDelivery {YES,NO1,NO2,NO3,NO4,NO5}
  enum Scannability {UNSCANNABLE,YES1,YES2,YES3,YES4}
  enum Readability {ILLEGIBLE,YES1,YES2,YES3,YES4}
  enum Address {INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6}
  enum ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5}
  GeneralDelivery generalDelivery;
  Scannability scannability;
  Readability readability;
  Address address;
  ReturnAddress returnAddress;
  static long counter = 0;
  long id = counter++;
  public String toString() { return "Mail " + id; }
  public String details() {
  return toString() + ", General Delivery: " + generalDelivery + ", Address Scanability: " + scannability + ", Address Readability: " + readability +
", Address Address: " + address + ", Return address: " + returnAddress;
  }
  // Generate test Mail:
  public static Mail randomMail() {
    Mail m = new Mail();
    m.generalDelivery= Enums.random(GeneralDelivery.class);
    m.scannability = Enums.random(Scannability.class);
    m.readability = Enums.random(Readability.class);
    m.address = Enums.random(Address.class);
    m.returnAddress = Enums.random(ReturnAddress.class);
    return m;
  }
  public static Iterable<Mail> generator(final int count) {
    return new Iterable<Mail>() {
      int n = count;
      public Iterator<Mail> iterator() {
        return new Iterator<Mail>() {
          public boolean hasNext() { return n-- > 0; }
          public Mail next() { return randomMail(); }
          public void remove() { // Not implemented
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }
}
public class PostOffice {
  enum MailHandler {
    GENERAL_DELIVERY {
      boolean handle(Mail m) {
        switch(m.generalDelivery) {
          case YES:
            print("Using general delivery for " + m);
            return true;
          default: return false;
        }
      }
    },
    MACHINE_SCAN {
      boolean handle(Mail m) {
        switch(m.scannability) {
          case UNSCANNABLE: return false;
          default:
            switch(m.address) {
              case INCORRECT: return false;
              default:
                print("Delivering "+ m + " automatically");
              return true;
            }
        }
      }
    },
    VISUAL_INSPECTION {
      boolean handle(Mail m) {
        switch(m.readability) {
          case ILLEGIBLE: return false;
          default:
            switch(m.address) {
              case INCORRECT: return false;
              default:
                print("Delivering " + m + " normally");
              return true;
            }
        }
      }
    },
    RETURN_TO_SENDER {
      boolean handle(Mail m) {
        switch(m.returnAddress) {
          case MISSING: return false;
          default:
            print("Returning " + m + " to sender");
          return true;
        }
      }
    };
    abstract boolean handle(Mail m);
  }
  static void handle(Mail m) {
    for(MailHandler handler : MailHandler.values())
      if(handler.handle(m))
        return;
    print(m + " is a dead letter");
  }
  public static void main(String[] args) {
    for(Mail mail : Mail.generator(10)) {
      print(mail.details());
      handle(mail);
      print("*****");
    }
  }
} /* Output:
Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1
Delivering Mail 0 normally
*****
Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1
Delivering Mail 1 automatically
*****
Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5
Using general delivery for Mail 2
*****
Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4
Returning Mail 3 to sender
*****
Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2
Returning Mail 4 to sender
*****
Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2
Delivering Mail 5 automatically
*****
Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4
Using general delivery for Mail 6
*****
Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING
Using general delivery for Mail 7
*****
Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING
Mail 8 is a dead letter
*****
Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4
Delivering Mail 9 normally
*****
*///:~

枚舉類型還是創(chuàng)建狀態(tài)機(jī)的理想類型,一個狀態(tài)機(jī)可以根據(jù)輸入在有限個狀態(tài)之間移動,然后在滿足某種狀態(tài)之后結(jié)束工作,另外每個狀態(tài)都會有相應(yīng)的輸出,一個售貨機(jī)器是一個典型的狀態(tài)機(jī)的實例,我們在枚舉內(nèi)定義不同的輸入:
復(fù)制代碼 代碼如下:

//: enumerated/Input.java
package enumerated;
import java.util.*;
public enum Input {
  NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100),TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),ABORT_TRANSACTION {
    public int amount() { // Disallow
      throw new RuntimeException("ABORT.amount()");
    }
  },
  STOP { // This must be the last instance.
    public int amount() { // Disallow
      throw new RuntimeException("SHUT_DOWN.amount()");
    }
  };
  int value; // In cents
  Input(int value) { this.value = value; }
  Input() {}
  int amount() { return value; }; // In cents
  static Random rand = new Random(47);
  public static Input randomSelection() {
    // Don't include STOP:
    return values()[rand.nextInt(values().length - 1)];
  }
} ///:~

VendingMachine用來對輸入進(jìn)行相應(yīng),首先通過Category枚舉歸類輸入,然后使用switch語句:
復(fù)制代碼 代碼如下:

//: enumerated/VendingMachine.java
// {Args: VendingMachineInput.txt}
package enumerated;
import java.util.*;
import net.mindview.util.*;
import static enumerated.Input.*;
import static net.mindview.util.Print.*;
enum Category {
  MONEY(NICKEL, DIME, QUARTER, DOLLAR),ITEM_SELECTION(TOOTHPASTE, CHIPS, SODA, SOAP),QUIT_TRANSACTION(ABORT_TRANSACTION),SHUT_DOWN(STOP);
  private Input[] values;
  Category(Input... types) { values = types; }
  private static EnumMap<Input,Category> categories = new EnumMap<Input,Category>(Input.class);
  static {
    for(Category c : Category.class.getEnumConstants())
      for(Input type : c.values)
        categories.put(type, c);
  }
  public static Category categorize(Input input) {
    return categories.get(input);
  }
}
public class VendingMachine {
  private static State state = State.RESTING;
  private static int amount = 0;
  private static Input selection = null;
  enum StateDuration { TRANSIENT } // Tagging enum
  enum State {
    RESTING {
      void next(Input input) {
        switch(Category.categorize(input)) {
          case MONEY:
            amount += input.amount();
            state = ADDING_MONEY;
            break;
          case SHUT_DOWN:
            state = TERMINAL;
          default:
        }
      }
    },
    ADDING_MONEY {
      void next(Input input) {
        switch(Category.categorize(input)) {
          case MONEY:
            amount += input.amount();
            break;
          case ITEM_SELECTION:
            selection = input;
            if(amount < selection.amount())
              print("Insufficient money for " + selection);
            else state = DISPENSING;
              break;
          case QUIT_TRANSACTION:
            state = GIVING_CHANGE;
            break;
          case SHUT_DOWN:
            state = TERMINAL;
            default:
        }
      }
    },
    DISPENSING(StateDuration.TRANSIENT) {
      void next() {
        print("here is your " + selection);
        amount -= selection.amount();
        state = GIVING_CHANGE;
      }
    },
    GIVING_CHANGE(StateDuration.TRANSIENT) {
      void next() {
        if(amount > 0) {
          print("Your change: " + amount);
          amount = 0;
        }
        state = RESTING;
      }
    },
    TERMINAL { void output() { print("Halted"); } };
    private boolean isTransient = false;
    State() {}
    State(StateDuration trans) { isTransient = true; }
    void next(Input input) {
      throw new RuntimeException("Only call " + "next(Input input) for non-transient states");
    }
    void next() {
      throw new RuntimeException("Only call next() for " + "StateDuration.TRANSIENT states");
    }
    void output() { print(amount); }
  }
  static void run(Generator<Input> gen) {
    while(state != State.TERMINAL) {
      state.next(gen.next());
      while(state.isTransient)
        state.next();
      state.output();
    }
  }
  public static void main(String[] args) {
    Generator<Input> gen = new RandomInputGenerator();
    if(args.length == 1)
      gen = new FileInputGenerator(args[0]);
    run(gen);
  }
}
// For a basic sanity check:
class RandomInputGenerator implements Generator<Input> {
  public Input next() { return Input.randomSelection(); }
}
// Create Inputs from a file of ‘;'-separated strings:
class FileInputGenerator implements Generator<Input> {
  private Iterator<String> input;
  public FileInputGenerator(String fileName) {
    input = new TextFile(fileName, ";").iterator();
  }
  public Input next() {
    if(!input.hasNext())
      return null;
    return Enum.valueOf(Input.class, input.next().trim());
  }
} /* Output:
here is your CHIPS
here is your TOOTHPASTE
Your change: 35
Insufficient money for SODA

Insufficient money for SODA
Your change: 75
Halted
*///:~

下面是用來生成上面輸出的測試數(shù)據(jù):
復(fù)制代碼 代碼如下:

QUARTER; QUARTER; QUARTER; CHIPS;
DOLLAR; DOLLAR; TOOTHPASTE;
QUARTER; DIME; ABORT_TRANSACTION;
QUARTER; DIME; SODA;
QUARTER; DIME; NICKEL; SODA;
ABORT_TRANSACTION;
STOP;
///:~

多重拆封
  當(dāng)處理多個類型之間的交互的時候代碼很有可能變得雜亂,例如Number.plush(Number),Number.mutiply(Number)等,Number僅僅是個家族的基類,那么當(dāng)你調(diào)用a.plus(b)的時候,你既不知道a的類型也不知道b的類型,那么如何保證他們之間的交互正確呢?Java只能執(zhí)行單重拆封,也就是如果在執(zhí)行多個未知類型的一個或者多個操作的時候,Java只能對其中的一個類型執(zhí)行動態(tài)綁定機(jī)制,這樣不能解決我們上面談到的問題,因此不得不手動書寫動態(tài)綁定的代碼。
  解決方案是使用多重綁定。多態(tài)只能在調(diào)用方法的時候發(fā)生,因此如果你需要多重拆封,必須調(diào)用多個方法。通過多重拆封,你必須有一個虛方法來調(diào)用每個類型的方法來進(jìn)行拆封。下面的例子是一個剪刀石頭布的實例:
復(fù)制代碼 代碼如下:

//: enumerated/Outcome.java
package enumerated;
public enum Outcome { WIN, LOSE, DRAW } ///:~
//: enumerated/RoShamBo1.java
// Demonstration of multiple dispatching.
package enumerated;
import java.util.*;
import static enumerated.Outcome.*;
interface Item {
  Outcome compete(Item it);
  Outcome eval(Paper p);
  Outcome eval(Scissors s);
  Outcome eval(Rock r);
}
class Paper implements Item {
  public Outcome compete(Item it) { return it.eval(this); }
  public Outcome eval(Paper p) { return DRAW; }
  public Outcome eval(Scissors s) { return WIN; }
  public Outcome eval(Rock r) { return LOSE; }
  public String toString() { return "Paper"; }
}
class Scissors implements Item {
  public Outcome compete(Item it) { return it.eval(this); }
  public Outcome eval(Paper p) { return LOSE; }
  public Outcome eval(Scissors s) { return DRAW; }
  public Outcome eval(Rock r) { return WIN; }
  public String toString() { return "Scissors"; }
}
class Rock implements Item {
  public Outcome compete(Item it) { return it.eval(this); }
  public Outcome eval(Paper p) { return WIN; }
  public Outcome eval(Scissors s) { return LOSE; }
  public Outcome eval(Rock r) { return DRAW; }
  public String toString() { return "Rock"; }
}
public class RoShamBo1 {
  static final int SIZE = 20;
  private static Random rand = new Random(47);
  public static Item newItem() {
    switch(rand.nextInt(3)) {
      default:
      case 0: return new Scissors();
      case 1: return new Paper();
      case 2: return new Rock();
    }
  }
  public static void match(Item a, Item b) {
    System.out.println(a + " vs. " + b + ": " + a.compete(b));
  }
  public static void main(String[] args) {
    for(int i = 0; i < SIZE; i++)
      match(newItem(), newItem());
  }
} /* Output:
Rock vs. Rock: DRAW
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Scissors vs. Scissors: DRAW
Scissors vs. Paper: WIN
Rock vs. Paper: LOSE
Paper vs. Paper: DRAW
Rock vs. Paper: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Rock vs. Scissors: WIN
Rock vs. Paper: LOSE
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
*///:~

我們使用了很多手段來實現(xiàn)多重拆封,但是獲得的是良好的代碼結(jié)構(gòu)。使用枚舉的解決方案來實現(xiàn)上面的代碼的時候最大的問題就是枚舉實例不是類型,因此不能使用枚舉實例來作為參數(shù)類型。但是我們還是可以有其他的方法繞狗這個障礙,一種方法就是使用構(gòu)造器來初始化每個枚舉類型,然后將輸出組織稱一個查找表:
復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo2.java
// Switching one enum on another.
package enumerated;
import static enumerated.Outcome.*;
public enum RoShamBo2 implements Competitor<RoShamBo2> {
  PAPER(DRAW, LOSE, WIN),SCISSORS(WIN, DRAW, LOSE),ROCK(LOSE, WIN, DRAW);
  private Outcome vPAPER, vSCISSORS, vROCK;
  RoShamBo2(Outcome paper,Outcome scissors,Outcome rock) {
    this.vPAPER = paper;
    this.vSCISSORS = scissors;
    this.vROCK = rock;
  }
  public Outcome compete(RoShamBo2 it) {
    switch(it) {
      default:
      case PAPER: return vPAPER;
      case SCISSORS: return vSCISSORS;
      case ROCK: return vROCK;
    }
  }
  public static void main(String[] args) {
    RoShamBo.play(RoShamBo2.class, 20);
  }
} /* Output:
ROCK vs. ROCK: DRAW
SCISSORS vs. ROCK: LOSE
SCISSORS vs. ROCK: LOSE
Enumerated Types 753
SCISSORS vs. ROCK: LOSE
PAPER vs. SCISSORS: LOSE
PAPER vs. PAPER: DRAW
PAPER vs. SCISSORS: LOSE
ROCK vs. SCISSORS: WIN
SCISSORS vs. SCISSORS: DRAW
ROCK vs. SCISSORS: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
ROCK vs. PAPER: LOSE
ROCK vs. SCISSORS: WIN
SCISSORS vs. ROCK: LOSE
PAPER vs. SCISSORS: LOSE
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
*///:~

復(fù)制代碼 代碼如下:

//: enumerated/Competitor.java
// Switching one enum on another.
package enumerated;
public interface Competitor<T extends Competitor<T>> {
  Outcome compete(T competitor);
} ///:~

復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo.java
// Common tools for RoShamBo examples.
package enumerated;
import net.mindview.util.*;
public class RoShamBo {
  public static <T extends Competitor<T>> void match(T a, T b) {
    System.out.println(a + " vs. " + b + ": " + a.compete(b));
  }
  public static <T extends Enum<T> & Competitor<T>> void play(Class<T> rsbClass, int size) {
    for(int i = 0; i < size; i++)
      match(Enums.random(rsbClass),Enums.random(rsbClass));
  }
} ///:~

因為制定靜態(tài)方法可以為每個枚舉類型提供不同的方法,看起來是一個實現(xiàn)多重拆封的好解決辦法,但是還是面臨著枚舉實例不是類型的問題,于是我們能做的就是添加一個switch語句:
復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo3.java
// Using constant-specific methods.
package enumerated;
import static enumerated.Outcome.*;
public enum RoShamBo3 implements Competitor<RoShamBo3> {
  PAPER {
    public Outcome compete(RoShamBo3 it) {
      switch(it) {
        default: // To placate the compiler
        case PAPER: return DRAW;
        case SCISSORS: return LOSE;
        case ROCK: return WIN;
      }
    }
  },
  SCISSORS {
    public Outcome compete(RoShamBo3 it) {
      switch(it) {
        default:
        case PAPER: return WIN;
        case SCISSORS: return DRAW;
        case ROCK: return LOSE;
      }
    }
  },
  ROCK {
    public Outcome compete(RoShamBo3 it) {
      switch(it) {
        default:
        case PAPER: return LOSE;
        case SCISSORS: return WIN;
        case ROCK: return DRAW;
      }
    }
  };
  public abstract Outcome compete(RoShamBo3 it);
  public static void main(String[] args) {
    RoShamBo.play(RoShamBo3.class, 20);
  }
} /* Same output as RoShamBo2.java *///:~

下面的代碼是一種更加簡潔的實現(xiàn)方法:
復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo4.java
package enumerated;
public enum RoShamBo4 implements Competitor<RoShamBo4> {
  ROCK {
    public Outcome compete(RoShamBo4 opponent) {
      return compete(SCISSORS, opponent);
    }
  },
  SCISSORS {
    public Outcome compete(RoShamBo4 opponent) {
      return compete(PAPER, opponent);
    }
  },
  PAPER {
    public Outcome compete(RoShamBo4 opponent) {
      return compete(ROCK, opponent);
    }
  };
  Outcome compete(RoShamBo4 loser, RoShamBo4 opponent) {
    return ((opponent == this) ? Outcome.DRAW: ((opponent == loser) ? Outcome.WIN: Outcome.LOSE));
  }
  public static void main(String[] args) {
    RoShamBo.play(RoShamBo4.class, 20);
  }
} /* Same output as RoShamBo2.java *///:~

EnumMap類似乎是一個可以真正實現(xiàn)多重拆封的好辦發(fā):
復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo5.java
// Multiple dispatching using an EnumMap of EnumMaps.
package enumerated;
import java.util.*;
import static enumerated.Outcome.*;
enum RoShamBo5 implements Competitor<RoShamBo5> {
  PAPER, SCISSORS, ROCK;
  static EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>> table = new EnumMap<RoShamBo5,EnumMap<RoShamBo5,Outcome>>(RoShamBo5.class);
  static {
    for(RoShamBo5 it : RoShamBo5.values())
      table.put(it, new EnumMap<RoShamBo5,Outcome>(RoShamBo5.class));
    initRow(PAPER, DRAW, LOSE, WIN);
    initRow(SCISSORS, WIN, DRAW, LOSE);
    initRow(ROCK, LOSE, WIN, DRAW);
  }
  static void initRow(RoShamBo5 it, Outcome vPAPER, Outcome vSCISSORS, Outcome vROCK) {
    EnumMap<RoShamBo5,Outcome> row = RoShamBo5.table.get(it);
    row.put(RoShamBo5.PAPER, vPAPER);
    row.put(RoShamBo5.SCISSORS, vSCISSORS);
    row.put(RoShamBo5.ROCK, vROCK);
  }
  public Outcome compete(RoShamBo5 it) {
    return table.get(this).get(it);
  }
  public static void main(String[] args) {
    RoShamBo.play(RoShamBo5.class, 20);
  }
} /* Same output as RoShamBo2.java *///:~

我們還可以使用枚舉實例具有固定值的特點(diǎn)來使用數(shù)據(jù)進(jìn)行最簡單的實現(xiàn)方法,這里使用一個二維數(shù)組進(jìn)行映射來實現(xiàn):
復(fù)制代碼 代碼如下:

//: enumerated/RoShamBo6.java
// Enums using "tables" instead of multiple dispatch.
package enumerated;
import static enumerated.Outcome.*;
enum RoShamBo6 implements Competitor<RoShamBo6> {
  PAPER, SCISSORS, ROCK;
  private static Outcome[][] table = {
    { DRAW, LOSE, WIN }, // PAPER
    { WIN, DRAW, LOSE }, // SCISSORS
    { LOSE, WIN, DRAW }, // ROCK
  };
  public Outcome compete(RoShamBo6 other) {
    return table[this.ordinal()][other.ordinal()];
  }
  public static void main(String[] args) {
    RoShamBo.play(RoShamBo6.class, 20);
  }
} ///:~

相關(guān)文章

  • Java中的CyclicBarrier循環(huán)柵欄詳解

    Java中的CyclicBarrier循環(huán)柵欄詳解

    這篇文章主要介紹了Java中的CyclicBarrier循環(huán)柵欄詳解,CyclicBarrier循環(huán)柵欄是用來進(jìn)行線程協(xié)作,等待線程滿足某個計數(shù),構(gòu)造時設(shè)置計數(shù)個數(shù),每個線程執(zhí)行到某個需要“同步”的時刻調(diào)用 await()方法進(jìn)行等待,當(dāng)?shù)却木€程數(shù)滿足計數(shù)個數(shù)時,繼續(xù)執(zhí)行,需要的朋友可以參考下
    2023-12-12
  • 詳解Spring學(xué)習(xí)之聲明式事務(wù)管理

    詳解Spring學(xué)習(xí)之聲明式事務(wù)管理

    這篇文章主要介紹了詳解Spring學(xué)習(xí)之聲明式事務(wù)管理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Springboot如何獲取上下文ApplicationContext

    Springboot如何獲取上下文ApplicationContext

    這篇文章主要介紹了Springboot如何獲取上下文ApplicationContext,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 深入理解@component與@Configuration注解

    深入理解@component與@Configuration注解

    這篇文章主要介紹了深入理解@component與@Configuration注解,從Spring3.0,@Configuration用于定義配置類,可替換xml配置文件,被注解的類內(nèi)部包含有一個或多個被@Bean注解的方法,這些方法將會被掃描,并用于構(gòu)建bean定義,初始化Spring容器,需要的朋友可以參考下
    2023-11-11
  • listview點(diǎn)擊無效的處理方法(推薦)

    listview點(diǎn)擊無效的處理方法(推薦)

    下面小編就為大家?guī)硪黄猯istview點(diǎn)擊無效的處理方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • springboot?正確的在異步線程中使用request的示例代碼

    springboot?正確的在異步線程中使用request的示例代碼

    這篇文章主要介紹了springboot中如何正確的在異步線程中使用request,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • JAVA通過HttpURLConnection 上傳和下載文件的方法

    JAVA通過HttpURLConnection 上傳和下載文件的方法

    這篇文章主要介紹了JAVA通過HttpURLConnection 上傳和下載文件的方法,非常具有實用價值,需要的朋友可以參考下
    2017-09-09
  • Java消息隊列RabbitMQ入門詳解

    Java消息隊列RabbitMQ入門詳解

    這篇文章主要介紹了Java消息隊列RabbitMQ入門詳解,RabbitMQ是使用Erlang語言開發(fā)的開源消息隊列系統(tǒng),基于AMQP協(xié)議 來實現(xiàn),AMQP的主要特征是面向消息、隊列、路由(包括點(diǎn)對點(diǎn)和發(fā)布 /訂閱)、可靠性、安全,需要的朋友可以參考下
    2023-07-07
  • java通過復(fù)選框控件數(shù)組實現(xiàn)添加多個復(fù)選框控件示例分享

    java通過復(fù)選框控件數(shù)組實現(xiàn)添加多個復(fù)選框控件示例分享

    編寫程序,通過復(fù)選框控件數(shù)組事先選擇用戶愛好信息的復(fù)選框,在該程序中,要求界面中的復(fù)選框數(shù)量可以根據(jù)指定復(fù)選框名稱的字符串?dāng)?shù)組的長度來自動調(diào)節(jié)
    2014-02-02
  • Java大批量導(dǎo)出Excel數(shù)據(jù)的優(yōu)化過程

    Java大批量導(dǎo)出Excel數(shù)據(jù)的優(yōu)化過程

    幾十萬上百萬行的數(shù)據(jù)是很常見的。本文主要介紹了Java大批量導(dǎo)出Excel數(shù)據(jù)的優(yōu)化過程,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論