Ví dụ về một lớp bên trong

Lớp AbstractList có lớp bên trong Itr . Đây là một triển khai của giao diện Iterator , cho phép lấy từng phần tử của bộ sưu tập:

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();
	}
}

Nó được sử dụng trong phương thức iterator :

public Iterator<E> iterator() {
	return new Itr();
}

Đây là cách mà bất kỳ hậu duệ nào của AbstractList đều có một trình lặp làm sẵn. Và nếu bạn cần tùy chỉnh trình lặp, bạn có thể triển khai lớp của riêng mình kế thừa Iterator hoặc Itr và sau đó ghi đè phương thức trình lặp . Ví dụ, đây là chức năng của lớp ArrayList .

Lớp Itr không tĩnh. Kết quả là, đối tượng Itr có tham chiếu đến đối tượng AbstractList và có thể truy cập các phương thức của nó ( size , get , remove ).

Ví dụ về một lớp lồng tĩnh

Lớp Integer có một lớp lồng nhau 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 đóng gói chức năng tạo bộ đệm và lưu trữ phạm vi bộ đệm cũng như chính các giá trị được lưu trong bộ đệm. Do đó, mọi thứ liên quan đến bộ đệm được giữ trong một lớp riêng biệt. Điều này làm cho việc đọc và sửa đổi mã dễ dàng hơn. Mã sử ​​dụng lớp:

public static Integer valueOf(int i) {
	if (i >= IntegerCache.low && i <= IntegerCache.high)
    		return IntegerCache.cache[i + (-IntegerCache.low)];
	return new Integer(i);
}

Lớp IntegerCache không truy cập các trường và phương thức không tĩnh của lớp Integer . Ngoài ra, nó chỉ được truy cập trong phương thức valueOf tĩnh . Nghĩa là, nó được liên kết với chính lớp Số nguyên , không phải với các thể hiện riêng lẻ của nó. Và điều đó có nghĩa là IntegerCache là tĩnh.

Ví dụ về một lớp bên trong ẩn danh

Để làm ví dụ về một lớp ẩn danh, hãy lấy InputStream và phương thức nullInputStream tĩnh của nó :

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;
    	}
    };
}

Phương thức này trả về một InputStream trống , được triển khai bởi một lớp ẩn danh. Vì lớp không được phép có hậu duệ, nên chúng tôi đã ẩn danh lớp này.

Với việc bổ sung Java Stream API, các lớp ẩn danh đã trở nên phổ biến: tất cả các biểu thức lambda đều là các lớp ẩn danh triển khai một số giao diện chức năng. Hãy xem xét một số ví dụ.

Lớp AbstractStringBuilder chứa cha của các lớp StringBuilderStringBuffer nổi tiếng :

@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);
}

Lớp Files có chức năng chuyển đổi Closeable thành Runnable :

private static Runnable asUncheckedRunnable(Closeable c) {
	return () -> {
    	try {
        	c.close();
    	} catch (IOException e) {
        	throw new UncheckedIOException(e);
    	}
	};
}

Lớp Class có một phương thức để lấy biểu diễn chuỗi của một phương thức:

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(",", "(", ")")));
}