Halimbawa ng isang panloob na klase

Ang klase ng AbstractList ay may panloob na klase ng Itr . Ito ay isang pagpapatupad ng interface ng Iterator , na ginagawang posible na makakuha ng mga elemento ng mga koleksyon nang paisa-isa:

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

Ginagamit ito sa pamamaraan ng iterator :

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

Ito ay kung paano nakakakuha ang sinumang inapo ng AbstractList ng isang yari na iterator. At kung kailangan mong i-customize ang iterator, maaari mong ipatupad ang iyong sariling klase na nagmamana ng Iterator o Itr , at pagkatapos ay i-override ang pamamaraan ng iterator . Halimbawa, ito ang ginagawa ng klase ng ArrayList .

Ang klase ng Itr ay hindi static. Bilang resulta, ang Itr object ay may reference sa AbstractList instance at maaaring ma-access ang mga pamamaraan nito ( size , get , remove ).

Halimbawa ng isang static na nested na klase

Ang Integer class ay may isang IntegerCache nested class.

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 encapsulates functionality na lumilikha ng isang cache at nag-iimbak ng mga hanay ng cache pati na rin ang mga naka-cache na halaga sa kanilang sarili. Kaya, lahat ng bagay na nauugnay sa cache ay pinananatili sa isang hiwalay na klase. Ginagawa nitong mas madaling basahin at baguhin ang code. Code na gumagamit ng klase:

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

Hindi ina-access ng klase ng IntegerCache ang mga non-static na field at pamamaraan ng klase ng Integer . Bilang karagdagan, ito ay naa-access lamang sa static na valueOf method. Iyon ay, ito ay nakasalalay sa klase ng Integer mismo, hindi sa mga indibidwal na pagkakataon nito. At nangangahulugan ito na ang IntegerCache ay static.

Halimbawa ng hindi kilalang panloob na klase

Bilang isang halimbawa ng isang hindi kilalang klase, kunin natin ang InputStream at ang static na nullInputStream na pamamaraan nito:

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

Ang pamamaraan ay nagbabalik ng isang walang laman na InputStream , na ipinatupad ng isang hindi kilalang klase. Dahil ang klase ay hindi dapat magkaroon ng mga inapo, ginawa namin itong anonymous.

Sa pagdaragdag ng Java Stream API, ang mga anonymous na klase ay naging ubiquitous: lahat ng lambda expression ay mga anonymous na klase na nagpapatupad ng ilang functional na interface. Isaalang-alang ang ilang halimbawa.

Ang klase ng AbstractStringBuilder ay naglalaman ng magulang ng sikat na StringBuilder at StringBuffer na mga klase:

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

Ang klase ng Files ay may para sa pag-convert ng isang Closeable sa isang Runnable :

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

Ang klase ng Klase ay may pamamaraan para sa pagkuha ng isang string na representasyon ng isang pamamaraan:

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