< prev index next > src/java.base/share/classes/java/lang/Class.java
Print this page
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.ClassFileFormatVersion;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+ import jdk.internal.javac.PreviewFeature;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.misc.Unsafe;
import jdk.internal.module.Resources;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.CallerSensitiveAdapter;
import jdk.internal.reflect.ConstantPool;
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
+ import jdk.internal.value.PrimitiveClass;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import sun.invoke.util.Wrapper;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
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 native void registerNatives();
static {
registerNatives();
}
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 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());
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
* this method returns "class " followed by {@code getName}.
*
* @return a string representation of this {@code Class} object.
*/
public String toString() {
! String s = getName();
! if (isPrimitive()) {
+ return s;
+ }
+ // Avoid invokedynamic based String concat, might be not available
+ // Prepend type of class
+ s = (isInterface() ? "interface " : "class ").concat(s);
+ if (isValue()) {
+ // prepend value class type
+ s = (isPrimitiveClass() ? "primitive " : "value ").concat(s);
+ if (isPrimitiveClass() && isPrimaryType()) {
+ // Append .ref
+ s = s.concat(".ref");
+ }
+ }
+ return s;
}
/**
* Returns a string describing this {@code Class}, including
* information about modifiers and type parameters.
} while (component.isArray());
sb.append(component.getName());
} else {
// Class modifiers are a superset of interface modifiers
int modifiers = getModifiers() & Modifier.classModifiers();
+ // Modifier.toString() below mis-interprets SYNCHRONIZED, STRICT, and VOLATILE bits
+ modifiers &= ~(Modifier.SYNCHRONIZED | Modifier.STRICT | Modifier.VOLATILE);
if (modifiers != 0) {
sb.append(Modifier.toString(modifiers));
sb.append(' ');
}
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)
throws ClassNotFoundException;
/**
* Returns the {@code Class} with the given <a href="ClassLoader.html#binary-name">
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)
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
+ */
+ /* package */ boolean isPrimitiveClass() {
+ return (this.getModifiers() & PrimitiveClass.PRIMITIVE_CLASS) != 0;
+ }
+
+ /**
+ * {@return {@code true} if this {@code Class} object represents an identity
+ * class or interface; otherwise {@code false}}
+ *
+ * If this {@code Class} object represents an array type, then this method
+ * returns {@code true}.
+ * If this {@code Class} object represents a primitive type, or {@code void},
+ * then this method returns {@code false}.
+ *
+ * @since Valhalla
+ */
+ @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
+ public native boolean isIdentity();
+
+ /**
+ * {@return {@code true} if this {@code Class} object represents a value
+ * class or interface; otherwise {@code false}}
+ *
+ * If this {@code Class} object represents an array type, a primitive type, or
+ * {@code void}, then this method returns {@code false}.
+ *
+ * @since Valhalla
+ */
+ @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
+ public boolean isValue() {
+ return (this.getModifiers() & Modifier.VALUE) != 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
+ /* package */ 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
+ /* package */ 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
+ */
+ /* package */ 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
+ */
+ /* package */ 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.
* in an integer. The modifiers consist of the Java Virtual Machine's
* constants for {@code public}, {@code protected},
* {@code private}, {@code final}, {@code static},
* {@code abstract} and {@code interface}; they should be decoded
* using the methods of class {@code Modifier}.
+ * The modifiers also include the Java Virtual Machine's constants for
+ * {@code identity class} and {@code value class}.
*
* <p> If the underlying class is an array class:
* <ul>
* <li> its {@code public}, {@code private} and {@code protected}
* modifiers are the same as those of its component type
* @jvms 4.1 The {@code ClassFile} Structure
*/
@IntrinsicCandidate
public native int getModifiers();
! /**
* {@return an unmodifiable set of the {@linkplain AccessFlag access
* flags} for this class, possibly empty}
*
* <p> If the underlying class is an array class:
* <ul>
* <li> its {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
* access flags are the same as those of its component type
* @jvms 4.1 The {@code ClassFile} Structure
*/
@IntrinsicCandidate
public native int getModifiers();
! /**
* {@return an unmodifiable set of the {@linkplain AccessFlag access
* flags} for this class, possibly empty}
+ * The {@code AccessFlags} may depend on the class file format version of the class.
*
* <p> If the underlying class is an array class:
* <ul>
* <li> its {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
* access flags are the same as those of its component type
// Use getClassAccessFlagsRaw to expose SUPER status.
var location = (isMemberClass() || isLocalClass() ||
isAnonymousClass() || isArray()) ?
AccessFlag.Location.INNER_CLASS :
AccessFlag.Location.CLASS;
! return AccessFlag.maskToAccessFlags((location == AccessFlag.Location.CLASS) ?
! getClassAccessFlagsRaw() :
! getModifiers(),
! location);
}
! /**
* 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);
-
/**
* 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
* immediately enclosing method of the underlying class. Returns
// Use getClassAccessFlagsRaw to expose SUPER status.
var location = (isMemberClass() || isLocalClass() ||
isAnonymousClass() || isArray()) ?
AccessFlag.Location.INNER_CLASS :
AccessFlag.Location.CLASS;
! int accessFlags = (location == AccessFlag.Location.CLASS) ?
! getClassAccessFlagsRaw() : getModifiers();
! var cffv = ClassFileFormatVersion.fromMajor(getClassFileVersion() & 0xffff);
! if (cffv.compareTo(ClassFileFormatVersion.latest()) >= 0) {
+ // Ignore unspecified (0x800) access flag for current version
+ accessFlags &= ~0x0800;
+ }
+ return AccessFlag.maskToAccessFlags(accessFlags, location, cffv);
}
! /**
* 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);
/**
* 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
* immediately enclosing method of the underlying class. Returns
boolean isPartial() {
return enclosingClass == null || name == null || descriptor == null;
}
! boolean isConstructor() { return !isPartial() && ConstantDescs.INIT_NAME.equals(name); }
! boolean isMethod() { return !isPartial() && !isConstructor() && !ConstantDescs.CLASS_INIT_NAME.equals(name); }
Class<?> getEnclosingClass() { return enclosingClass; }
String getName() { return name; }
boolean isPartial() {
return enclosingClass == null || name == null || descriptor == null;
}
! boolean isObjectConstructor() { return !isPartial() && ConstantDescs.INIT_NAME.equals(name); }
! boolean isValueFactoryMethod() { return !isPartial() && ConstantDescs.VNEW_NAME.equals(name); }
+
+ boolean isMethod() { return !isPartial() && !isObjectConstructor()
+ && !isValueFactoryMethod()
+ && !ConstantDescs.CLASS_INIT_NAME.equals(name); }
Class<?> getEnclosingClass() { return enclosingClass; }
String getName() { return name; }
EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
if (enclosingInfo == null)
return null;
else {
! if (!enclosingInfo.isConstructor())
return null;
ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
getFactory());
Type [] parameterTypes = typeInfo.getParameterTypes();
EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
if (enclosingInfo == null)
return null;
else {
! if (!enclosingInfo.isObjectConstructor() && !enclosingInfo.isValueFactoryMethod())
return null;
ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
getFactory());
Type [] parameterTypes = typeInfo.getParameterTypes();
int dimensions = 0;
do {
dimensions++;
cl = cl.getComponentType();
} while (cl.isArray());
! return cl.getName().concat("[]".repeat(dimensions));
} catch (Throwable e) { /*FALLTHRU*/ }
}
! return getName();
}
/**
* Returns the canonical name of the underlying class as
* defined by <cite>The Java Language Specification</cite>.
int dimensions = 0;
do {
dimensions++;
cl = cl.getComponentType();
} while (cl.isArray());
! return cl.getTypeName().concat("[]".repeat(dimensions));
} catch (Throwable e) { /*FALLTHRU*/ }
}
! 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>.
if (arrayContentsEq(parameterTypes,
fact.getExecutableSharedParameterTypes(constructor))) {
return constructor;
}
}
! throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
}
//
// Other helpers and base implementation
//
if (arrayContentsEq(parameterTypes,
fact.getExecutableSharedParameterTypes(constructor))) {
return constructor;
}
}
! throw new NoSuchMethodException(methodToString(isValue() ? "<vnew>" : "<init>", parameterTypes));
}
//
// Other helpers and base implementation
//
* @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);
}
private native Class<?> getNestHost0();
/**
*
* @return an array representing the superinterfaces
* @since 1.8
*/
public AnnotatedType[] getAnnotatedInterfaces() {
! 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()) {
String name = getName();
int index = name.indexOf('/');
return new StringBuilder(name.length() + 2)
! .append('L')
.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(name)
.append(';')
.toString();
}
}
if (isPrimitive())
return Wrapper.forPrimitiveType(this).basicTypeString();
if (isArray()) {
return "[" + componentType.descriptorString();
! }
+ char typeDesc = isPrimitiveValueType() ? 'Q' : 'L';
+ if (isHidden()) {
String name = getName();
int index = name.indexOf('/');
return new StringBuilder(name.length() + 2)
! .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(typeDesc)
.append(name)
.append(';')
.toString();
}
}
*
* If the class is an array type then the class file version of its element
* type is returned. If the class is a primitive type then the latest class
* file major version is returned and zero is returned for the minor version.
*/
! private int getClassFileVersion() {
Class<?> c = isArray() ? elementType() : this;
return c.getClassFileVersion0();
}
private native int getClassFileVersion0();
*
* If the class is an array type then the class file version of its element
* type is returned. If the class is a primitive type then the latest class
* file major version is returned and zero is returned for the minor version.
*/
! /* package-private */
+ int getClassFileVersion() {
Class<?> c = isArray() ? elementType() : this;
return c.getClassFileVersion0();
}
private native int getClassFileVersion0();
< prev index next >