JAVA拾遗

枚举

枚举允许构造函数和抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum TrafficLight {
RED(60) { // 这样调用构造函数
public TrafficLight next() {
return GREEN;
}
}, // 注意此处的逗号
GREEN(30) {
public TrafficLight next() {
return RED;
}
}; // 元素列表应置于最前
private int time;
public abstract TrafficLight next();
// 枚举中构造函数必须为private
private TrafficLight(int time) { this.time = time; }
}

枚举只有一个成员时就可以作为一种单例实现方式

单元素的枚举类型已经成为实现Singleton的最佳方式 ——Joshua Bloch, Effective JAVA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private Singleton() { }
public static Singleton instance() {
return SingletonHolder.INSTANCE.getInstance();
}
private enum SingletonHolder {
INSTANCE;
private Singleton singleton;
SingletonHolder() {
singleton = new Singleton();
}
public Singleton getInstance() {
return singleton;
}
}
}

可变参数方法

使用可变参数方法时编译器为其隐式创建一个数组在方法体中可以数组的形式访问参数列表

1
2
3
public static void printArray(int... is) {
for(int i : is) { ... }
}

泛型(Generic)

容器(Container)

One of the reasons that generic comes out.

1
ArrayList<String> strList = new ArrayList<>();

Declare a generic class.

1
class MyList <T> { … }

Declare a generic function.

1
public <T> T get(int index) { … }

类型擦除(Type Erasure)

If you do this below, you will get an error.

1
new ArrayList<int>(); // ERROR!

ERROR: Type argument can not be basic type.

Types are removed from a JAVA program, before it is executed at runtime.

1
2
3
public <T> T add(T a, T b) {
return a + b; // ERROR!
}

ERROR: Operator '+' cannot be applied to 'T', 'T'.

However, similar codes in C++ works.

The reason is that in C++ template can be regarded as advanced macro.

But this one in JAVA is okay.

1
2
3
public <T> boolean isSame(T a, T b) {
return a.equals(b);
}

T is just a Object. That's why the argument can not be basic type, and that explains why operator '+' is not allowed.

JAVA can not get anything from type argument, and the declaration below causes error.

1
Class<?> c = ArrayList<String>.class; // ERROR!

This one is correct.

1
Class<?> c = ArrayList.class;

In JAVA, ArrayList<String> and ArrayList<Integer> are the same type.

无界通配符(Unbounded Wildcard) <?>

Wildcard(通配符) <?> can be used in variable declarations, but not in the definition of a generic type.

1
Class<?> c = ArrayList.class;

It is the same as the code below.

1
Class<? extends Object> c = ArrayList.class;

上界通配符(Upper Bound Wildcard) <? extends …>

Use <? extends …> in function argument when calling T's member method is required.

1
2
3
4
5
void printText(List<? extends TextView> textViews) {
for(TextView tv: textViews) {
System.out.println(tv.getText());
}
}

协变(Covariance)

In JAVA, it looks fine but wrong.

1
ArrayList<Fruit> fruits = new ArrayList<Apple>(); // ERROR!

JAVA's generic is invariant(不变的), so List<Base> has no relation to List<Derive>. Covariance means that List<Derive> inherits List<Base>, its needed in some situations.

Code like this when covariance is needed.

1
ArrayList<? extends Fruit> fruits = new ArrayList<Apple>();

But the restriction is that any alteration to T type variable is unavailable as well as function with T type parameter is not allowed.

1
fruits.add(Apple()); // ERROR!

So covariance means read-only.

1
2
3
4
5
void printText(List<? extends TextView> textViews) {
for(TextView tv: textViews) {
System.out.println(tv.getText());
}
}

逆变(Contravariance)

Contravariance is a totally different situation.

1
ArrayList<? super Apple> apples = new ArrayList<Fruit>();

But there still exists restriction.

1
Apple apple = apples.get(0);

That contravariance means write-only. See this example below.

1
2
3
4
void addText(List<? Super TextView> textViews) {
TextView tv = …;
textViews.add(tv);
}

In a word, follow PECS rule.

PECS Rule

Producer Extends Consumer Super.

多重约束(Multiple Boundary)

So strange because A and B are interfaces, but still keyword extends is used here.

1
2
3
interface A { … }
interface B { … }
class C <T extends A & B> { … }

多线程

同步锁

下例为经典的代理卖票问题

没有同步锁的情况多个线程同时访问共享的资源将导致线程不同步又称线程不安全

1
2
3
4
5
6
7
8
9
10
@Override public void run() {
while(true) {
synchronized(this) { // 资源共享
if(ticket > 0) {
Log.d("TAG", Thread.currentThread().getName()); // 获取线程名
--ticket;
} else break;
}
}
}

线程池

管理线程提高程序性能

  • 可缓存线程池可回收旧线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ExecutorService exec = Executors.newCachedThreadPool();
    for(int i = 0; i < 10; ++i) {
    final int index = i; // JAVA8中匿名/局部类的变量捕获
    exec.execute(new Runnable() {
    @Override public void run() {
    ...
    }
    });
    }
  • 有限线程池Executors.newFixedThreadPool(n)创建一个定长线程池可控制线程最大并发数

  • 单一线程池Executors.newSingleThreadExecutor()保证所有任务按指定顺序执行只会用唯一的工作线程来执行任务相当于线程数量为1FixedThreadPool

JNI(Java Native Interface)

使用native关键字调用操作系统的底层函数方便代码在不同平台上运作也是JavaC/C++的桥梁

1
2
3
4
5
6
public synchronized void start() {
if(started) throw new IllegalThreadStateException();
started = true;
start0();
}
private native void start0();

❽Optional

1
2
3
4
Optional.ofNullable(user)
.map(User::getPhone)
.filter(it -> it.getPassword().equals("password"))
.ifPresent(System.out::println);