--- old/src/java.base/share/classes/java/lang/Class.java 2020-04-15 11:02:22.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/Class.java 2020-04-15 11:02:22.000000000 -0700 @@ -163,10 +163,18 @@ * * The {@linkplain #getName() name of a hidden class or interface} is * not a binary name, - * which means that a hidden class or interface cannot be - * referenced by the constant pools of other classes and interfaces, - * and cannot be discovered by {@link #forName Class::forName} or - * {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass}. + * which means the following: + * * * A hidden class or interface is never an array class, but may be * the element type of an array. In all other respects, the fact that @@ -1065,10 +1073,7 @@ public String getPackageName() { String pn = this.packageName; if (pn == null) { - Class c = this; - while (c.isArray()) { - c = c.getComponentType(); - } + Class c = isArray() ? elementType() : this; if (c.isPrimitive()) { pn = "java.lang"; } else { @@ -1226,6 +1231,20 @@ private final Class componentType; + /* + * Returns the {@code Class} representing the element type of an array class. + * If this class does not represent an array class, then this method returns + * {@code null}. + */ + private Class elementType() { + if (!isArray()) return null; + + Class c = this; + while (c.isArray()) { + c = c.getComponentType(); + } + return c; + } /** * Returns the Java language modifiers for this class or interface, encoded @@ -3023,10 +3042,7 @@ */ private String resolveName(String name) { if (!name.startsWith("/")) { - Class c = this; - while (c.isArray()) { - c = c.getComponentType(); - } + Class c = isArray() ? elementType() : this; String baseName = c.getPackageName(); if (baseName != null && !baseName.isEmpty()) { name = baseName.replace('.', '/') + "/" + name; @@ -4241,13 +4257,57 @@ } /** - * Returns the type descriptor string for this class. - *

- * Note that this is not a strict inverse of {@link #forName}; + * Returns the descriptor string of the entity (class, interface, array class, + * primitive type, or {@code void}) represented by this {@code Class} object. + * + *

If this {@code Class} object represents a class or interface, + * not an array class, then: + *

+ * + *

If this {@code Class} object represents an array class, then + * the result is a string consisting of one or more '{@code [}' characters + * representing the depth of the array nesting, followed by the + * descriptor string of the element type. + *

+ * + *

If this {@code Class} object represents a primitive type or + * {@code void}, then the result is a field descriptor string which + * is a one-letter code corresponding to a primitive type or {@code void} + * ({@code "B", "C", "D", "F", "I", "J", "S", "Z", "V"}) (JVMS {@jvms 4.3.2}). + * + * @apiNote + * This is not a strict inverse of {@link #forName}; * distinct classes which share a common name but have different class loaders * will have identical descriptor strings. * - * @return the type descriptor representation + * @return the descriptor string for this {@code Class} object * @jvms 4.3.2 Field Descriptors * @since 12 */ @@ -4255,10 +4315,15 @@ public String descriptorString() { if (isPrimitive()) return Wrapper.forPrimitiveType(this).basicTypeString(); - else if (isArray()) { + + if (isArray()) { return "[" + componentType.descriptorString(); - } - else { + } else if (isHidden()) { + String name = getName(); + int index = name.indexOf('/'); + return "L" + name.substring(0, index).replace('.', '/') + + "." + name.substring(index+1) + ";"; + } else { return "L" + getName().replace('.', '/') + ";"; } } @@ -4301,7 +4366,9 @@ */ @Override public Optional describeConstable() { - return Optional.of(ClassDesc.ofDescriptor(descriptorString())); + Class c = isArray() ? elementType() : this; + return c.isHidden() ? Optional.empty() + : Optional.of(ClassDesc.ofDescriptor(descriptorString())); } /**