package thinkinginjava.charpter19;
/*
* here is my first time to check this strange
* syntactic that static can follow after import?
* about this point, I should check some materials
* from the Internet.
* okay, now here, I got a little understand about
* this, here, we just want to know the truth, if
* we import one object, this is just meant that
* we can use this object, but it doesn't meant that
* you can access the static value in object, here
* is the point, user this import static keyword,
* than you can just use the static method without
* using class name to declare.
*
*/
import static thinkinginjava.charpter19.Spiciness.*;
import static java.lang.System.out;
public class Burrito {
Spiciness degreeSpiciness;
public Burrito(Spiciness degress){
this.degreeSpiciness = degress;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Burrito is "+degreeSpiciness;
}
public static void main(String[] args) {
out.println(new Burrito(NOT));
out.println(new Burrito(HOT));
out.println(new Burrito(FLAMING));
}
}
define enum spiciness:
package thinkinginjava.charpter19;
public enum Spiciness{NOT, MILD, MEDIUM, HOT , FLAMING}
execute result:
Burrito is NOT
Burrito is HOT
Burrito is FLAMING
here is just the same thing that I should understand, this is normal.
有些事情感到不解有时候是可以想象的。
比如,我们可以在enum中加入main方法,就像是普通的类一样,关键的一点是,必须注意在enum中定义自己的属性和方法的时候,应该是在定义了enum实例之后的。
package thinkinginjava.charpter19;
public enum OzWitch {
//just like here, instance must be defined first
WEST("Miss Gulch, aka the Wicked Witch of the West"),
NORTH("Glinda, the Good Witch of the North"),
EAST("Wichked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house"),
SOUTH("Good by inference, but missing");
private String description;
/*
* here I want to know something that doesn't matter
* this enum thing, I am wondering if I can check the
* Enum class and find how kind of methods it has.
* so I check the Enum class, and find it just got some
* method, what we care about is the property it has,
* one name, the enum name, so...
*/
private OzWitch(String description){
this.description = description;
}
public String getDescription(){
return this.description;
}
public static void main(String[] args) {
//现在我在纠结的一点就是怎么使用枚举类
for (OzWitch ozWitch : OzWitch.values()) {
/*
* 从这个for语句来推测,枚举类应该是一个有着静态方法values()的类
* 但是在查找了Enum类的源代码之后,发现,没有values()这个方法,
* 很多人都会觉得奇怪,values()是又编译器添加的static方法,这样子
* 似乎看起来问题就决解了。这边就先到这边顿住。
* 还可以看出的一点是,上面定义的WEST,NORTH,EAST,SOUTH其实都是
* OzWitch的实例,这样子看来,为题好像有清晰了许多,枚举类就是定义
* 本身的几个对象,按照一定顺序排列,然后...使用?
*/
System.out.println("description: "+ozWitch.getDescription());
}
}
}
/*
console result:
description: Miss Gulch, aka the Wicked Witch of the West
description: Glinda, the Good Witch of the North
description: Wichked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house
description: Good by inference, but missing
*/
这边用反射机制来看下Enum的方法和相关的values方法:
package thinkinginjava.charpter19;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
import thinkinginjava.utils.OSExecute;
enum Explore {HERE, THERE;}
public class Reflection {
public static Set<String> analyze(Class<?> enumClass){
//interface
System.out.println("interface: ");
Type[] interfaceType = enumClass.getGenericInterfaces();
for (Type type : interfaceType) {
System.out.print(" | "+type);
}
//super class
System.out.println("\nBase: "+enumClass.getSuperclass());
//methods
System.out.println("method: ");
Method[] methods = enumClass.getMethods();
Set<String> methodSet = new HashSet<String>();
for (Method method : methods) {
methodSet.add(method.getName());
}
System.out.println(methodSet);
return methodSet;
}
public static void main(String[] args) {
Set<String> exploreMethodSet = analyze(Explore.class);
Set<String> enumMethodSet = analyze(Enum.class);
System.out.println("Explore.containAll(Enum)? "+exploreMethodSet.containsAll(enumMethodSet));
System.out.println("Explore.removeAll(Enum): "+exploreMethodSet.removeAll(enumMethodSet));
System.out.println("leftSet: "+ exploreMethodSet);
}
/*
OUTPUT:
Base: class java.lang.Enum
method:
[getClass, getDeclaringClass, values, equals, notify, name, ordinal, hashCode, compareTo, toString, wait, valueOf, notifyAll]
interface:
| java.lang.Comparable<E> | interface java.io.Serializable
Base: class java.lang.Object
method:
[getClass, getDeclaringClass, equals, notify, name, ordinal, hashCode, compareTo, toString, wait, valueOf, notifyAll]
Explore.containAll(Enum)? true
Explore.removeAll(Enum): true
leftSet: [values]
*/
}
反编译Explore.class:
Compiled from "Reflection.java"
final class thinkinginjava.charpter19.Explore extends java.lang.Enum<thinkinginj
ava.charpter19.Explore> {
public static final thinkinginjava.charpter19.Explore HERE;
public static final thinkinginjava.charpter19.Explore THERE;
static {};
public static thinkinginjava.charpter19.Explore[] values();
public static thinkinginjava.charpter19.Explore valueOf(java.lang.String);
}
这样的结果,我不知道能说明什么,但是上面的values方法明显是编译器生成的,同样的,你还可以看到另外的多出来的两个,valueOf(String) 和static{}, 意识到Enum中也有一个avluesOf方法,但是是两个参数,一个Class,String.这边应该是待处理的……
===============================================================
就像普通的类一样,我们知道enum在编译时会生成一个继承Enum的类,而Enum又是默认继承Object,所以我们同样可以想对待普通的子类一样对待我们编写的enum,覆盖它的一些方法:
package thinkinginjava.charpter19;
public enum SpaceShip {
SCOUT, CARGO, TRANSPORT, CRUISER, BATTLESHIP, MOTHERSHIP;
/*
* (non-Javadoc)
* @see java.lang.Enum#toString()
* here we just override toString method.
*/
public String toString() {
String id = name(); //here name is the method of Enum class
String lower = id.substring(1).toLowerCase();
/*
* 这边会是感觉怪怪的,但是没办法,就是这样子拼接的,是否可以有更好的办法来处理这样的
* 事情呢,除非传唤称StringBuffer,否则,我们知道String是不可变的。
*/
return id.charAt(0) + lower;
};
public static void main(String[] args) {
for (SpaceShip spaceShip : SpaceShip.values()) {
System.out.println(spaceShip);
}
}
/*
* Output:
Scout
Cargo
Transport
Cruiser
Battleship
Mothership
*/
}
现在有一个问题来了,是这样子的,在JDK1.8之前,switch只能是使用整数值,但是对于枚举,他是继承Enum,怎么可以使用,事实上确实是可以switch使用enum,当然,这是编译器帮忙做的事情,因为enum的ordinal方法获取的是次序,所以可以想象编译器做的事情,把枚举转换成次序。
package thinkinginjava.charpter19;
enum Signal{RED, GREEN, YELLOW;}
public class TrafficLight {
Signal color = Signal.RED;
//so, here , this is normal
public void change(){
switch (color) {
case RED:
color = Signal.YELLOW;
break;
case GREEN:
color = Signal.RED;
break;
case YELLOW:
color = Signal.GREEN;
break;
default:
break;
}
}
@Override
public String toString() {
return "the traffic light is: "+color;
}
public static void main(String[] args) {
TrafficLight tl = new TrafficLight();
for (int i = 0; i < 7; i++) {
System.out.println(tl);
tl.change();
}
}
/*output:
the traffic light is: RED
the traffic light is: YELLOW
the traffic light is: GREEN
the traffic light is: RED
the traffic light is: YELLOW
the traffic light is: GREEN
the traffic light is: RED
*/
}
这边有多出来了一个无关enum的以外,也是部分相关的:
package thinkinginjava.charpter19;
enum Search{HITHER, YON};
public class UpcaseEnum {
public static void main(String[] args) {
Search[] searchValues = Search.values();
Enum e = Search.HITHER;
/*
* it looks rediculous, you need just find one enum instance,
* and then, use this instance to find the kind of class it
* belongs, and find all instance of this class, now it is
* not so rediculous as what I thought before.
*/
for (Enum<Search> search : e.getClass().getEnumConstants()) {
System.out.println(search);
}
}
}
/*
output:
HITHER
YON
*/
是的,上面说的是enum,但是这样要说明的是这个getEnumConstants()这个方法,但是这个方法是Class的,所以, 想着是不是应该普通的类也是可以通过这个方法去获取普通类的枚举实例?
package thinkinginjava.charpter19;
public class NonEnum {
/*
* here I just want to try to find the enum constants
* of an object
*/
public static void main(String[] args) {
Class<Integer> integerClass = Integer.class;
for (Object an: integerClass.getEnumConstants()) {
System.out.println(an);
}
}
}
/*
output:
Exception in thread "main" java.lang.NullPointerException
at thinkinginjava.charpter19.NonEnum.main(NonEnum.java:11)
*/
从上面的结果来看,就是说Integer里面是没有枚举常量的。
在我们看来,现在有一个道理是很浅显的,因为enum继承Enum,java不支持多继承,所以只能用实现来实现所谓的多继承的行为,既是我们自己写的枚举类是不能再有继承什么父类的,只能是实现:
package thinkinginjava.charpter19;
import java.util.Random;
/*
* I don't know, why Bruce Eckel use this code to
* show this tip, but we can see nuderstand this
* is okay.
*/
enum CartoonCharacter implements Generator{
SLAPPY, APANKY, PUNCHY, SILLY,BOUNCY, NUTTY, BON;
private Random random = new Random(47);
//this is a method in Generator
public Generator next(){
//return a random generator
return values()[random.nextInt(values().length)];
}
}
public class EnumImplementation{
public static void main(String[] args) {
CartoonCharacter cc = CartoonCharacter.BON;
for (int i = 0; i < 10; i++) {
printNext(cc);
}
}
public static void printNext(Generator rg){
System.out.println(rg.next()+",");
}
}
/*
output:-------------------------------------
BON,
PUNCHY,
BON,
APANKY,
NUTTY,
PUNCHY,
SLAPPY,
NUTTY,
NUTTY,
SLAPPY,
*/
and here, the interface generator is:
package thinkinginjava.charpter19;
public interface Generator {
Generator next();
}
here is the exercise: modify upper java file, write one static method with let enum implement the interface. so:
package thinkinginjava.charpter19.exercise;
import java.util.Random;
enum Document{
XML, DOC, XLS, SQL, PPT, MK, C, CPP, JAVA, CS;
private static Random random = new Random(52);
public static Document next(){
return values()[random.nextInt(values().length)];
}
}
public class e1902 {
/*
* here, we want ot modify the EnumImplementation class without
* implements the generator in enum, just write a own static next
* method
*/
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(Document.next());
}
}
}
/*
output:
DOC
CS
CPP
MK
DOC
PPT
DOC
MK
DOC
CPP
*/
if you want to recognize the difference between, it may just only the logic and rational analyze it. the second example make more sense.
so, here we have a utils class:
package thinkinginjava.utils;
import java.util.Random;
/**
* here, this is the utils to generate
* random enum instance
* @author Saturday
* @time 2016年10月15日 下午5:34:24
* @file Enums.java
*/
public class Enums {
private static Random random = new Random(47);
public static <T extends Enum<T>> T random(Class<T> ec){
return random(ec.getEnumConstants());
}
private static <T> T random(T[] values){
return values[random.nextInt(values.length)];
}
}
给个例子:
package thinkinginjava.charpter19;
import thinkinginjava.utils.Enums;
enum Activity{RUNNING, WALKING, LYING, STANDING, SITTING, JUMPING, FALLING, FLYING;}
// now it looks easy for us to pick a random enum, just use this utils class.
public class RandomTest {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(Enums.random(Activity.class));
}
}
}
/*output:
JUMPING
STANDING
SITTING
RUNNING
WALKING
SITTING
WALKING
STANDING
SITTING
JUMPING
*/