< prev index next >

src/java.base/share/classes/java/lang/Class.java

Print this page
*** 196,13 ***
                                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();
      }
--- 196,14 ---
                                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 PRIMITIVE_CLASS = 0x00000100;
  
      private static native void registerNatives();
      static {
          registerNatives();
      }

*** 230,12 ***
       * 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.
--- 231,23 ---
       * this method returns "class " followed by {@code getName}.
       *
       * @return a string representation of this {@code Class} object.
       */
      public String toString() {
!         String s = isPrimitive() ? "" : "class ";
!         if (isInterface()) {
+             s = "interface ";
+         }
+         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.

*** 292,10 ***
--- 304,13 ---
                  }
  
                  if (isAnnotation()) {
                      sb.append('@');
                  }
+                 if (isPrimitiveClass()) {
+                     sb.append("primitive ");
+                 }
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");

*** 467,12 ***
          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">
--- 482,12 ---
          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">

*** 546,10 ***
--- 561,117 ---
          } 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 #isValueType() 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.
+      *
+      * @return {@code true} if this class is a primitive class, otherwise {@code false}
+      * @see #asPrimaryType()
+      * @see #asValueType()
+      * @since Valhalla
+      */
+     public boolean isPrimitiveClass() {
+         return (this.getModifiers() & PRIMITIVE_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 #isValueType()
+      * 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 isValueType() {
+         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.

*** 690,21 ***
       * 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 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.
       *
       * @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
--- 812,25 ---
       * 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 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

*** 828,10 ***
--- 954,12 ---
       * <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}

*** 846,12 ***
--- 974,18 ---
       * <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

*** 1281,22 ***
       * @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);
  
--- 1415,20 ---

*** 1680,14 ***
                  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>.
--- 1812,19 ---
                  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>.

*** 3876,17 ***
       *
       * @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")
      @IntrinsicCandidate
      public T cast(Object obj) {
          if (obj != null && !isInstance(obj))
              throw new ClassCastException(cannotCastMsg(obj));
          return (T) obj;
      }
  
--- 4013,22 ---
       *
       * @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 #isValueType()
+      * primitive value type} and the object is {@code null}
       *
       * @since 1.5
       */
      @SuppressWarnings("unchecked")
      @IntrinsicCandidate
      public T cast(Object obj) {
+         if (isValueType() && obj == null)
+             throw new NullPointerException(getName() + " is a primitive value type");
+ 
          if (obj != null && !isInstance(obj))
              throw new ClassCastException(cannotCastMsg(obj));
          return (T) obj;
      }
  

*** 4178,11 ***
       *
       * @return an array representing the superinterfaces
       * @since 1.8
       */
      public AnnotatedType[] getAnnotatedInterfaces() {
!          return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
      }
  
      private native Class<?> getNestHost0();
  
      /**
--- 4320,11 ---
       *
       * @return an array representing the superinterfaces
       * @since 1.8
       */
      public AnnotatedType[] getAnnotatedInterfaces() {
!         return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
      }
  
      private native Class<?> getNestHost0();
  
      /**

*** 4393,24 ***
          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();
          }
      }
--- 4535,26 ---
          if (isPrimitive())
              return Wrapper.forPrimitiveType(this).basicTypeString();
  
          if (isArray()) {
              return "[" + componentType.descriptorString();
!         }
+         char typeDesc = isValueType() ? '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();
          }
      }
< prev index next >