内部クラスの例
AbstractListクラスにはItr内部クラスがあります。これはIteratorインターフェイスの実装であり、コレクションの要素を 1 つずつ取得できるようになります。
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException(e);
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
これはイテレータメソッドで使用されます。
public Iterator<E> iterator() {
return new Itr();
}
これは、 AbstractListの子孫が既製のイテレータを取得する方法です。また、イテレータをカスタマイズする必要がある場合は、IteratorまたはItrを継承する独自のクラスを実装し、イテレータメソッドをオーバーライドできます。たとえば、これはArrayListクラスが行うことです。
Itrクラスは非静的です。その結果、ItrオブジェクトはAbstractListインスタンスへの参照を持ち、そのメソッド ( size、get、Remove ) にアクセスできるようになります。
静的ネストされたクラスの例
Integerクラスには、 IntegerCacheネストされたクラスがあります。
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
static {
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
}
}
high = h;
VM.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
IntegerCache は、キャッシュを作成し、キャッシュ範囲とキャッシュされた値自体を保存する機能をカプセル化します。したがって、キャッシュに関連するものはすべて別のクラスに保持されます。これにより、コードの読み取りと変更が容易になります。クラスを使用するコード:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCacheクラスは、 Integerクラスの非静的フィールドおよびメソッドにはアクセスしません。さらに、静的なvalueOfメソッドでのみアクセスされます。つまり、個々のインスタンスではなく、Integerクラス自体にバインドされます。これは、IntegerCacheが静的であることを意味します。
匿名内部クラスの例
匿名クラスの例として、InputStreamとその静的nullInputStreamメソッドを取り上げます。
public static InputStream nullInputStream() {
return new InputStream() {
private volatile boolean closed;
private void ensureOpen() throws IOException {
if (closed) {
throw new IOException("Stream closed");
}
}
@Override
public int available () throws IOException {
ensureOpen();
return 0;
}
@Override
public int read() throws IOException {
ensureOpen();
return -1;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
ensureOpen();
return -1;
}
@Override
public byte[] readAllBytes() throws IOException {
ensureOpen();
return new byte[0];
}
@Override
public int readNBytes(byte[] b, int off, int len)throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
ensureOpen();
return 0;
}
@Override
public byte[] readNBytes(int len) throws IOException {
if (len < 0) {
throw new IllegalArgumentException("len < 0");
}
ensureOpen();
return new byte[0];
}
@Override
public long skip(long n) throws IOException {
ensureOpen();
return 0L;
}
@Override
public void skipNBytes(long n) throws IOException {
ensureOpen();
if (n > 0) {
throw new EOFException();
}
}
@Override
public long transferTo(OutputStream out) throws IOException {
Objects.requireNonNull(out);
ensureOpen();
return 0L;
}
@Override
public void close() throws IOException {
closed = true;
}
};
}
このメソッドは、匿名クラスによって実装された空のInputStreamを返します。このクラスは子孫を持つことを想定していないため、匿名にしました。
Java Stream API の追加により、匿名クラスが遍在するようになりました。すべてのラムダ式は、何らかの関数インターフェイスを実装する匿名クラスです。いくつかの例を考えてみましょう。
AbstractStringBuilderクラスには、有名なStringBuilderクラスとStringBufferクラスの親が含まれています。
@Override
public IntStream chars() {
return StreamSupport.intStream(
() -> {
byte[] val = this.value;
int count = this.count;
byte coder = this.coder;
return coder == LATIN1
? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CharsSpliterator(val, 0, count, 0);
},
Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
false);
}
Filesクラスには、CloseableをRunnableに変換するための があります。
private static Runnable asUncheckedRunnable(Closeable c) {
return () -> {
try {
c.close();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}
Classクラスには、メソッドの文字列表現を取得するためのメソッドがあります。
private String methodToString(String name, Class<?>[] argTypes) {
return getName() + '.' + name +
((argTypes == null || argTypes.length == 0) ?
"()" :
Arrays.stream(argTypes)
.map(c -> c == null ? "null" : c.getName())
.collect(Collectors.joining(",", "(", ")")));
}
GO TO FULL VERSION