JAVA拾遗
枚举
枚举允许构造函数和抽象方法。
1 | public enum TrafficLight { |
枚举只有一个成员时,就可以作为一种单例实现方式。
单元素的枚举类型已经成为实现Singleton的最佳方式。 ——Joshua Bloch, Effective JAVA
1 | public class Singleton { |
可变参数方法
使用可变参数方法时,编译器为其隐式创建一个数组,在方法体中可以数组的形式访问参数列表。
1 | public static void printArray(int... 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 | public <T> T add(T a, T b) { |
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 | public <T> boolean isSame(T a, T 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 | void printText(List<? extends TextView> textViews) { |
协变(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 toList<Derive>
. Covariance means thatList<Derive>
inheritsList<Base>
, it’s 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 | void printText(List<? extends TextView> textViews) { |
逆变(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 | void addText(List<? Super TextView> textViews) { |
In a word, follow PECS rule.
PECS Rule
Producer Extends Consumer Super.
多重约束(Multiple Boundary)
So strange because
A
andB
are interfaces, but still keywordextends
is used here.
1 | interface A { … } |
多线程
同步锁
下例为经典的代理卖票问题。
没有同步锁的情况,多个线程同时访问共享的资源,将导致线程不同步,又称线程不安全。
1 | public void run() { |
线程池
管理线程,提高程序性能。
可缓存线程池:可回收旧线程;
1
2
3
4
5
6
7
8
9ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0; i < 10; ++i) {
final int index = i; // JAVA8中匿名/局部类的变量捕获
exec.execute(new Runnable() {
public void run() {
...
}
});
}有限线程池:
Executors.newFixedThreadPool(n)
,创建一个定长线程池,可控制线程最大并发数;单一线程池:
Executors.newSingleThreadExecutor()
,保证所有任务按指定顺序执行,只会用唯一的工作线程来执行任务,相当于线程数量为1的FixedThreadPool
。
JNI(Java Native Interface)
使用native
关键字,调用操作系统的底层函数,方便代码在不同平台上运作,也是Java和C/C++的桥梁。
1 | public synchronized void start() { |
❽Optional
1 | Optional.ofNullable(user) |