CodeGym /Corsi /All lectures for IT purposes /Esempi di diversi tipi di classi dal JDK

Esempi di diversi tipi di classi dal JDK

All lectures for IT purposes
Livello 1, Lezione 74
Disponibile

Esempio di classe interna

La classe AbstractList ha una classe interna Itr . È un'implementazione dell'interfaccia Iterator , che consente di ottenere gli elementi delle raccolte uno per uno:


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

Viene utilizzato nel metodo iteratore :


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

Questo è il modo in cui qualsiasi discendente di AbstractList ottiene un iteratore già pronto. E se è necessario personalizzare l'iteratore, è possibile implementare la propria classe che eredita Iterator o Itr e quindi eseguire l'override del metodo iteratore . Ad esempio, questo è ciò che fa la classe ArrayList .

La classe Itr non è statica. Di conseguenza, l' oggetto Itr ha un riferimento all'istanza AbstractList e può accedere ai suoi metodi ( size , get , remove ).

Esempio di una classe nidificata statica

La classe Integer ha una classe annidata 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 incapsula la funzionalità che crea una cache e archivia gli intervalli della cache nonché i valori memorizzati nella cache stessi. Pertanto, tutto ciò che riguarda la cache viene conservato in una classe separata. Ciò semplifica la lettura e la modifica del codice. Codice che utilizza la classe:


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

La classe IntegerCache non accede ai campi e ai metodi non statici della classe Integer . Inoltre, vi si accede solo nel metodo valueOf statico . Cioè, è legato alla classe Integer stessa, non alle sue singole istanze. E questo significa che IntegerCache è statico.

Esempio di classe interna anonima

Come esempio di una classe anonima, prendiamo InputStream e il suo metodo nullInputStream statico:


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

Il metodo restituisce un InputStream vuoto , implementato da una classe anonima. Poiché la classe non dovrebbe avere discendenti, l'abbiamo resa anonima.

Con l'aggiunta dell'API Java Stream, le classi anonime sono diventate onnipresenti: tutte le espressioni lambda sono classi anonime che implementano un'interfaccia funzionale. Considera alcuni esempi.

La classe AbstractStringBuilder contiene il genitore delle famose classi StringBuilder e 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);
}

La classe Files ha un per convertire un Closeable in un Runnable :


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

La classe Class ha un metodo per ottenere una rappresentazione di stringa di un metodo:


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(",", "(", ")")));
}
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION