基础知识

1.Java完全采用了动态内存分配方式,每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。

2.存储空间
寄存器:最快的存储区,位于处理器内部。
堆栈:位于RAM中,存储对象引用。
堆:位于RAM中,存储对象。
常量存储:常量值通常直接存放在程序代码内部。
非RAM存储:位于ROM中,在程序没有运行时也可以存在。

3.在Java中尽管一切都看作对象,但操纵的标识符实际上是对象的一个"引用",你拥有一个引用,并不一定需要有一个对象与它关联。

String s; //创建的只是引用,并不是对象

一旦创建了一个引用,就希望它能与一个新的对象相关联,通常用new操作符来实现这一目的。

String s = new String("asdf"); //字符串初始化 方式1
String s = "asdf"; //字符串初始化 方式2

4.Java对象不具备和基本类型一样的生命周期,当用new创建一个Java对象时,它可以存活于作用域之外。

{
    String s = new String("a string");
} // End of scope

引用s在作用域终点就消失了,然而s指向的String对象仍继续占据内存空间。
在这一小段代码中,我们无法在这个作用域之后访问这个对象,因为对它唯一的引用已超出了作用域的范围。

Java有一个垃圾回收器,用来监视new创建的所有对象,并辨别那些不会再被引用的对象,随后释放这些对象的内存空间,以便供其他新的对象使用。

5.方法的基本组成部分包括:名称、参数、返回值和方法体。
方法名和参数列表(它们合起来被称为"方法签名")唯一地标识出某个方法。
在参数列表中必须指定每个所传递对象的类型及名字,像Java中任何传递对象的场合一样,这里传递的实际上也是引用,并且引用的类型必须正确。

6.基本类型,不用new来创建变量,而是创建一个并非是引用的"自动"变量,这个变量直接存储"值",并置于堆栈中。
Java要确定每种基本类型所占存储空间的大小,它们的大小并不像其他大多数语言那样随机器硬件架构的变化而变化。这种所占存储空间大小的不变性是Java程序比用其他大多数语言编写的程序更具可移植性的原因之一。

基本类型

所有数值类型都有正负号,所以不要去寻找无符号的数值类型。
boolean类型所占存储空间的大小没有明确指定,仅定义为能够取字面值true或false。

基本类型具有的包装器类,使得可以在堆中创建一个非基本对象,用来表示对应的基本类型。

char c = 'x';
Character ch = new Character(c);
或者
Character ch = new Character('x');

自动包装:
Character ch = 'x';
反向转换:
char c = ch;

Java提供了两个用于高精度计算的类:
BigInteger:支持任意精度的整数。
BigDecimal:支持任意精度的定点数。

7.基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方。但是在对一个对象进行赋值时,实际是将"引用"从一个地方复制到另一个地方。

8.==和!=比较的是对象的引用。

9.equals()的默认行为是比较对象的引用,大多数Java类库都实现了equals()方法,用于比较对象的内容而非比较对象的引用。

10.直接常量

int a = 0x2f;
int b = 0x2F;
int c = 0177;
long d = 200L;
long e = 200l; //小写字母l,容易与数字1混淆,慎用
float f = 1F;
float g = 1f;
double h = 1D;
double i = 1d;

//print
Integer.toBinaryString(a) ==> 101111
Integer.toBinaryString(b) ==> 101111
Integer.toBinaryString(c) ==> 1111111
d ==> 200
e ==> 200
f ==> 1.0
g ==> 1.0
h ==> 1.0
i ==> 1.0

11.字符串操作符+和+=,如果表达式以一个字符串起头,那么后续所有操作数都必须是字符串型。

12.在将float或double转型为整型值时,总是对该数字执行截尾。如果想要得到舍入的结果,就需要使用java.lang.Math中的round()方法。

13.构造器是一种特殊类型的方法,因为它没有返回值。new表达式确实返回了对新建对象的引用,但构造器本身并没有任何返回值。

构造器虽然没有显式地使用static关键字,但它实际上也是静态方法。

14.每个重载的方法都必须有一个独一无二的参数类型列表。

15.默认构造器是没有形式参数的,如果类中没有构造器,则编译器会自动创建一个默认构造器。如果类中已经定义了一个构造器(无论是否有参数),编译器就不会自动创建默认构造器。

16.this关键字只能在方法内部使用,表示对"调用方法的那个对象"的引用。

可以使用this调用一个构造器,但是不能连续调用两个。此外必须将构造器调用置于最起始处,否则编译器会报错。

17.static方法就是没有this的方法,可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。

在static方法的内部不能调用非static方法,而在非static方法的内部能够调用static方法。

18.static关键字不能应用于局部变量,只能作用于成员变量。

19.Java尽力保证所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译时错误的形式来贯彻这种保证。

20.对象的创建及初始化过程
假设有个名为Dog的类:
(1)当首次创建类型为Dog的对象时,或者Dog类的静态成员变量或静态成员方法首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
(2)然后载入Dog.class,创建一个Class对象,有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
(3)当用new Dog()创建对象的时候,首先在堆上为Dog对象分配足够的存储空间。
(4)这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值,而引用则被设置成了null。
(5)执行所有出现于成员变量定义处的初始化动作。
(6)执行构造器。

如果存在继承的情况,初始化大概流程如下:
(1)静态初始化,从父类到子类依次执行。
(2)默认初始化,从父类到子类依次执行。
(3)成员变量定义处初始化、构造器初始化,从父类到子类依次执行。

21.数组只是相同类型的、用一个标识符名称封装到一起的一个对象序列或基本类型数据序列。

//定义
int[] a; //方法1
int a[]; //方法2

//初始化
int[] a = {1, 2, 3}; //特殊初始化,只能用于数组定义处
Random rand = new Random(47);
a = new int[rand.nextInt(20)]; //尽管创建的是基本类型数组,new仍然可以工作(不能用new创建单个的基本类型数据)

//赋值
int[] b;
b = a; //在Java中可以将一个数组赋值给另一个数组,其实真正做的只是复制了一个引用。

如果创建了一个非基本类型的数组,那么就创建了一个引用数组。

Integer[] a = new Integer[rand.nextInt(20)]; //创建一个引用数组
a[i] = rand.nextInt(500); //对引用数组进行初始化,使用了自动包装机制

22.可变参数列表

//对象引用
static void f(int required, String... trailing) {

}

//基本类型
static void g(int... args) {

}

23.枚举类型

//定义
public enum Week {
    MON, TUE, WED, THU, FRI, SAT, SUN
}

//使用
Week week = Week.FRI;

for(Week week : Week.values()) {
    Log.d(TAG, "week: " + week + ", ordinal: " + week.ordinal()); ==> week: MON, ordinal: 0
}

24.访问权限控制的等级,从最大权限到最小权限依次是:public、protected、包访问权限(没有关键词)、private。
可以用来修饰:类、成员变量、成员方法。

25.当编译一个.java文件时,在.java文件中的每个类都会有一个输出文件,而该输出文件的名称与.java文件中的每个类的名称相同,只是多了一个后缀名.class。因此,在编译少量.java文件之后,会得到大量的.class文件。

26.package和import关键字允许你做的,是将单一的全局名字空间分割开,使得无论多少人使用Internet以及Java开始编写类,都不会出现名称冲突的问题。

27.import static,导入类的静态成员变量及静态成员方法,可以直接使用导入的静态成员变量及静态成员方法,而不用在前面添加类名及点。

import static com.tomorrow.test.TestObject.*; //静态导入

testMethod(); //直接使用TestObject类里面的静态方法

28.继承通过extends关键字来实现,子类会自动得到父类中所有的成员变量和成员方法。Java用super关键字表示父类的意思,当前类就是从父类继承来的。

super.method(); //调用父类的方法
super.field; //获取父类的成员变量

29.当创建了一个子类的对象时,该对象包含了一个父类的子对象,这个子对象与用父类直接创建的对象是一样的,区别在于后者来自于外部,而父类的子对象被包装在子类对象内部。

Java会自动在子类构造器中插入对父类构造器的调用,以此对父类的子对象进行初始化。但是如果父类没有默认的构造器或者想调用父类的一个带参数的构造器,就必须用关键字super显式地编写调用父类构造器的语句,并且配以适当的参数列表。

30.由子类转型成父类,在继承图上是向上移动的,因此一般称为向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所以总是很安全的。

31.final关键字
final数据:对基本类型使用final使得数值恒定不变。对对象引用使用final使得引用恒定不变,然而对象自身却是可以被修改的。

//定义为public表示可以被用于包之外
//定义为static表示只有一份
//定义为final表示常量
public static final int INT = 5;

final j; //空白final,指被声明为final但又未给定初值的成员变量或局部变量
j = 1; //无论什么情况,编译器都确保空白final在使用前必须被初始化

void method(final TestObject object) //final参数,无法在方法中更改参数引用所指向的对象

final方法:确保在继承中使方法行为保持不变,并且不会被覆盖。类中所有的private方法都隐式地指定为final的。

final类:当将某个类的整体定义为final时,就表明了你不打算继承该类,而且也不允许别人这样做。

32.方法调用绑定
将一个方法调用同一个方法主体关联起来被称为绑定。若在程序执行前进行绑定叫做前期绑定,若在运行时根据对象的类型进行绑定叫做后期绑定/动态绑定/运行时绑定。

Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。

Shape s = new Circle(); //父类Shape,子类Circle
s.draw(); //由于后期绑定(多态),调用子类Circle的draw()方法

33.静态方法、final方法(包括private方法)、成员变量,都不具有多态性。

34.构造器内部的多态方法的行为

//父类
public class TestObject {
    private static final String TAG = "TestObject";

    public TestObject() {
        Log.d(TAG, "zwm, TestObject construct");
        draw();
    }

    public void draw() {
        Log.d(TAG, "zwm, TestObject draw");
    }
}

//子类
public class ExtendTestObject extends TestObject {
    private static final String TAG = "ExtendTestObject";
    private int radius = 1;

    public ExtendTestObject(int radius) {
        Log.d(TAG, "zwm, ExtendTestObject construct, radius: " + radius);
        this.radius = radius;
    }

    @Override
    public void draw() {
        Log.d(TAG, "zwm, ExtendTestObject draw, radius: " + radius);
    }
}

//调用
new ExtendTestObject(5);

//log
TestObject construct //先调用父类的构造器
ExtendTestObject draw, radius: 0 //由于多态性,在父类的构造器中调用了子类的draw()方法,由于子类尚未进行成员变量定义处初始化及构造器初始化,因此radius默认值为0
ExtendTestObject construct, radius: 5 //在父类进行了成员变量定义处初始化及构造器初始化后,子类才进行成员变量定义处初始化及构造器初始化

编写构造器时有一条有效的准则:用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其他方法。

在构造器内唯一能够安全调用的那些方法是基类中的final方法(包括private方法),这些方法不能被覆盖,因此也就不会出现多态性的问题。

35.在Java中进入运行期会对所有的转型进行检查,以便保证它的确是我们希望的那种类型,如果不是,就会返回一个ClassCastException(类转型异常)。这种在运行期间对类型进行检查的行为称作"运行时类型识别"(RTTI)。

36.包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的,否则编译器会报错。

如果从一个抽象类继承,并想创建该新类的对象,那么就必须为父类中的所有抽象方法提供方法定义。如果不这么做,那么子类便也是抽象类,且编译器将会强制我们用abstract关键字来限定这个类。

创建抽象类和抽象方法非常有用,因为它们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样来使用它们。抽象类还是很有用的重构工具,因为它们使得我们可以很容易地将公共方法沿着继承层次结构向上移动。

37.abstract关键字允许人们在类中创建一个或多个没有任何定义的方法,这些实现是由此类的继承者创建的。而interface关键字使抽象的概念更向前迈进了一步,interface关键字产生一个完全抽象的类,它根本就没有提供任何具体实现。

38.要想创建一个接口,需要用interface关键字来替代class关键字。可以在interface关键字前面添加public关键字(但仅限于该接口在与其同名的文件中被定义)。如果不添加public关键字,则它只具有包访问权限,这样它就只能在同一个包内可用。

接口中的成员变量默认为public、static、final的,接口中的成员方法默认为public的。

39.Java允许一个类继承(extends)一个类及实现(implements)多个接口。

40.通过继承来扩展接口

interface A {
    void a();
}

interface B {
    void b();
}

interface C extends A, B {
    void c();
}

41.接口可以嵌套在类或其他接口中
在类中嵌套接口,该接口可以拥有public、protected、"包访问"、private访问权限。
在接口中嵌套接口,该接口自动就是public访问权限,并且不能定义为其它访问权限。

42.当实现某个接口时,并不需要实现嵌套在其内部的任何接口。而且private接口不能在定义它的类之外被实现。

43.优先使用组合而不是继承。优先使用类而不是接口。

44.可以将一类的定义放在另一个类的定义内部,这就是内部类。
内部类的访问权限可以为public、protected、"包访问"、private。

public class A { //外部类
    private int field = 1;

    class B { //内部类
        private int field;

        public void method() {
            field =  A.this.field; //使用.this 生成对外部类对象的引用
        }
    }
    
    static class C { //静态内部类

    }
}

A a = new A(); //先创建外部类对象
A.B b = a.new B(); //使用.new 通过外部类对象创建内部类对象

A.C c = new A.C(); //静态内部类不需要对外部类对象的引用

45.当生成一个内部类的对象时,此对象与制造它的外部类的对象之间就有了一种联系,所以它能访问其外部类的对象的所有成员(包括private成员),而不需要任何特殊条件。

46.在方法和作用域内的内部类

public class A {
    private int field = 1;

    public void method() {
        class B { //在方法内的内部类
            private int field;

            public void method() {
                field = A.this.field;
            }
        }

        B b = new B();
        b.method();
    }
}

public class A {
    private int field = 1;

    public void method() {
        if(field > 0) {
            class B { //在任意作用域内的内部类
                private int field;

                public void method() {
                    field = A.this.field;
                }
            }
         
            B b = new B();
            b.method();
        }
    }
}

47.匿名内部类

public class A {
    public InterfaceA method(final int param) {
        return new InterfaceA() { //创建匿名内部类
            @Override
            public void method() {
                int test = param; //匿名内部类使用外部类的方法参数param,该参数需要添加final关键字
            }
        };
    }

    private interface InterfaceA {
        void method();
    }
}

48.如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。

在匿名类中不可能有命名构造器,因为它根本没名字,但通过实例初始化,就能够达到为匿名内部类创建一个构造器的效果。

49.普通内部类对象隐式地保存了一个引用,指向创建它的外部类对象。而静态内部类对象则不需要其外部类对象,不能在静态内部类对象中访问非静态外部类对象。

50.普通内部类不能有静态成员变量、静态成员方法、静态内部类。
而静态内部类可以有静态成员变量、静态成员方法、静态内部类。

51.接口内部的类,默认是public和static的。

public interface TestInterface {
    void method();

    class InnerClass implements TestInterface {

        @Override
        public void method() {
            
        }
    }
}

52.一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外部类的所有成员。

public class A {
    public void methodA() {

    }

    class B {
        public void methodB() {

        }

        class C {
            public void methodC() {
                methodA();
                methodB();
            }
        }
    }
}

53.每个内部类都能独立地继承自一个(接口的)实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
内部类允许继承多个非接口类型(类或抽象类),内部类使得多重继承的解决方案变得完整。

54.内部类的继承

public class A { //外部类
    public void methodA() {

    }

    class B { //内部类
        public void methodB() {

        }
    }
}

public class TestClass extends A { //继承外部类

}

public class TestClass extends A.B { //继承内部类
    public TestClass(A a) {
        a.super(); //调用外部类对象的super()方法,程序才能编译通过
    }
}

public class TestClass extends A { //继承外部类
    public class TestClass2 extends A.B { //继承内部类
        
    }
}

55.仍然使用局部内部类而不是匿名内部类的唯一理由是,我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。

56.内部类标识符

TestClass.class //外部类TestClass
TestClass$InnerClass.class //内部类InnerClass

57.异常情形是指阻止当前方法或作用域继续执行的问题。
异常处理程序的任务是将程序从错误状态中恢复,以使程序能要么换一种方式运行,要么继续运行下去。

58.与使用Java中的其他对象一样,我们总是用new在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。
所有标准异常类都有两个构造器:一个是默认构造器,另一个是接收字符串作为参数,以便能把相关信息放入异常对象的构造器。

59.异常将在一个恰当的异常处理程序中得到解决,它的位置可能离异常被抛出的地方很远,也可能会跨越方法调用栈的许多层次。

60.捕获异常
try {

} catch(ExceptionType exceptionType) {

} finally {

}

61.自定义异常

private void test() throws MyException { //throws MyException 为异常说明
    throw new MyException("zwm, custom exception");
}

class MyException extends Exception {
    public MyException() {

    }

    public MyException(String msg) {
        super(msg);
    }
}

try {
    test();
} catch (MyException e) {
    e.printStackTrace(); //打印栈轨迹
}

62.重新抛出异常

try {
    test();
} catch (MyException e) { //第二次捕获异常
    e.printStackTrace(); //打印栈轨迹
}

private void test() throws MyException {
    try {
        test2();
    } catch (MyException e) { //第一次捕获异常
        e.printStackTrace(); //打印栈轨迹
        e.fillInStackTrace(); //更新异常抛出信息
        throw e; //第二次抛出跟第一次相同的异常
    }
}

private void test2() throws MyException {
    throw new MyException("zwm, custom exception"); //第一次抛出异常
}

class MyException extends Exception {
    public MyException() {

    }

    public MyException(String msg) {
        super(msg);
    }
}   

//输出 
com.tomorrow.test20181228.MainActivity$MyException: zwm, custom exception
    at com.tomorrow.test20181228.MainActivity.test2(MainActivity.java:53) //第一次是test2方法抛出的异常
    at com.tomorrow.test20181228.MainActivity.test(MainActivity.java:44)
    at com.tomorrow.test20181228.MainActivity.onCreate(MainActivity.java:36)
    at android.app.Activity.performCreate(Activity.java:7183)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
com.tomorrow.test20181228.MainActivity$MyException: zwm, custom exception
    at com.tomorrow.test20181228.MainActivity.test(MainActivity.java:47) //第二次是test方法抛出的异常
    at com.tomorrow.test20181228.MainActivity.onCreate(MainActivity.java:36)
    at android.app.Activity.performCreate(Activity.java:7183)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
    at android.app.ActivityThread.-wrap11(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

63.Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型(指从Throwable继承而得到的类型):Error用来表示编译时和系统错误(除特殊情况外,一般不用你关心);Exception是可以被抛出的基本类型,在Java类库,用户方法以及运行时故障都可能抛出Exception型异常。

64.属于运行时异常的类型有很多,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。这些异常都是从RuntimeException类基础而来。只能在代码中忽略RuntimeException(及其子类)类型的异常,其他类型异常的处理都是由编译器强制实施的。究其原因,RuntimeException代表的是编程错误。

65.捕获异常有返回值的情况

private int test() {
    int result = -1;
    try {
        test2(); //1.test2()方法抛异常,进入catch模块
        result = 1;
        return result;
    } catch (MyException e) { 
        e.printStackTrace(); 
        result = 2;
        return result; //2.执行return语句,此时result值为2,但是有finally模块,还会继续执行,方法暂时不返回
    } finally {
        result = 3; //3.执行finally模块,此时result值为3,由于finally模块没有return语句,此时会再次执行catch模块的return语句,最终返回result值为2,而不是3!
    }
}

private void test2() throws MyException {
    throw new MyException("zwm, custom exception");
}

66.当覆盖方法的时候,只能抛出(也可以不抛出)在基类方法的异常说明里列出的那些异常。

67.抛出异常的时候,异常处理系统会按照代码的书写顺序找出"最近"的处理程序,找到匹配的处理程序之后,它就认为异常将得到处理,然后就不再继续查找。查找的时候并不要求抛出的异常同处理程序所声明的异常完成匹配,派生类的对象也可以匹配基类的处理程序。

68.String对象是不可变的,String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容,而最初的String对象则丝毫未动。

69.重载"+"与StringBuilder

String s = "abc" + mango + "def" + 47;

这种方式虽然行得通,但是为了生成最终的String,会产生一大堆需要垃圾回收的中间对象。建议使用StringBuilder。

70.类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当地说,是被保存在一个同名的.class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用被称为"类加载器"的子系统。

所有的类都是在对其第一次使用时,动态加载到JVM中的。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。因此,使用new操作符创建类的新对象也会被当作对类的静态成员的引用。类加载器首先检查这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件,在这个类的字节码被加载时,它们会接受验证,以确保没有被破坏,并且不包含不良代码。一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

71.创建enum时,编译器会生成一个相关的类,这个类继承自java.lang.Enum。Enum类实现了Comparable接口,所以它具有compareTo()方法,同时还实现了Serializable接口。

//Color.java
public enum Color {RED, GREEN, BLUE}

//MainActivity.java,测试代码
for(Color color : Color.values()) {
    Log.d(TAG, "zwm, ordinal: " + color.ordinal());
    Log.d(TAG, "zwm, color.compareTo(Color.GREEN): " + color.compareTo(Color.GREEN));
    Log.d(TAG, "zwm, color.equals(Color.GREEN): " + color.equals(Color.GREEN));
    Log.d(TAG, "zwm, color == Color.GREEN: " + (color == Color.GREEN));
    Log.d(TAG, "zwm, color.getDeclaringClass(): " + color.getDeclaringClass());
    Log.d(TAG, "zwm, color.name(): " + color.name());
}

for(String s : "RED GREEN BLUE".split(" ")) {
    Color c = Enum.valueOf(Color.class, s);
    Log.d(TAG, "zwm, c: " + c);
}

//输出
02-24 11:21:15.759 zwm, ordinal: 0
02-24 11:21:15.759 zwm, color.compareTo(Color.GREEN): -1
02-24 11:21:15.759 zwm, color.equals(Color.GREEN): false
02-24 11:21:15.759 zwm, color == Color.GREEN: false
02-24 11:21:15.759 zwm, color.getDeclaringClass(): class com.tomorrow.bustest.Color
02-24 11:21:15.759 zwm, color.name(): RED
02-24 11:21:15.759 zwm, ordinal: 1
02-24 11:21:15.759 zwm, color.compareTo(Color.GREEN): 0
02-24 11:21:15.759 zwm, color.equals(Color.GREEN): true
02-24 11:21:15.760 zwm, color == Color.GREEN: true
02-24 11:21:15.760 zwm, color.getDeclaringClass(): class com.tomorrow.bustest.Color
02-24 11:21:15.760 zwm, color.name(): GREEN
02-24 11:21:15.760 zwm, ordinal: 2
02-24 11:21:15.760 zwm, color.compareTo(Color.GREEN): 1
02-24 11:21:15.760 zwm, color.equals(Color.GREEN): false
02-24 11:21:15.760 zwm, color == Color.GREEN: false
02-24 11:21:15.760 zwm, color.getDeclaringClass(): class com.tomorrow.bustest.Color
02-24 11:21:15.760 zwm, color.name(): BLUE
02-24 11:21:15.761 zwm, c: RED
02-24 11:21:15.761 zwm, c: GREEN
02-24 11:21:15.761 zwm, c: BLUE

72.将静态导入用于enum。

//Color.java
public enum Color {RED, GREEN, BLUE}

//MainActivity.java,测试代码
import static com.tomorrow.bustest.Color.*;
Log.d(TAG, "zwm, color: " + GREEN);

//输出
02-24 11:30:32.093 zwm, color: GREEN

73.向enum中添加新方法。

//Color.java
public enum Color {
    RED("This is RED color"),
    GREEN("This is GREEN color"),
    BLUE("This is BLUE color");

    private String description;
    private Color(String description) {
        this.description = description;
    }
    public String getDescription() {
        return description;
    }


    @Override
    public String toString() {
        return "name: " + name() + ", description: " + description;
    }
}

//MainActivity.java,测试代码
Log.d(TAG, "zwm, color description: " + Color.GREEN.getDescription());
Log.d(TAG, "zwm, color: " + Color.GREEN);

//输出
02-24 11:46:25.799 zwm, color description: This is GREEN color
02-24 11:46:25.799 zwm, color: name: GREEN, description: This is GREEN color

74.switch语句中的enum。

//Color.java
public enum Color {RED, GREEN, BLUE}

//MainActivity.java,测试代码
Color color = Color.GREEN;
switch(color) {
    case RED: //这里不要使用Color.RED,直接使用RED即可
        Log.d(TAG, "zwm, case RED");
        break;
    case GREEN:
        Log.d(TAG, "zwm, case GREEN");
        break;
    case BLUE:
        Log.d(TAG, "zwm, case BLUE");
        break;
    default:
        break;
}

//输出
02-24 15:02:53.402 zwm, case GREEN

75.使用EnumSet替代标志,EnumSet中的元素必须来自一个enum。

//Color.java
public enum Color {RED, GREEN, BLUE}

//MainActivity.java,测试代码
EnumSet<Color> favoriteColor = EnumSet.noneOf(Color.class);
favoriteColor.add(Color.BLUE);
favoriteColor.add(Color.GREEN);
Log.d(TAG, "zwm, favoriteColor.contains(Color.BLUE): " + favoriteColor.contains(Color.BLUE));
Log.d(TAG, "zwm, favoriteColor.contains(Color.RED): " + favoriteColor.contains(Color.RED));

//输出
02-24 15:15:22.816 zwm, favoriteColor.contains(Color.BLUE): true
02-24 15:15:22.816 zwm, favoriteColor.contains(Color.RED): false

76.EnumMap要求其中的键必须来自一个enum。

//Color.java
public enum Color {RED, GREEN, BLUE}

//MainActivity.java,测试代码
EnumMap<Color, String> favoriteColor = new EnumMap<>(Color.class);
favoriteColor.put(Color.BLUE, "This is blue color");
favoriteColor.put(Color.GREEN, "This is green color");
Log.d(TAG, "zwm, favoriteColor.get(Color.BLUE): " + favoriteColor.get(Color.BLUE));
Log.d(TAG, "zwm, favoriteColor.get(Color.RED): " + favoriteColor.get(Color.RED));

//输出
02-24 15:22:29.150 zwm, favoriteColor.get(Color.BLUE): This is blue color
02-24 15:22:29.150 zwm, favoriteColor.get(Color.RED): null

77.enum常量相关的方法。

//Color.java
public enum Color {
    RED {
        @Override
        public String getDescription() {
            return "This is RED";
        }

        @Override
        public int getLength() {
            return 3;
        }
    },
    GREEN {
        @Override
        public String getDescription() {
            return "This is GREEN";
        }
    },
    BLUE {
        @Override
        public String getDescription() {
            return "This is BLUE";
        }
    };

    public abstract String getDescription();
    public int getLength() {
        return 0;
    }
}

//MainActivity.java,测试代码
Color color = Color.RED;
Log.d(TAG, "zwm, desceiption: " + color.getDescription());
Log.d(TAG, "zwm, length: " + color.getLength());

//输出
02-24 15:32:04.402 zwm, desceiption: This is RED
02-24 15:32:04.402 zwm, length: 3
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 7,046评论 0 4
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 5,412评论 0 6
  • 1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?答:可以有多个类,但只能有一个publ...
    岳小川阅读 4,500评论 0 2
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 9,448评论 1 10
  • JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以...
    yangkg阅读 3,868评论 0 1