Exemplu de clasă interioară

Clasa AbstractList are o clasă internă Itr . Este o implementare a interfeței Iterator , care face posibilă obținerea elementelor colecțiilor unul câte unul:


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

Este utilizat în metoda iteratorului :


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

Acesta este modul în care orice descendent al AbstractList obține un iterator gata făcut. Și dacă trebuie să personalizați iteratorul, puteți implementa propria clasă care moștenește Iterator sau Itr și apoi să suprascrieți metoda iteratorului . De exemplu, asta face clasa ArrayList .

Clasa Itr este non-statică. Drept urmare, obiectul Itr are o referință la instanța AbstractList și poate accesa metodele acesteia ( size , get , remove ).

Exemplu de clasă imbricată statică

Clasa Integer are o clasă imbricată 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 încapsulează funcționalitatea care creează un cache și stochează intervalele cache, precum și valorile cache în sine. Astfel, tot ce este legat de cache este păstrat într-o clasă separată. Acest lucru facilitează citirea și modificarea codului. Cod care folosește clasa:


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

Clasa IntegerCache nu accesează câmpurile și metodele non-statice ale clasei Integer . În plus, este accesat numai în metoda static valueOf . Adică este legat de clasa Integer însăși, nu de instanțe individuale. Și asta înseamnă că IntegerCache este static.

Exemplu de clasă interioară anonimă

Ca exemplu de clasă anonimă, să luăm InputStream și metoda sa statică 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;
    	}
    };
}

Metoda returnează un InputStream gol , implementat de o clasă anonimă. Pentru că clasa nu ar trebui să aibă descendenți, am făcut-o anonimă.

Odată cu adăugarea API-ului Java Stream, clasele anonime au devenit omniprezente: toate expresiile lambda sunt clase anonime care implementează o anumită interfață funcțională. Luați în considerare câteva exemple.

Clasa AbstractStringBuilder conține părintele celebrelor clase StringBuilder și 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);
}

Clasa Files are un pentru conversia unui Closeable într-un Runnable :


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

Clasa Class are o metodă pentru a obține o reprezentare în șir a unei metode:


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