< prev index next >
src/java.base/share/classes/java/lang/Class.java
Print this page
rev 55127 : 8223351: [lworld] Primary mirror and nullable mirror for inline type
Reviewed-by: tbd
*** 60,71 ****
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
- import java.util.StringJoiner;
- import java.util.stream.Stream;
import java.util.stream.Collectors;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
--- 60,69 ----
*** 195,207 ****
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this class object.
*/
public String toString() {
! return (isValue() ? "inline " : "")
+ (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
! + getName() + (isValue() && isBoxType() ? "?" : "");
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
--- 193,205 ----
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this class object.
*/
public String toString() {
! return (isInlineClass() ? "inline " : "")
+ (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
! + getName() + (isInlineClass() && isNullableType() ? "?" : "");
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
*** 258,268 ****
}
if (isAnnotation()) {
sb.append('@');
}
! if (isValue()) {
sb.append("value");
sb.append(' ');
}
if (isInterface()) { // Note: all annotation types are interfaces
sb.append("interface");
--- 256,266 ----
}
if (isAnnotation()) {
sb.append('@');
}
! if (isInlineClass()) {
sb.append("value");
sb.append(' ');
}
if (isInterface()) { // Note: all annotation types are interfaces
sb.append("interface");
*** 360,373 ****
* 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>
--- 358,367 ----
*** 444,457 ****
*
* <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
--- 438,447 ----
*** 510,524 ****
}
}
/**
! * Returns {@code true} if this class is a value class.
*
! * @return {@code true} if this class is a value class.
*/
! public boolean isValue() {
int mods = this.getModifiers();
if ((mods & VALUE_TYPE) != 0) {
if ((mods & (Modifier.INTERFACE | Modifier.ABSTRACT)) != 0) {
throw new InternalError("inline class can't have ACC_INTERFACE or ACC_ABSTRACT set");
}
--- 500,514 ----
}
}
/**
! * Returns {@code true} if this class is an inline class.
*
! * @return {@code true} if this class is an inline class.
*/
! public boolean isInlineClass() {
int mods = this.getModifiers();
if ((mods & VALUE_TYPE) != 0) {
if ((mods & (Modifier.INTERFACE | Modifier.ABSTRACT)) != 0) {
throw new InternalError("inline class can't have ACC_INTERFACE or ACC_ABSTRACT set");
}
*** 529,583 ****
}
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.
*/
@HotSpotIntrinsicCandidate
! public Class<T> 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}.
*/
@HotSpotIntrinsicCandidate
! public Class<T> 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<T> boxType;
! private transient Class<T> 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
--- 519,578 ----
}
return false;
}
/**
! * Returns a {@code Class} object representing the <em>nullable-projection</em>
! * type if this class is an {@linkplain #isInlineClass() inline class};
* otherwise, returns this class.
*
! * <p> An inline class has two {@code Class} representations,
! * the zero-default inline class and the nullable-projection type
! * that can be obtained by calling {@link #asPrimaryType()} or
! * {@link #asNullableType()} method respectively.
*
! * @return the {@code Class} object representing the nullable-projection of
! * this class if this class is an inline class; otherwise, this class.
*/
@HotSpotIntrinsicCandidate
! public Class<T> asNullableType() {
! return isInlineClass() ? nullableType : this;
}
/**
! * Returns a {@code Class} object representing this <em>zero-default</em>
! * inline class if this class is an {@linkplain #isInlineClass() inline class};
! * otherwise, returns this class.
*
! * <p> An inline class has two {@code Class} representations,
! * the zero-default inline class and the nullable-projection type
! * that can be obtained by calling {@link #asPrimaryType()} or
! * {@link #asNullableType()} method respectively.
*
! * @return the {@code Class} object representing the zero-default inline class
! * if this class is an inline class; otherwise, this class.
*/
@HotSpotIntrinsicCandidate
! public Class<T> asPrimaryType() {
! return isInlineClass() ? inlineType : this;
}
! /**
! * Returns {@code true} if this class is a nullable type. A nullable type
! * can be a reference class or interface and
! * a {@linkplain #asNullableType nullable-projection type}.
! *
! * @return {@code true} if this class is a nullable type.
*/
! public boolean isNullableType() {
! return nullableType == null || this == nullableType;
}
! // set by VM if this class is an inline type
! // otherwise, these two fields are null
! private transient Class<T> inlineType;
! private transient Class<T> nullableType;
/**
* 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
*** 633,643 ****
@CallerSensitive
@Deprecated(since="9")
public T newInstance()
throws InstantiationException, IllegalAccessException
{
! if (this.isValue()) {
throw new IllegalAccessException(
"cannot create new instance of an inline class " + this.getName());
}
SecurityManager sm = System.getSecurityManager();
--- 628,638 ----
@CallerSensitive
@Deprecated(since="9")
public T newInstance()
throws InstantiationException, IllegalAccessException
{
! if (this.isInlineClass()) {
throw new IllegalAccessException(
"cannot create new instance of an inline class " + this.getName());
}
SecurityManager sm = System.getSecurityManager();
*** 853,863 ****
* <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
--- 848,858 ----
* <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 #asPrimaryType() inline 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
*** 873,887 ****
* 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
--- 868,884 ----
* String.class.getName()
* returns "java.lang.String"
* byte.class.getName()
* returns "byte"
* Point.class.getName()
! * returns "Point"
* (new Object[3]).getClass().getName()
* returns "[Ljava.lang.Object;"
* (new Point[3]).getClass().getName()
* returns "[QPoint;"
+ * (new Point?[3][4]).getClass().getName()
+ * returns "[[LPoint;"
* (new int[3][4][5][6][7][8][9]).getClass().getName()
* returns "[[[[[[[I"
* </pre></blockquote>
*
* @return the name of the class or interface
*** 1296,1316 ****
* 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);
--- 1293,1313 ----
* particular, this method returns null if this object represents
* a primitive type or void.
* @since 1.1
*/
public Object[] getSigners() {
! Class<?> c = isInlineClass() && isNullableType() ? asPrimaryType() : this;
return c.getSigners0();
}
private native Object[] getSigners0();
/**
* Set the signers of this class.
*/
void setSigners(Object[] signers) {
! Class<?> c = isInlineClass() && isNullableType() ? asPrimaryType() : this;
c.setSigners0(signers);
}
native void setSigners0(Object[] signers);
*** 1648,1660 ****
*
* <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();
--- 1645,1654 ----
*** 1672,1682 ****
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.
*
--- 1666,1676 ----
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.
*
*** 1698,1709 ****
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
--- 1692,1702 ----
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
! return toTypeName();
}
/**
* Returns the canonical name of the underlying class as
* defined by the Java Language Specification. Returns null if
*** 3524,3540 ****
private String methodToString(String name, Class<?>[] argTypes) {
StringBuilder sb = new StringBuilder();
sb.append(getName() + "." + name + "(");
if (argTypes != null) {
sb.append(Arrays.stream(argTypes)
! .map(c -> (c == null) ? "null" : c.getName())
.collect(Collectors.joining(",")));
}
sb.append(")");
return sb.toString();
}
/** use serialVersionUID from JDK 1.1 for interoperability */
private static final long serialVersionUID = 3206093459760846163L;
/**
--- 3517,3541 ----
private String methodToString(String name, Class<?>[] argTypes) {
StringBuilder sb = new StringBuilder();
sb.append(getName() + "." + name + "(");
if (argTypes != null) {
sb.append(Arrays.stream(argTypes)
! .map(c -> (c == null) ? "null" : c.toTypeName())
.collect(Collectors.joining(",")));
}
sb.append(")");
return sb.toString();
}
+ /*
+ * Returns the class name appended with "?" if it is the nullable projection
+ * of an inline class.
+ */
+ private String toTypeName() {
+ return isInlineClass() && isNullableType() ? getName() + "?" : getName();
+ }
+
/** use serialVersionUID from JDK 1.1 for interoperability */
private static final long serialVersionUID = 3206093459760846163L;
/**
*** 3705,3724 ****
* @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;
}
--- 3706,3725 ----
* @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 an {@linkplain #asPrimaryType()
! * inline class} and the object is {@code null}
*
* @since 1.5
*/
@SuppressWarnings("unchecked")
@HotSpotIntrinsicCandidate
public T cast(Object obj) {
! if (isInlineClass() && !isNullableType() && obj == null)
! throw new NullPointerException(getName() + " is an inline class");
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
< prev index next >