Java隐藏特征

Double Brace Initialization

双括号初始化,创建一个从指定类(外部大括号)派生的匿名类,并在该类(内部大括号)中提供初始化块。

每次使用双括号初始化时,都会生成一个新类,创建的类具有指向周围外部类的隐式this指针。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};

…将产生这些类:

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class

当然,如果你这样只做一次,它将不需要太多的初始化时间。

优点非常明显:

  • 对于熟悉该使用方法的人而言,它具有更好的可读性以及更好的维护性。

缺点:

  • 在使用Double Brace Initialization的时候,我们实际上创建了一个匿名类。匿名类有一个性质,那就是该匿名类实例将拥有一个包含它的类型的引用。如果我们将该匿名类实例通过函数调用等方式传到该类型之外,那么对该匿名类的保持实际上会导致外层的类型无法被释放,进而造成内存泄露。
  • 另外一个缺点则是破坏了equals()函数的语义。在为一个类型实现equals()函数的时候,我们可能需要判断两个参与比较的类型是否一致。

最常见的一种解决方案就是使用第三方类库。例如由Apache Commons类库提供的ArrayUtils.toMap()函数就提供了一种非常清晰的创建Map的实现:

1
2
3
4
5
Map<Integer, String> map = (Map) ArrayUtils.toMap(new Object[][] {
{1, "one"},
{2, "two"},
{3, "three"}
});

类实例化顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class App {
public App(String name) { System.out.println(name + "'s constructor called"); }

static { System.out.println("static initializer called"); }

{ System.out.println("instance initializer called"); }

static { System.out.println("static initializer2 called"); }

{ System.out.println("instance initializer2 called"); }

public static void main( String[] args ) {
new App("one");
new App("two");
}
}

ThreadLocal

提供线程局部变量。这些变量与普通变量不同,因为每个访问一个线程(通过其get或set方法)的线程都有其自己的,独立初始化的变量副本。

ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段(例如,用户ID或事务ID)。

只要线程是活动的并且ThreadLocal 实例是可访问的,则每个线程都对其线程局部变量的副本持有隐式引用。线程消失后,其线程本地实例的所有副本都将进行垃圾回收(除非存在对这些副本的其他引用)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.concurrent.atomic.AtomicInteger;

public class UniqueThreadIdGenerator {

private static final AtomicInteger uniqueId = new AtomicInteger(0);

private static final ThreadLocal < Integer > uniqueNum =
new ThreadLocal < Integer > () {
@Override protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};

public static int getCurrentThreadId() {
return uniqueId.get();
}
} // UniqueThreadIdGenerator

Compare and swap (CAS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class SimulatedCAS {
private int value;

public synchronized int getValue() { return value; }

public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (value == expectedValue)
value = newValue;
return oldValue;
}
}

public class CasCounter {
private SimulatedCAS value;

public int getValue() {
return value.getValue();
}

public int increment() {
int oldValue = value.getValue();
while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
oldValue = value.getValue();
return oldValue + 1;
}
}

Lock-free and wait-free algorithms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class PseudoRandomUsingSynch implements PseudoRandom {
private int seed;

public PseudoRandomUsingSynch(int s) { seed = s; }

public synchronized int nextInt(int n) {
int s = seed;
seed = Util.calculateNext(seed);
return s % n;
}
}

public class PseudoRandomUsingAtomic implements PseudoRandom {
private final AtomicInteger seed;

public PseudoRandomUsingAtomic(int s) {
seed = new AtomicInteger(s);
}

public int nextInt(int n) {
for (;;) {
int s = seed.get();
int nexts = Util.calculateNext(s);
if (seed.compareAndSet(s, nexts))
return s % n;
}
}
}

------ 本文结束------

本文标题:Java隐藏特征

文章作者:Perkins

发布时间:2020年10月09日

原始链接:https://perkins4j2.github.io/posts/3350900/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。