< prev index next >
src/java.base/share/classes/java/lang/Class.java
Print this page
*** 56,66 ****
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
- import java.util.Set;
import java.util.StringJoiner;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
--- 56,65 ----
*** 187,197 ****
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this class object.
*/
public String toString() {
! return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
/**
* Returns a string describing this {@code Class}, including
--- 186,197 ----
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this class object.
*/
public String toString() {
! return (isValue() ? "value " : "")
! + (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
/**
* Returns a string describing this {@code Class}, including
*** 248,257 ****
--- 248,261 ----
}
if (isAnnotation()) {
sb.append('@');
}
+ if (isValue()) {
+ sb.append("value");
+ sb.append(' ');
+ }
if (isInterface()) { // Note: all annotation types are interfaces
sb.append("interface");
} else {
if (isEnum())
sb.append("enum");
*** 336,345 ****
--- 340,353 ----
* types or void.
*
* <p> If {@code name} denotes an array class, the component type of
* the array class is loaded but not initialized.
*
+ * <p> If {@code name} denotes a value class, this method returns
+ * the {@code Class} object representing the
+ * {@linkplain #asBoxType() box value type}.
+ *
* <p> For example, in an instance method the expression:
*
* <blockquote>
* {@code Class.forName("Foo")}
* </blockquote>
*** 416,425 ****
--- 424,437 ----
*
* <p> If the class loader of the given module defines other modules and
* the given name is a class defined in a different module, this method
* returns {@code null} after the class is loaded. </p>
*
+ * <p> If {@code name} denotes a value class, this method returns
+ * the {@code Class} object representing the
+ * {@linkplain #asBoxType() box value type}. </p>
+ *
* <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
*** 497,506 ****
--- 509,563 ----
}
return false;
}
/**
+ * Returns a {@code Class} object representing the <em>box type</em>
+ * of this class if this class is a {@linkplain #isValue() value class};
+ * otherwise, returns this class.
+ *
+ * <p> A value class has two {@code Class} representations,
+ * a null-free type or a nullable box type, that can be obtained
+ * by calling {@link #asValueType()} or {@link #asBoxType()} method
+ * for conversion.
+ *
+ * @return the box type of this class if this class is a value class;
+ * otherwise, this class.
+ */
+ public Class<?> asBoxType() {
+ return isValue() ? boxType : this;
+ }
+
+ /**
+ * Returns a {@code Class} object representing the <em>null-free value type</em>
+ * of this class if this class is a {@linkplain #isValue() value class};
+ * otherwise, returns {@code null}.
+ *
+ * <p> A value class has two {@code Class} representations,
+ * a null-free type or a nullable box type, that can be obtained
+ * by calling {@link #asValueType()} or {@link #asBoxType()} method
+ * for conversion.
+ *
+ * @return the unbox value type of this class if this class is a value class;
+ * otherwise, {@code null}.
+ */
+ public Class<?> asValueType() {
+ return isValue() ? valueType : null;
+ }
+
+ /*
+ * Returns true if this class is a non-value class or a box value class.
+ */
+ boolean isBoxType() {
+ return boxType == null || this == boxType;
+ }
+
+ // set by VM if this class is a value type
+ private transient Class<?> boxType;
+ private transient Class<?> valueType;
+
+ /**
* Creates a new instance of the class represented by this {@code Class}
* object. The class is instantiated as if by a {@code new}
* expression with an empty argument list. The class is initialized if it
* has not already been initialized.
*
*** 786,795 ****
--- 843,854 ----
* <tr><th scope="row"> boolean <td style="text-align:center"> Z
* <tr><th scope="row"> byte <td style="text-align:center"> B
* <tr><th scope="row"> char <td style="text-align:center"> C
* <tr><th scope="row"> class or interface
* <td style="text-align:center"> L<i>classname</i>;
+ * <tr><th scope="row"> {@linkplain #asValueType() regular value class}
+ * <td style="text-align:center"> Q<i>classname</i>;
* <tr><th scope="row"> double <td style="text-align:center"> D
* <tr><th scope="row"> float <td style="text-align:center"> F
* <tr><th scope="row"> int <td style="text-align:center"> I
* <tr><th scope="row"> long <td style="text-align:center"> J
* <tr><th scope="row"> short <td style="text-align:center"> S
*** 803,825 ****
* <blockquote><pre>
* String.class.getName()
* returns "java.lang.String"
* 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()
* returns "[[[[[[[I"
* </pre></blockquote>
*
* @return the name of the class or interface
* represented by this object.
*/
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;
--- 862,889 ----
* <blockquote><pre>
* String.class.getName()
* returns "java.lang.String"
* byte.class.getName()
* returns "byte"
+ * Point.class.getName()
+ * returns "p.Point"
* (new Object[3]).getClass().getName()
* returns "[Ljava.lang.Object;"
+ * (new Point[3]).getClass().getName()
+ * returns "[QPoint;"
* (new int[3][4][5][6][7][8][9]).getClass().getName()
* returns "[[[[[[[I"
* </pre></blockquote>
*
* @return the name of the class or interface
* represented by this object.
*/
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;
*** 1215,1240 ****
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native int getModifiers();
-
/**
* Gets the signers of this class.
*
* @return the signers of this class, or null if there are no signers. In
* particular, this method returns null if this object represents
* a primitive type or void.
* @since 1.1
*/
! public native Object[] getSigners();
/**
* Set the signers of this class.
*/
! native void setSigners(Object[] signers);
/**
* If this {@code Class} object represents a local or anonymous
* class within a method, returns a {@link
--- 1279,1312 ----
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native int getModifiers();
/**
* Gets the signers of this class.
*
* @return the signers of this class, or null if there are no signers. In
* particular, this method returns null if this object represents
* a primitive type or void.
* @since 1.1
*/
! public Object[] getSigners() {
! Class<?> c = (isValue() && !isBoxType()) ? asBoxType() : this;
! return c.getSigners0();
! }
+ private native Object[] getSigners0();
/**
* Set the signers of this class.
*/
! void setSigners(Object[] signers) {
! Class<?> c = (isValue() && !isBoxType()) ? asBoxType() : this;
! c.setSigners0(signers);
! }
!
! native void setSigners0(Object[] signers);
/**
* If this {@code Class} object represents a local or anonymous
* class within a method, returns a {@link
*** 1568,1577 ****
--- 1640,1652 ----
*
* <p>The simple name of an array is the simple name of the
* component type with "[]" appended. In particular the simple
* name of an array whose component type is anonymous is "[]".
*
+ * <p>The simple name of a value type is the simple name of
+ * this class with {@code ".box"} appended.
+ *
* @return the simple name of the underlying class
* @since 1.5
*/
public String getSimpleName() {
ReflectionData<T> rd = reflectionData();
*** 1589,1599 ****
String simpleName = getSimpleBinaryName();
if (simpleName == null) { // top level class
simpleName = getName();
simpleName = simpleName.substring(simpleName.lastIndexOf('.') + 1); // strip the package name
}
! return simpleName;
}
/**
* Return an informative string for the name of this type.
*
--- 1664,1674 ----
String simpleName = getSimpleBinaryName();
if (simpleName == null) { // top level class
simpleName = getName();
simpleName = simpleName.substring(simpleName.lastIndexOf('.') + 1); // strip the package name
}
! return isValue() && isBoxType() ? simpleName + ".box" : simpleName;
}
/**
* Return an informative string for the name of this type.
*
*** 1608,1625 ****
do {
dimensions++;
cl = cl.getComponentType();
} while (cl.isArray());
StringBuilder sb = new StringBuilder();
! sb.append(cl.getName());
for (int i = 0; i < dimensions; i++) {
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
! return getName();
}
/**
* Returns the canonical name of the underlying class as
* defined by the Java Language Specification. Returns null if
--- 1683,1701 ----
do {
dimensions++;
cl = cl.getComponentType();
} while (cl.isArray());
StringBuilder sb = new StringBuilder();
! sb.append(cl.getTypeName());
for (int i = 0; i < dimensions; i++) {
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
! // ## append "/box" to box value type instead?
! return isBoxType() ? getName() : getName() + "/val";
}
/**
* Returns the canonical name of the underlying class as
* defined by the Java Language Specification. Returns null if
*** 3619,3635 ****
*
* @param obj the object to be cast
* @return the object after casting, or null if obj is null
*
* @throws ClassCastException if the object is not
! * null and is not assignable to the type T.
*
* @since 1.5
*/
@SuppressWarnings("unchecked")
@HotSpotIntrinsicCandidate
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
--- 3695,3716 ----
*
* @param obj the object to be cast
* @return the object after casting, or null if obj is null
*
* @throws ClassCastException if the object is not
! * {@code null} and is not assignable to the type T.
! * @throws NullPointerException if this class is a {@linkplain #asValueType()
! * null-free value class} and the object is {@code null}
*
* @since 1.5
*/
@SuppressWarnings("unchecked")
@HotSpotIntrinsicCandidate
public T cast(Object obj) {
+ if (isValue() && !isBoxType() && obj == null)
+ throw new NullPointerException(getName() + " is non-nullable value class");
+
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
< prev index next >