Pequeñas optimizaciones en Java 9-16

Cuando sale una nueva versión de Java, las características principales siempre se discuten activamente. Pero hay trabajo que normalmente permanece "invisible": pequeñas optimizaciones en la biblioteca estándar. Nos ayudan acelerando sigilosamente nuestro código y sin exigir nada a cambio, ¡y ni siquiera sabemos nada sobre ellos!



Esta situación es corregida por Tagir Valeev (lany), hablando de tales optimizaciones. Primero, habló en Joker 2019 con una charla "Java 9-14: pequeñas optimizaciones", puedes ver su video . Luego, como a la audiencia le gustó mucho, en JPoint 2020 desarrolló el tema . Y ahora decidimos hacer un post para Habr del segundo informe para que no solo se pudiera ver, sino también leer.





Además, debajo del corte, el texto irá en nombre del orador.



Introducción



Solo veremos las cosas más básicas que todos usan directa o indirectamente: cadenas, colecciones y reflexión. No cubrimos las API posteriores a Java 8. Todas las mejoras de rendimiento son gratuitas si ejecuta su código Java 8 en una JVM más nueva.



. , , , . Intel Core i7-6820HQ Windows 10. , . , +UseParallelGC. , « , ».



, « .» , .





String.hashCode



String.hashCode. , - « »:



@Benchmark
public int calcHashCode() {
  return "  ".hashCode();
}


Java 12 Java 13 :





- 4 ? , . , . : « » « »:



@Benchmark
public int calcHashCode() {
  return "  ".hashCode();
}

@Benchmark
public int calcHashCode2() {
  return "  ".hashCode();
}




, Java 12, «» , «» . Java 13 . ?

-. Java 9 Java 12 hashCode() ( -, Compact Strings):



/** Cache the hash code for the string */
private int hash; // Default to 0

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        hash = h = isLatin1() ? StringLatin1.hashCode(value)
                              : StringUTF16.hashCode(value);
    }
    return h;
}


- , . 4 - 0. - . , - , 0 . — , , .



JPoint 2015 « java.lang.String». Java 8 « » - 0, « » . , , String .



, .



layout String Java 8. , 64- JVM String 4 , , . 1 .





, 32- JVM . , - , .



Java 9 , , . , , Latin-1, UTF-16 . 3 , VM, 3 0. , ?



Java 13, String.hashIsZero:





. - :



private int hash; // Default to 0
private boolean hashIsZero; // Default to false;
public int hashCode() {
    int h = hash;
    if (h == 0 && !hashIsZero) {
        h = isLatin1() ? StringLatin1.hashCode(value)
                       : StringUTF16.hashCode(value);
        if (h == 0) {
            hashIsZero = true;
        } else {
            hash = h;
        }
    }
    return h;
}


hashIsZero? , hashIsCalculated true, .



, hashCode() , . , , -, 0 ( ). , . hashIsCalculated , hashIsCalculated true , 0, .



, String: , , .



, , , . .



String.concat



+, String.concat(). , . :



@Param({"", "is a very very very very very very very very cool conference!"})
String data;

@Benchmark
public String concat() {
  return "JPoint ".concat(data);
}

@Benchmark
public String plus() {
  return "JPoint " + data;
}


:





, String.concat() Java 8-14 ~3 , + 15 , ~19 . ?



Java. . , breaking change. String.concat() , : , - 0, . , : , .



, .





, . Java 8 String.concat() , +, Java 9 . Java 12 , Java 13 Java 14 String.concat() + 10%.



String.concat(). Java 9 JEP 280 — invokedynamic-. + , String.concat() JEP 280 .



Java 9 :





, Java . , , String.concat(). ?



String.concat() Java 12:



public String concat(String str) {
    if (str.isEmpty()) {
        return this;
    }
    if (coder() == str.coder()) {
        byte[] val = this.value;
        byte[] oval = str.value;
        int len = val.length + oval.length;
        byte[] buf = Arrays.copyOf(val, len);
        System.arraycopy(oval, 0, buf, val.length, oval.length);
        return new String(buf, coder);
    }
    int len = length();
    int olen = str.length();
    byte[] buf = StringUTF16.newBytesFor(len + olen);
    getBytes(buf, 0, UTF16);
    str.getBytes(buf, len, UTF16);
    return new String(buf, UTF16);
}


, , . , , .



public String concat(String str) {
    if (str.isEmpty()) {
        return this;
    }
    return StringConcatHelper.simpleConcat(this, str);
}

static String simpleConcat(Object first, Object second) {
    String s1 = stringOf(first);
    String s2 = stringOf(second);
    // start "mixing" in length and coder or arguments, order is not
    // important
    long indexCoder = mix(initialCoder(), s2);
    indexCoder = mix(indexCoder, s1);
    byte[] buf =(indexCoder);
    // prepend each argument in reverse order, since we prepending
    // from the end of the byte array
    indexCoder = prepend(indexCoder, buf, s2);
    indexCoder = prepend(indexCoder, buf, s1);
    return newString(buf, indexCoder);
}


Java 13 simpleConcat(), . , , mix() prepend(). newArray():



static byte[] newArray(long indexCoder) {
    byte coder = (byte)(indexCoder >> 32);
    int index = (int)indexCoder;
    return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
}


, . . Java 12 newArray() copyOf(), .





.





, , 11 — . , JDK-8247605, Java 16.

simpleConcat():



static String simpleConcat(Object first, Object second) {
    String s1 = stringOf(first);
    String s2 = stringOf(second);
    // start "mixing" in length and coder or arguments, order is not
    // important
    long indexCoder = mix(initialCoder(), s2);
    indexCoder = mix(indexCoder, s1);
    byte[] buf =(indexCoder);
    // prepend each argument in reverse order, since we prepending
    // from the end of the byte array
    indexCoder = prepend(indexCoder, buf, s2);
    indexCoder = prepend(indexCoder, buf, s1);
    return newString(buf, indexCoder);
}


, s1 s2 — . , . . , , . — :



...
String s1 = stringOf(first);
String s2 = stringOf(second);
if (s1.isEmpty()) {
    // newly created string required, see JLS 15.18.1
    return new String(s2);
}   
if (s2.isEmpty()) {
    // newly created string required, see JLS 15.18.1
    return new String(s1);
}  
...


, , , , . , .



Java 16, :





( , ) , , — ~6 .



: , , . , target- Java 9 .



invokedynamic — , .



TreeMap.computeIfAbsent



, Java 8 map:



  • putIfAbsent()
  • computeIfAbsent()
  • computeIfPresent()
  • compute()
  • merge()


map, , putIfAbsent(), , , . , , . , computeIfAbsent():



default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
         V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }

    return v;
}


computeIfAbsent() map, . , null, .



. , : get() - , , put() , . 2 , .



, , map. . Java 8, , map :





TreeMap . — , - . , , .



2017 , Java 10. Code Review, . 2019 , merge(), . Java 15, , :





, . map computeIfAbsent() , . computeIfPresent() , . map , , 10-20 % .



. , , , — .



public BigInteger fibo(int arg) {
    if (arg < 1) {
        throw new IllegalArgumentException();
    }
    if (arg <= 2) {
        return BigInteger.ONE;
    }
    return fibo(arg - 1).add(fibo(arg - 2));
}

public static void main(String[] args) {
    Fibo fibo = new Fibo();
    System.out.println(fibo.fibo(100));
}


100. , . :



Map<Integer, BigInteger> map = new HashMap<>();

private BigInteger calcFibo(int arg) {
    if (arg < 1) {
        throw new IllegalArgumentException();
    }
    if (arg <= 2) {
        return BigInteger.ONE;
    }
    return fibo(arg - 1).add(fibo(arg - 2));
}

public BigInteger fibo(int arg) {
    BigInteger value = map.get(arg);
    if (value == null) {
        value = calcFibo(arg);
        map.put(arg, value);
    }
    return value;
}


, , HashMap. calcFibo() , , , .



, :



public static void main(String[] args) {
    Fibo fibo = new Fibo();
    System.out.println(fibo.fibo(100));
    // 354224848179261915075
    System.out.println(fibo.map.get(100));
    // 354224848179261915075
}


. 100, map. , map:



System.out.println(fibo.map.size());
// 100  


100 . , , .



Java 7. . IntelliJ IDEA if fibo() computeIfAbsent(), :



public BigInteger fibo(int arg) {
    return map.computeIfAbsent(arg, this::calcFibo);
}


, . null. . map 185. , .



map , . , get() put(), - .



computeIfAbsent() , :



  1. -.
  2. , .
  3. mappingFunction().
  4. null, null.
  5. .
  6. -.
  7. size 1.
  8. , 3.


, map, . . - , , . 5 , .



, map, 1. HashMap . , HashMap .



Java 9, , . : ConcurrentModificationException. HashMap .



- computeIfAbsent(), TreeMap HashMap, , , TreeMap . Java 8-14, Java 15 , .



, computeIfAbsent() , . ,



The mapping function should not modify this map during computation.


ArrayList.removeIf



removeIf() Java 8 , :



default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) {
            each.remove();
            removed = true;
        }
    }
    return removed;
}  


, , Iterator.remove() , , removed, , . Java 8 , .



default- , . ArrayList Java 8, Java 9 . , .



: ArrayList, 0 size-1 :



data = new ArrayList<>();
for (int i = 0; i < size; i++) {
  data.add(i);
}


, , . , :



removeAll:   list.removeIf(x -> true);
removeHalf:  list.removeIf(x -> x % 2 == 0);
removeLast:  list.removeIf(x -> x == size - 1);
removeFirst: list.removeIf(x -> x == 0);
removeNone:  list.removeIf(x -> false);


, ArrayList.removeIf() Java 8 1000 :





, removeAll removeHalf removeFirst. , ArrayList . , . . , , .



ArrayList subList, , :





. . removeAll 20 , removeHalf — 6 . removeLast removeFirst subList .



«» ? Java 8 subList(0, size).removeIf() , default- . , , .



Java 9:





subList , , Java 9 subList . , . : removeLast removeNone. , subList removeFirst Java 8. .



removeIf() Java 8 :



public boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    // figure out which elements are to be removed
    // any exception thrown from the filter predicate at this stage
    // will leave the collection unmodified
    int removeCount = 0;
    final BitSet removeSet = new BitSet(size);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        @SuppressWarnings("unchecked")
        final E element = (E) elementData[i];
        if (filter.test(element)) {
            removeSet.set(i);
            removeCount++;
        }
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    // shift surviving elements left over the spaces
    // left by removed elements
    final boolean anyToRemove = removeCount > 0;
    if (anyToRemove) {
        final int newSize = size - removeCount;
        for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
            i = removeSet.nextClearBit(i);
            elementData[j] = elementData[i];
        }
        for (int k=newSize; k < size; k++) {
            elementData[k] = null; // Let gc do its work
        }    
        this.size = newSize;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}


, BitSet, , . , BitSet, ArrayList . , ArrayList . . . default-, .



BitSet . , GC .



, removeLast . BitSet :



for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
    i = removeSet.nextClearBit(i);
    elementData[j] = elementData[i];
}


, , , . .



removeAll , newSize 0. , .



for (int k=newSize; k < size; k++) {
    elementData[k] = null; // Let gc do its work
}


Java 9? -, , , . subList.



boolean removeIf(Predicate<? super E> filter, int i, final int end) {
    Objects.requireNonNull(filter);
    int expectedModCount = modCount;
    final Object[] es = elementData;
    // Optimize for initial run of survivors
    for (; i < end && !filter.test(elementAt(es, i)); i++)
        ;
    // Tolerate predicates that reentrantly access the collection for
    // read (but writers still get CME), so traverse once to find
    // elements to delete, a second pass to physically expunge.
    if (i < end) {
    } else {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        return false;
    }
}


, i , .



, — , false. , , , .



, - :



if (i < end) {
    final int beg = i;
    final long[] deathRow = nBits(end - beg); // new long[((n - 1) >> 6) + 1];
    deathRow[0] = 1L; // set bit 0
    for (i = beg + 1; i < end; i++)
        if (filter.test(elementAt(es, i)))
            setBit(deathRow, i - beg); // bits[i >> 6] |= 1L << i;
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    modCount++;
    int w = beg;
    for (i = beg; i < end; i++)
        if (isClear(deathRow, i - beg)) // (bits[i >> 6] & (1L << i)) == 0;
            es[w++] = es[i];
    shiftTailOverGap(es, w, end);
    return true;
} else { … }


, BitSet « ». nBits(), setBit() isClear long . , , .



BitSet , . removeLast , .



, . , , BitSet , . .



Java 9. Java 9 , . , . .



hashSet.removeIf()



ArrayList, HashSet. - . HashSet : [], [0], [0, 1] . .:



HashSet<List<Integer>> set;

@Setup
public void setup() {
    set = IntStream.range(0, 1000)
        .mapToObj(i -> IntStream.range(0, i).boxed().collect(Collectors.toList()))
        .collect(Collectors.toCollection(HashSet::new));
}


, HashSet . :



@Benchmark
public Set<List<Integer>> removeHalf() {
    Set<List<Integer>> copy = new HashSet<>(set);
    copy.removeIf(list -> list.size() > 500);
    return copy;
}
@Benchmark
public Set<List<Integer>> noRemove() {
    return new HashSet<>(set);
}


, . Java 8:





, + , . , , .





Java 9 , 10 % . ? , HashSet.removeIf() ? . Collection.removeIf(), HashSet.iterator().remove(). HashSet.iterator().remove() HashMap.keySet().iterator().remove(). , HashSet HashMap default-, set. HashMap.KeyIterator.remove(), remove(). , HashMap : keySet().iterator(), valueSet().iterator(), entrySet().iterator(), , .





HashIterator. , ? :





removeNode(), , . Java 9 , , .



, . , . - , , .



, , . , , HashMap LinkedHashMap, .



HashMap.containsKey



Java 15 Map. :



HashMap<List<Integer>, String> emptyMap;
HashMap<List<Integer>, String> nonEmptyMap;
List<Integer> key;

@Setup
public void setup() {
    emptyMap = new HashMap<>();
    nonEmptyMap = new HashMap<>();
    nonEmptyMap.put(Collections.emptyList(), "");
    key = IntStream.range(0, 500).boxed().collect(Collectors.toList());
}

@Benchmark
public boolean containsInEmpty() {
    return emptyMap.containsKey(key);
}

@Benchmark
public boolean containsInNonEmpty() {
    return nonEmptyMap.containsKey(key);
}


HashMap. , . -, , 500 . :





Java 14 500 , , Java 15 3 . , -, .



, . HashMap getNode(), - . Java 15 , , .



final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
    }
    return null;
}


Java 15 - getNode(). , - , . - , .



final Node<K,V> getNode(Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & (hash = hash(key))]) != null) {
    }
    return null;
}


, containsKey(), get() getOrDefault(). .



computeIfPresent() . null, . .



. , map computeIfPresent().





, computeIfPresent() , getNode(), , , . - computeIfPresent() , null .



Class.getSimpleName()



Reflection. , , . : class.getName(), class.getCanonicalName(), class.getSimpleName(). Class.getName() , , JVM-. Class.getCanonicalName() , , Java-. Class.getSimpleName() . , :





Java 8 getName() , , . getCanonicalName() getSimpleName() , , . , .



Java 11 , . getCanonicalName() getSimpleName() 1,3 , getName(). , .



public String getName() {
    String name = this.name;
    if (name == null)
        this.name = name = getName0();
    return name;
}

// cache the name to reduce the number of calls into the VM
private transient String name;
private native String getName0();


getName() . getName(), .



public String getCanonicalName() {
    if (isArray()) {
        String canonicalName = getComponentType().getCanonicalName();
        if (canonicalName != null)
            return canonicalName + "[]";
        else
            return null;
    }
    if (isLocalOrAnonymousClass())
        return null;
    Class<?> enclosingClass = getEnclosingClass();
    if (enclosingClass == null) { // top level class
        return getName();
    } else {
        String enclosingName = enclosingClass.getCanonicalName();
        if (enclosingName == null)
            return null;
        return enclosingName + "." + getSimpleName();
    }
}


getCanonicalName() Java 10, , , . getSimpleName() . , Java 8 , Java. , , java.lang.Class, «» .



Java 8 32- JVM 112 , SoftReference reflection. reflection, , . Java 8 ReflectionData SoftReference. 32- JVM 32 , Reflection , 224 , 8 Reflection.



. - getSimpleName() getCanonicalName() . - , . ReflectionData. ReflectionData .



// reflection data that might get invalidated
// when JVM TI RedefineClasses() is called
private static class ReflectionData<T> {
    volatile Field[] declaredFields;
    volatile Field[] publicFields;
    volatile Method[] declaredMethods;
    volatile Method[] publicMethods;
    volatile Constructor<T>[] declaredConstructors;
    volatile Constructor<T>[] publicConstructors;
    // Intermediate results for getFields and getMethods
    volatile Field[] declaredPublicFields;
    volatile Method[] declaredPublicMethods;
    volatile Class<?>[] interfaces;

    // Value of classRedefinedCount when we created this ReflectionData instance
    final int redefinedCount;

    ReflectionData(int redefinedCount) {
        this.redefinedCount = redefinedCount;
    }
}


. , JVMTI-, ReflectionData , ReflectionData.



private transient volatile SoftReference<ReflectionData<T>> reflectionData;

// Incremented by the VM on each call to JVM TI RedefineClasses()
// that redefines this class or a superclass.
private transient volatile int classRedefinedCount;

// Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() {
    SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
    int classRedefinedCount = this.classRedefinedCount;
    ReflectionData<T> rd;
    if (reflectionData != null &&
        (rd = reflectionData.get()) != null &&
        rd.redefinedCount == classRedefinedCount) {
        return rd;
    }
    // else no SoftReference or cleared SoftReference or stale ReflectionData
    // -> create and replace new instance
    return newReflectionData(reflectionData, classRedefinedCount);
}


-, SoftReference, . -, redefinedCount, . , int, .



, ReflectionData GC , classRedefinedCount .



private ReflectionData<T> newReflectionData(
                              SoftReference<ReflectionData<T>> oldReflectionData,
                                            int classRedefinedCount) {
    while (true) {
        ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
        // try to CAS it...
        if (Atomic.casReflectionData(
                        this, oldReflectionData, new SoftReference<>(rd))) {
            return rd;
        }
        // else retry
        oldReflectionData = this.reflectionData;
        classRedefinedCount = this.classRedefinedCount;
        if (oldReflectionData != null &&
            (rd = oldReflectionData.get()) != null &&
            rd.redefinedCount == classRedefinedCount) {
            return rd;
        }
    }
}


CAS-, , .



Java 11 ReflectionData :



private static class ReflectionData<T> {
    volatile Field[] declaredFields;
    volatile Class<?>[] interfaces;

+   // Cached names
+   String simpleName;
+   String canonicalName;
+   static final String NULL_SENTINEL = new String();

}


(, ), , ( - ). .



public String getCanonicalName() {
    ReflectionData<T> rd = reflectionData();
    String canonicalName = rd.canonicalName;
    if (canonicalName == null) {
        rd.canonicalName = canonicalName = getCanonicalName0();
    }
    return canonicalName == ReflectionData.NULL_SENTINEL ?
                            null : canonicalName;
}


Java 11 getCanonicalName() . getSimpleName(). , ReflectionData, , 1,3 .



Class.getConstructor



getConstructor(). :



public static class X {
  public X() {}
}

public static class X1 {
  public X1() {}
  public X1(int p1) {}
  public X1(int p1, int p2) {}
  public X1(int p1, int p2, int p3) {}
  public X1(int p1, int p2, int p3, int p4) {}
  public X1(int p1, int p2, int p3, int p4, int p5) {}
}

public static class X2 {
  public X2() {}
  public X2(int p1) {}
  public X2(int p1, int p2) {}
  public X2(int p1, int p2, int p3) {}
  public X2(int p1, int p2, int p3, int p4) {}
  public X2(int p1, int p2, int p3, int p4, int p5) {}
  public X2(int p1, int p2, int p3, int p4, int p5, int p6) {}
  public X2(int p1, int p2, int p3, int p4, int p5, int p6, int p7) {}
  public X2(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) {}
  public X2(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9) {}
  public X2(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10) {}
}


, :



@Benchmark
public Constructor<?> getConstructorX() throws NoSuchMethodException {
  return X.class.getConstructor();
}

@Benchmark
public Constructor<?> getConstructorX1() throws NoSuchMethodException {
  return X1.class.getConstructor();
}

@Benchmark
public Constructor<?> getConstructorX2() throws NoSuchMethodException {
  return X2.class.getConstructor();
}


Java 8, , :





90 , JDK Java 9:





, . , . , :





. Java 8 , Java 9 . ?



getConstructor() getConstructor(), Java 8 :



private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException
{
    Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
    for (Constructor<T> constructor : constructors) {
        if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) {
            return getReflectionFactory().copyConstructor(constructor);
        }
    }
    throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}


. ReflectionData privateGetDeclaredConstructors(). find-first , . , reflection , , . , , , .



getParameterTypes(): . , ( Reflection API , , ).



, Constructor , :



public final class Constructor<T> extends Executable {

    @Override
    public Class<?>[] getParameterTypes() {
        return parameterTypes.clone();
    } 

}


, , , , . . Class java.lang, Constructor java.lang.reflect, . , « », . Java 9 getConstructor0():



private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException
{
    ReflectionFactory fact = getReflectionFactory();
    Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
    for (Constructor<T> constructor : constructors) {
        if (arrayContentsEq(parameterTypes, fact.getExecutableSharedParameterTypes(constructor))) {
            return constructor;
        }
    }
    throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
}


« » ReflectionFactory:



package jdk.internal.reflect;

public class ReflectionFactory {
    private final JavaLangReflectAccess langReflectAccess;
    private ReflectionFactory() {
        this.langReflectAccess = SharedSecrets.getJavaLangReflectAccess();
    }

    public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
        return langReflectAccess.getExecutableSharedParameterTypes(ex);
    }
}


, «». «» JavaLangReflect, java.base. jdk.internal , .



SharedSecrets, , jdk.internal.access , «» JDK, JavaLangReflect:



package jdk.internal.access;

public class SharedSecrets {
    private static JavaLangReflectAccess javaLangReflectAccess;

    public static void setJavaLangReflectAccess(JavaLangReflectAccess jlra) {
        javaLangReflectAccess = jlra;
    }

    public static JavaLangReflectAccess getJavaLangReflectAccess() {
        return javaLangReflectAccess;
    } 

}


JavaLangReflectAccess — , :



package jdk.internal.access;

/** An interface which gives privileged packages Java-level access to
internals of java.lang.reflect. */

public interface JavaLangReflectAccess {
    /** Gets the shared array of parameter types of an Executable. */
public Class<?>[] getExecutableSharedParameterTypes(Executable ex);

}


AccessibleObject:



package java.lang.reflect;

public class AccessibleObject implements AnnotatedElement {
    static {
        // AccessibleObject is initialized early in initPhase1
        SharedSecrets.setJavaLangReflectAccess(new ReflectAccess());
    }
}


AccessibleObject JVM, .



— java.lang.reflect, :



package java.lang.reflect;

/** Package-private class implementing the
    jdk.internal.access.JavaLangReflectAccess interface, allowing the java.lang
    package to instantiate objects in this package. */

class ReflectAccess implements jdk.internal.access.JavaLangReflectAccess {

    public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
        return ex.getSharedParameterTypes();
    }

}


, — :





:





, . , , Java .





9 , Java 9-16, , JDK, . , Java 8 , . !



— . , Joker 2020 , -. , .

— Java Champion -1 Java, JVM, concurrency, file-io memory Stack Overflow. Java-, , .



All Articles