< prev index next > src/java.base/share/classes/java/lang/Class.java
Print this page
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamField;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AnnotatedType;
+ import java.lang.reflect.AccessFlag;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
GenericDeclaration,
Type,
AnnotatedElement,
TypeDescriptor.OfField<Class<?>>,
Constable {
- private static final int ANNOTATION= 0x00002000;
- private static final int ENUM = 0x00004000;
- private static final int SYNTHETIC = 0x00001000;
+ private static final int ANNOTATION = 0x00002000;
+ private static final int ENUM = 0x00004000;
+ private static final int SYNTHETIC = 0x00001000;
+ private static final int VALUE_CLASS = 0x00000040;
+ private static final int PERMITS_VALUE = 0x00000100;
+ private static final int PRIMITIVE_CLASS = 0x00000800;
private static native void registerNatives();
static {
registerNatives();
}
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this {@code Class} object.
*/
public String toString() {
- String kind = isInterface() ? "interface " : isPrimitive() ? "" : "class ";
- return kind.concat(getName());
+ String s = isPrimitive() ? "" : "class ";
+ if (isInterface()) {
+ s = "interface ";
+ }
+ if (isValue()) {
+ s = "value ";
+ }
+ if (isPrimitiveClass()) {
+ s = "primitive ";
+ }
+ // Avoid invokedynamic based String concat, might be not available
+ s = s.concat(getName());
+ if (isPrimitiveClass() && isPrimaryType()) {
+ s = s.concat(".ref");
+ }
+ return s;
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
}
if (isAnnotation()) {
sb.append('@');
}
+ if (isValue()) {
+ sb.append(isPrimitiveClass() ? "primitive" : "value");
+ }
if (isInterface()) { // Note: all annotation interfaces are interfaces
sb.append("interface");
} else {
if (isEnum())
sb.append("enum");
return forName0(name, initialize, loader, caller);
}
/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
- ClassLoader loader,
- Class<?> caller)
+ ClassLoader loader,
+ Class<?> caller)
throws ClassNotFoundException;
/**
* Returns the {@code Class} with the given <a href="ClassLoader.html#binary-name">
} else {
return BootLoader.loadClass(module, name);
}
}
+ // set by VM if this class is an exotic type such as primitive class
+ // otherwise, these two fields are null
+ private transient Class<T> primaryType;
+ private transient Class<T> secondaryType;
+
+ /**
+ * Returns {@code true} if this class is a primitive class.
+ * <p>
+ * Each primitive class has a {@linkplain #isPrimaryType() primary type}
+ * representing the <em>primitive reference type</em> and a
+ * {@linkplain #isPrimitiveValueType() secondary type} representing
+ * the <em>primitive value type</em>. The primitive reference type
+ * and primitive value type can be obtained by calling the
+ * {@link #asPrimaryType()} and {@link #asValueType} method
+ * of a primitive class respectively.
+ * <p>
+ * A primitive class is a {@linkplain #isValue() value class}.
+ *
+ * @return {@code true} if this class is a primitive class, otherwise {@code false}
+ * @see #isValue()
+ * @see #asPrimaryType()
+ * @see #asValueType()
+ * @since Valhalla
+ */
+ public boolean isPrimitiveClass() {
+ return (this.getModifiers() & PRIMITIVE_CLASS) != 0;
+ }
+
+ /**
+ * Returns {@code true} if this class is a value class.
+ *
+ * @return {@code true} if this class is a value class;
+ * otherwise {@code false}
+ * @since Valhalla
+ */
+ public boolean isValue() {
+ return (this.getModifiers() & VALUE_CLASS) != 0;
+ }
+
+ /**
+ * Returns a {@code Class} object representing the primary type
+ * of this class or interface.
+ * <p>
+ * If this {@code Class} object represents a primitive type or an array type,
+ * then this method returns this class.
+ * <p>
+ * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+ * primitive class}, then this method returns the <em>primitive reference type</em>
+ * type of this primitive class.
+ * <p>
+ * Otherwise, this {@code Class} object represents a non-primitive class or interface
+ * and this method returns this class.
+ *
+ * @return the {@code Class} representing the primary type of
+ * this class or interface
+ * @since Valhalla
+ */
+ @IntrinsicCandidate
+ public Class<?> asPrimaryType() {
+ return isPrimitiveClass() ? primaryType : this;
+ }
+
+ /**
+ * Returns a {@code Class} object representing the <em>primitive value type</em>
+ * of this class if this class is a {@linkplain #isPrimitiveClass() primitive class}.
+ *
+ * @apiNote Alternatively, this method returns null if this class is not
+ * a primitive class rather than throwing UOE.
+ *
+ * @return the {@code Class} representing the {@linkplain #isPrimitiveValueType()
+ * primitive value type} of this class if this class is a primitive class
+ * @throws UnsupportedOperationException if this class or interface
+ * is not a primitive class
+ * @since Valhalla
+ */
+ @IntrinsicCandidate
+ public Class<?> asValueType() {
+ if (isPrimitiveClass())
+ return secondaryType;
+
+ throw new UnsupportedOperationException(this.getName().concat(" is not a primitive class"));
+ }
+
+ /**
+ * Returns {@code true} if this {@code Class} object represents the primary type
+ * of this class or interface.
+ * <p>
+ * If this {@code Class} object represents a primitive type or an array type,
+ * then this method returns {@code true}.
+ * <p>
+ * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+ * primitive}, then this method returns {@code true} if this {@code Class}
+ * object represents a primitive reference type, or returns {@code false}
+ * if this {@code Class} object represents a primitive value type.
+ * <p>
+ * If this {@code Class} object represents a non-primitive class or interface,
+ * then this method returns {@code true}.
+ *
+ * @return {@code true} if this {@code Class} object represents
+ * the primary type of this class or interface
+ * @since Valhalla
+ */
+ public boolean isPrimaryType() {
+ if (isPrimitiveClass()) {
+ return this == primaryType;
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if this {@code Class} object represents
+ * a {@linkplain #isPrimitiveClass() primitive} value type.
+ *
+ * @return {@code true} if this {@code Class} object represents
+ * the value type of a primitive class
+ * @since Valhalla
+ */
+ public boolean isPrimitiveValueType() {
+ return isPrimitiveClass() && this == secondaryType;
+ }
+
/**
* 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.
* Determines if the class or interface represented by this
* {@code Class} object is either the same as, or is a superclass or
* superinterface of, the class or interface represented by the specified
* {@code Class} parameter. It returns {@code true} if so;
* otherwise it returns {@code false}. If this {@code Class}
+ * object represents the {@linkplain #isPrimaryType() reference type}
+ * of a {@linkplain #isPrimitiveClass() primitive class}, this method
+ * return {@code true} if the specified {@code Class} parameter represents
+ * the same primitive class. If this {@code Class}
* object represents a primitive type, this method returns
* {@code true} if the specified {@code Class} parameter is
* exactly this {@code Class} object; otherwise it returns
* {@code false}.
*
* <p> Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
- * or via a widening reference conversion. See <cite>The Java Language
- * Specification</cite>, sections {@jls 5.1.1} and {@jls 5.1.4},
- * for details.
+ * or via a widening reference conversion or via a primitive widening
+ * conversion. See <cite>The Java Language Specification</cite>,
+ * sections {@jls 5.1.1} and {@jls 5.1.4}, for details.
*
* @param cls the {@code Class} object to be checked
* @return the {@code boolean} value indicating whether objects of the
* type {@code cls} can be assigned to objects of this class
* @throws NullPointerException if the specified Class parameter is
* <tr><th scope="row"> {@code boolean} <td style="text-align:center"> {@code Z}
* <tr><th scope="row"> {@code byte} <td style="text-align:center"> {@code B}
* <tr><th scope="row"> {@code char} <td style="text-align:center"> {@code C}
* <tr><th scope="row"> class or interface with <a href="ClassLoader.html#binary-name">binary name</a> <i>N</i>
* <td style="text-align:center"> {@code L}<em>N</em>{@code ;}
+ * <tr><th scope="row"> {@linkplain #isPrimitiveClass() primitive class} with <a href="ClassLoader.html#binary-name">binary name</a> <i>N</i>
+ * <td style="text-align:center"> {@code Q}<em>N</em>{@code ;}
* <tr><th scope="row"> {@code double} <td style="text-align:center"> {@code D}
* <tr><th scope="row"> {@code float} <td style="text-align:center"> {@code F}
* <tr><th scope="row"> {@code int} <td style="text-align:center"> {@code I}
* <tr><th scope="row"> {@code long} <td style="text-align:center"> {@code J}
* <tr><th scope="row"> {@code short} <td style="text-align:center"> {@code S}
* <blockquote><pre>
* 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.ref[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, interface, or other entity
* <p> The modifier encodings are defined in section {@jvms 4.1}
* of <cite>The Java Virtual Machine Specification</cite>.
*
* @return the {@code int} representing the modifiers for this class
* @see java.lang.reflect.Modifier
+ * @see #accessFlags()
* @see <a
* href="{@docRoot}/java.base/java/lang/reflect/package-summary.html#LanguageJvmModel">Java
* programming language and JVM modeling in core reflection</a>
* @since 1.1
* @jls 8.1.1 Class Modifiers
* @jls 9.1.1. Interface Modifiers
*/
@IntrinsicCandidate
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 {@code Class} 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);
+ /**
+ * {@return an unmodifiable set of the {@linkplain AccessFlag access
+ * flags} for this class, possibly empty}
+ * @see #getModifiers()
+ * @jvms 4.1 The ClassFile Structure
+ * @jvms 4.7.6 The InnerClasses Attribute
+ * @since 20
+ */
+ public Set<AccessFlag> accessFlags() {
+ // This likely needs some refinement. Exploration of hidden
+ // classes, array classes. Location.CLASS allows SUPER and
+ // AccessFlag.MODULE which INNER_CLASS forbids. INNER_CLASS
+ // allows PRIVATE, PROTECTED, and STATIC, which are not
+ // allowed on Location.CLASS.
+ return AccessFlag.maskToAccessFlags(getModifiers(),
+ (isMemberClass() || isLocalClass() || isAnonymousClass()) ?
+ AccessFlag.Location.INNER_CLASS :
+ AccessFlag.Location.CLASS);
+ }
/**
* If this {@code Class} object represents a local or anonymous
* class within a method, returns a {@link
* java.lang.reflect.Method Method} object representing the
int dimensions = 0;
do {
dimensions++;
cl = cl.getComponentType();
} while (cl.isArray());
- return cl.getName().concat("[]".repeat(dimensions));
+ return cl.getTypeName().concat("[]".repeat(dimensions));
} catch (Throwable e) { /*FALLTHRU*/ }
}
- return getName();
+ if (isPrimitiveClass()) {
+ // TODO: null-default
+ return isPrimaryType() ? getName().concat(".ref") : getName();
+ } else {
+ return getName();
+ }
}
/**
* Returns the canonical name of the underlying class as
* defined by <cite>The Java Language Specification</cite>.
*
* @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.
+ * {@code null} and is not assignable to the type T.
+ * @throws NullPointerException if this class is an {@linkplain #isPrimitiveValueType()
+ * primitive value type} and the object is {@code null}
*
* @since 1.5
*/
@SuppressWarnings("unchecked")
@IntrinsicCandidate
public T cast(Object obj) {
+ if (isPrimitiveValueType() && obj == null)
+ throw new NullPointerException(getName() + " is a primitive value type");
+
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));
return (T) obj;
}
*
* @return an array representing the superinterfaces
* @since 1.8
*/
public AnnotatedType[] getAnnotatedInterfaces() {
- return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
+ return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
}
private native Class<?> getNestHost0();
/**
if (isPrimitive())
return Wrapper.forPrimitiveType(this).basicTypeString();
if (isArray()) {
return "[" + componentType.descriptorString();
- } else if (isHidden()) {
+ }
+ char typeDesc = isPrimitiveValueType() ? 'Q' : 'L';
+ if (isHidden()) {
String name = getName();
int index = name.indexOf('/');
return new StringBuilder(name.length() + 2)
- .append('L')
+ .append(typeDesc)
.append(name.substring(0, index).replace('.', '/'))
.append('.')
.append(name, index + 1, name.length())
.append(';')
.toString();
} else {
String name = getName().replace('.', '/');
return new StringBuilder(name.length() + 2)
- .append('L')
+ .append(typeDesc)
.append(name)
.append(';')
.toString();
}
}
< prev index next >