Summary
Clarify the specification of the name parameter of Class::forName
to match the implementation.
Problem
The 1-arg and 3-arg Class::forName
methods specify the name as a "fully qualified name"
that does not match the long standing implementation. For a (non-hidden) class or interface,
the name must be a binary name e.g. to find a nested type, the binary name is C$M
but not C.M
.
For an array class, the name consists of one or more [
, followed by:
LN;
whereN
is the binary name of the element type, or- the type descriptor of a primitive type
Solution
Update the specification of Class::forName
to match the long-standing behavior.
The name must be a binary name to find a class or interface. Specify the format of
the string to find an array class. Also add a note in the 2-arg Class::forName
as
it does not support loading of array types which is different than 1-arg and 3-arg Class::forName
.
Specification
- Update the
@param className
ofClass.forName(String name)
- Update the javadoc of
Class.forName(String name, boolean initialize, ClassLoader loader)
about the name parameter - Add an API note in the
Class.forName(Module m, String cn)
method that it does not allow class names for array types, unlike the 3-argClass.forName
- Add an example of nested type in
Class.getName
Specdiff is attached.
diff a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java
--- a/src/java.base/share/classes/java/lang/Class.java
+++ b/src/java.base/share/classes/java/lang/Class.java
@@ -375,11 +375,11 @@
*
* where {@code currentLoader} denotes the defining class loader of
* the current class.
*
* <p> For example, the following code fragment returns the
- * runtime {@code Class} descriptor for the class named
+ * runtime {@code Class} object for the class named
* {@code java.lang.Thread}:
*
* {@snippet lang="java" :
* Class<?> t = Class.forName("java.lang.Thread");
* }
@@ -390,13 +390,14 @@
* <p>
* In cases where this method is called from a context where there is no
* caller frame on the stack (e.g. when called directly from a JNI
* attached thread), the system class loader is used.
*
- * @param className the fully qualified name of the desired class.
- * @return the {@code Class} object for the class with the
- * specified name.
+ * @param className the {@linkplain ClassLoader##binary-name binary name}
+ * of the class or the string representing an array type
+ * @return the {@code Class} object for the class with the
+ * specified name.
* @throws LinkageError if the linkage fails
* @throws ExceptionInInitializerError if the initialization provoked
* by this method fails
* @throws ClassNotFoundException if the class cannot be located
*
/**
* Returns the {@code Class} object associated with the class or
* interface with the given string name, using the given class loader.
- * Given the fully qualified name for a class or interface (in the same
- * format returned by {@code getName}) this method attempts to
- * locate and load the class or interface. The specified class
- * loader is used to load the class or interface. If the parameter
- * {@code loader} is null, the class is loaded through the bootstrap
+ * Given the {@linkplain ClassLoader##binary-name binary name} for a class or interface,
+ * this method attempts to locate and load the class or interface. The specified
+ * class loader is used to load the class or interface. If the parameter
+ * {@code loader} is {@code null}, the class is loaded through the bootstrap
* class loader. The class is initialized only if the
* {@code initialize} parameter is {@code true} and if it has
* not been initialized earlier.
*
- * <p> If {@code name} denotes a primitive type or void, an attempt
- * will be made to locate a user-defined class in the unnamed package whose
- * name is {@code name}. Therefore, this method cannot be used to
- * obtain any of the {@code Class} objects representing primitive
- * types or void.
+ * <p> This method cannot be used to obtain any of the {@code Class} objects
+ * representing primitive types or void, hidden classes or interfaces,
+ * or array classes whose element type is a hidden class or interface.
+ * If {@code name} denotes a primitive type or void, for example {@code I},
+ * an attempt will be made to locate a user-defined class in the unnamed package
+ * whose name is {@code I} instead.
*
- * <p> If {@code name} denotes an array class, the component type of
- * the array class is loaded but not initialized.
- *
- * <p> For example, in an instance method the expression:
+ * <p> To obtain the {@code Class} object associated with an array class,
+ * the name consists of one or more {@code '['} representing the depth
+ * of the array nesting, followed by the element type as encoded in
+ * {@linkplain ##nameFormat the table} specified in {@code Class.getName()}.
*
+ * <p> Examples:
* {@snippet lang="java" :
- * Class.forName("Foo")
+ * Class<?> threadClass = Class.forName("java.lang.Thread", false, currentLoader);
+ * Class<?> stringArrayClass = Class.forName("[Ljava.lang.String;", false, currentLoader);
+ * Class<?> intArrayClass = Class.forName("[[[I", false, currentLoader);
+ * Class<?> nestedClass = Class.forName("java.lang.Character$UnicodeBlock", false, currentLoader); // Class of int[][][]
+ * Class<?> fooClass = Class.forName("Foo", true, currentLoader);
* }
*
- * is equivalent to:
+ * <p> A call to {@code getName()} on the {@code Class} object returned
+ * from {@code forName(}<i>N</i>{@code )} returns <i>N</i>.
*
- * {@snippet lang="java" :
- * Class.forName("Foo", true, this.getClass().getClassLoader())
- * }
+ * <p> A call to {@code forName("[L}<i>N</i>{@code ;")} causes the element type
+ * named <i>N</i> to be loaded but not initialized regardless of the value
+ * of the {@code initialize} parameter.
*
- * Note that this method throws errors related to loading, linking
- * or initializing as specified in Sections {@jls 12.2}, {@jls
- * 12.3}, and {@jls 12.4} of <cite>The Java Language
- * Specification</cite>.
- * Note that this method does not check whether the requested class
+ * @apiNote
+ * This method throws errors related to loading, linking or initializing
+ * as specified in Sections {@jls 12.2}, {@jls 12.3}, and {@jls 12.4} of
+ * <cite>The Java Language Specification</cite>.
+ * In addition, this method does not check whether the requested class
* is accessible to its caller.
*
- * @param name fully qualified name of the desired class
+ * @param name the {@linkplain ClassLoader##binary-name binary name}
+ * of the class or the string representing an array class
+ *
* @param initialize if {@code true} the class will be initialized
* (which implies linking). See Section {@jls
* 12.4} of <cite>The Java Language
* Specification</cite>.
* @param loader class loader from which the class must be loaded
@@ -484,10 +492,11 @@
* @see java.lang.ClassLoader
*
* @jls 12.2 Loading of Classes and Interfaces
* @jls 12.3 Linking of Classes and Interfaces
* @jls 12.4 Initialization of Classes and Interfaces
+ * @jls 13.1 The Form of a Binary
* @since 1.2
*/
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
*
* <p> This method does not check whether the requested class is
* accessible to its caller. </p>
*
* @apiNote
- * This method returns {@code null} on failure rather than
+ * This method does not support loading of array types, unlike
+ * {@link #forName(String, boolean, ClassLoader)}. The class name must be
+ * a binary name. This method returns {@code null} on failure rather than
* throwing a {@link ClassNotFoundException}, as is done by
* the {@link #forName(String, boolean, ClassLoader)} method.
* The security check is a stack-based permission check if the caller
* loads a class in another module.
*
@@ -886,11 +897,11 @@
* <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 element
* type as encoded using the following table:
*
- * <blockquote><table class="striped">
+ * <blockquote><table class="striped" id="nameFormat">
* <caption style="display:none">Element types and encodings</caption>
* <thead>
* <tr><th scope="col"> Element Type <th scope="col"> Encoding
* </thead>
* <tbody style="text-align:left">
@@ -913,10 +924,12 @@
*
* <p> Examples:
* <blockquote><pre>
* String.class.getName()
* returns "java.lang.String"
+ * Character.UnicodeBlock.class.getName()
+ * returns "java.lang.Character$UnicodeBlock"
* byte.class.getName()
* returns "byte"
* (new Object[3]).getClass().getName()
* returns "[Ljava.lang.Object;"
- (new int[3]
[4][5][6][7][8][9]).getClass().getName()
- csr of
-
JDK-8310242 Clarify the name parameter to Class::forName
- Resolved