< prev index next >
src/java.base/share/classes/java/lang/Class.java
Print this page
@@ -161,14 +161,22 @@
* hidden classes; all kinds of interface, including annotation types,
* may be hidden interfaces.
*
* The {@linkplain #getName() name of a hidden class or interface} is
* not a <a href="ClassLoader.html#binary-name">binary name</a>,
- * 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:
+ * <ul>
+ * <li>A hidden class or interface cannot be referenced by the constant pools
+ * of other classes and interfaces.
+ * <li>A hidden class or interface cannot be described in
+ * {@linkplain java.lang.constant.ConstantDesc <em>nominal form</em>} by
+ * {@link #describeConstable() Class::describeConstable},
+ * {@link ClassDesc#of(String) ClassDesc::of}, or
+ * {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}.
+ * <li>A hidden class or interface cannot be discovered by {@link #forName Class::forName}
+ * or {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass}.
+ * </ul>
*
* 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
* a class or interface is hidden has no bearing on the characteristics
* exposed by the methods of class {@code Class}.
@@ -1063,14 +1071,11 @@
* @jls 6.7 Fully Qualified Names
*/
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 {
String cn = c.getName();
int dot = cn.lastIndexOf('.');
@@ -1224,10 +1229,24 @@
}
}
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
* in an integer. The modifiers consist of the Java Virtual Machine's
* constants for {@code public}, {@code protected},
@@ -3021,14 +3040,11 @@
* Add a package name prefix if the name is not absolute Remove leading "/"
* if name is absolute
*/
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;
}
} else {
@@ -4212,28 +4228,72 @@
}
return members;
}
/**
- * Returns the type descriptor string for this class.
- * <p>
- * 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.
+ *
+ * <p> If this {@code Class} object represents a class or interface,
+ * not an array class, then:
+ * <ul>
+ * <li> If the class or interface is not {@linkplain Class#isHidden() hidden},
+ * then the result is a field descriptor string (JVMS {@jvms 4.3.2})
+ * for the class or interface. A {@link ClassDesc ClassDesc}
+ * can be created from the result descriptor string via
+ * {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}.
+ * <li> If the class or interface is {@linkplain Class#isHidden() hidden},
+ * then the result is a string of the form: {@code "L" + N + "." + <suffix> + ";"}
+ * where {@code N} is the <a href="ClassLoader.html#binary-name">binary name</a>
+ * encoded in internal form indicated by the {@code class} file passed to
+ * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
+ * Lookup::defineHiddenClass}, and {@code <suffix>} is an unqualified name.
+ * A hidden class or interface has no {@linkplain ClassDesc nominal descriptor}.
+ * </ul>
+ *
+ * <p> 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.
+ * <ul>
+ * <li> If the element type is not a {@linkplain Class#isHidden() hidden} class
+ * or interface, then this array class can be described nominally and a
+ * {@link ClassDesc ClassDesc} can be created via
+ * {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}
+ * from the result field descriptor string.
+ * <li> If the element type is a {@linkplain Class#isHidden() hidden} class or
+ * interface, then this array class cannot be described nominally and
+ * no {@code ClassDesc} can be created from the result string.
+ * </ul>
+ *
+ * <p> 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
*/
@Override
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, name.length()) + ";";
+ } else {
return "L" + getName().replace('.', '/') + ";";
}
}
/**
@@ -4272,11 +4332,13 @@
* or an empty {@link Optional} if one cannot be constructed.
* @since 12
*/
@Override
public Optional<ClassDesc> describeConstable() {
- return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
+ Class<?> c = isArray() ? elementType() : this;
+ return c.isHidden() ? Optional.empty()
+ : Optional.of(ClassDesc.ofDescriptor(descriptorString()));
}
/**
* Returns {@code true} if and only if the underlying class is a hidden class.
*
< prev index next >