Ichki klassning misoli
AbstractList klassida Itr deb nomlangan ichki klass mavjud. Bu Iterator interfeysining amalga oshirilishi bo'lib, u kollektsiyalar elementlarini ketma-ket olish imkonini beradi:
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();
}
}
U iterator metodida ishlatiladi:
public Iterator<E> iterator() {
return new Itr();
}
Shunday qilib, har qanday AbstractList merosxo'r klass tayyor ishlaydigan iteratorni oladi. Agar siz iteratorni sozlashni xohlasez, o'z klassingizni yaratib, uni Iterator yoki Itrdan meros qilib olishingiz va metodni iterator qayta aniqlashingiz mumkin. Masalan, ArrayList klassida bo'lgani kabi.
Itr klassi - statik emas. Shu sababli, Itrning nusxasi AbstractListning nusxasiga ishoraga ega va u uning metodlariga (size, get, remove) murojaat qilishi mumkin.
Ichki statik klassning misoli
Integer klassida IntegerCache deb nomlangan ichki klass mavjud:
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 kechni generatsiya qilishni inkapsulyatsiya qiladi, kech diapazonini va kechlangan qiymatlarni saqlaydi. Shunday qilib, kech bilan bog'liq hamma narsa alohida klassga chiqarilgan. Bu kodni o'qishni va unga o'zgartirish kiritishni osonlashtiradi. Klassdan foydalanish kodi:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache klassi Integer klassining statik bo'lmagan maydonlari va metodlariga murojaat qilmaydi, va ularga faqat valueOf statik metodida murojaat qilinadi. Demak, u Integer klassiga umuman bog'liq, alohida nusxalariga emas, — va shu sababli IntegerCache statik.
Ichki anonim klassning misoli
Anonim klass misoli sifatida InputStream klassini va uning nullInputStream statik metodini olamiz:
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;
}
};
}
Metod bo'sh InputStream qaytaradi va uning amalga oshirilishi uchun aynan anonim klass ishlatiladi. Klass uchun merosxo'rlar rejalashtirilmaganligi sababli, uni anonim qilishgan.
Java Stream API qo'shilishi bilan anonim klasslar keng qo'llanila boshlandi: barcha lambda-iboralari — bu anonim klasslar, ular o'ziga xos funksional interfeysni amalga oshiradi. Misollarni ko'rib chiqamiz.
AbstractStringBuilder klassida — mashhur StringBuilder va StringBufferning ota klassi:
@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 klassida — Closeableni Runnablega aylantirish uchun metod:
private static Runnable asUncheckedRunnable(Closeable c) {
return () -> {
try {
c.close();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}
Class klassida — metodni matn ko'rinishiga o'tkazish uchun metod:
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