[ad_1]
Adding local classes, lambdas and the toString()
method to complete the previous two answers. Further, I add arrays of lambdas and arrays of anonymous classes (which do not make any sense in practice though):
package com.example;
public final class TestClassNames {
private static void showClass(Class<?> c) {
System.out.println("getName(): " + c.getName());
System.out.println("getCanonicalName(): " + c.getCanonicalName());
System.out.println("getSimpleName(): " + c.getSimpleName());
System.out.println("toString(): " + c.toString());
System.out.println();
}
private static void x(Runnable r) {
showClass(r.getClass());
showClass(java.lang.reflect.Array.newInstance(r.getClass(), 1).getClass()); // Obtains an array class of a lambda base type.
}
public static class NestedClass {}
public class InnerClass {}
public static void main(String[] args) {
class LocalClass {}
showClass(void.class);
showClass(int.class);
showClass(String.class);
showClass(Runnable.class);
showClass(SomeEnum.class);
showClass(SomeAnnotation.class);
showClass(int[].class);
showClass(String[].class);
showClass(NestedClass.class);
showClass(InnerClass.class);
showClass(LocalClass.class);
showClass(LocalClass[].class);
Object anonymous = new java.io.Serializable() {};
showClass(anonymous.getClass());
showClass(java.lang.reflect.Array.newInstance(anonymous.getClass(), 1).getClass()); // Obtains an array class of an anonymous base type.
x(() -> {});
}
}
enum SomeEnum {
BLUE, YELLOW, RED;
}
@interface SomeAnnotation {}
This is the full output:
getName(): void
getCanonicalName(): void
getSimpleName(): void
toString(): void
getName(): int
getCanonicalName(): int
getSimpleName(): int
toString(): int
getName(): java.lang.String
getCanonicalName(): java.lang.String
getSimpleName(): String
toString(): class java.lang.String
getName(): java.lang.Runnable
getCanonicalName(): java.lang.Runnable
getSimpleName(): Runnable
toString(): interface java.lang.Runnable
getName(): com.example.SomeEnum
getCanonicalName(): com.example.SomeEnum
getSimpleName(): SomeEnum
toString(): class com.example.SomeEnum
getName(): com.example.SomeAnnotation
getCanonicalName(): com.example.SomeAnnotation
getSimpleName(): SomeAnnotation
toString(): interface com.example.SomeAnnotation
getName(): [I
getCanonicalName(): int[]
getSimpleName(): int[]
toString(): class [I
getName(): [Ljava.lang.String;
getCanonicalName(): java.lang.String[]
getSimpleName(): String[]
toString(): class [Ljava.lang.String;
getName(): com.example.TestClassNames$NestedClass
getCanonicalName(): com.example.TestClassNames.NestedClass
getSimpleName(): NestedClass
toString(): class com.example.TestClassNames$NestedClass
getName(): com.example.TestClassNames$InnerClass
getCanonicalName(): com.example.TestClassNames.InnerClass
getSimpleName(): InnerClass
toString(): class com.example.TestClassNames$InnerClass
getName(): com.example.TestClassNames$1LocalClass
getCanonicalName(): null
getSimpleName(): LocalClass
toString(): class com.example.TestClassNames$1LocalClass
getName(): [Lcom.example.TestClassNames$1LocalClass;
getCanonicalName(): null
getSimpleName(): LocalClass[]
toString(): class [Lcom.example.TestClassNames$1LocalClass;
getName(): com.example.TestClassNames$1
getCanonicalName(): null
getSimpleName():
toString(): class com.example.TestClassNames$1
getName(): [Lcom.example.TestClassNames$1;
getCanonicalName(): null
getSimpleName(): []
toString(): class [Lcom.example.TestClassNames$1;
getName(): com.example.TestClassNames$$Lambda$1/1175962212
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212
getSimpleName(): TestClassNames$$Lambda$1/1175962212
toString(): class com.example.TestClassNames$$Lambda$1/1175962212
getName(): [Lcom.example.TestClassNames$$Lambda$1;
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212[]
getSimpleName(): TestClassNames$$Lambda$1/1175962212[]
toString(): class [Lcom.example.TestClassNames$$Lambda$1;
So, here are the rules. First, lets start with primitive types and void
:
- If the class object represents a primitive type or
void
, all the four methods simply returns its name.
Now the rules for the getName()
method:
- Every non-lambda and non-array class or interface (i.e, top-level, nested, inner, local and anonymous) has a name (which is returned by
getName()
) that is the package name followed by a dot (if there is a package), followed by the name of its class-file as generated by the compiler (whithout the suffix.class
). If there is no package, it is simply the name of the class-file. If the class is an inner, nested, local or anonymous class, the compiler should generate at least one$
in its class-file name. Note that for anonymous classes, the class name would end with a dollar-sign followed by a number. - Lambda class names are generally unpredictable, and you shouldn’t care about they anyway. Exactly, their name is the name of the enclosing class, followed by
$$Lambda$
, followed by a number, followed by a slash, followed by another number. - The class descriptor of the primitives are
Z
forboolean
,B
forbyte
,S
forshort
,C
forchar
,I
forint
,J
forlong
,F
forfloat
andD
fordouble
. For non-array classes and interfaces the class descriptor isL
followed by what is given bygetName()
followed by;
. For array classes, the class descriptor is[
followed by the class descriptor of the component type (which may be itself another array class). - For array classes, the
getName()
method returns its class descriptor. This rule seems to fail only for array classes whose the component type is a lambda (which possibly is a bug), but hopefully this should not matter anyway because there is no point even on the existence of array classes whose component type is a lambda.
Now, the toString()
method:
- If the class instance represents an interface (or an annotation, which is a special type of interface), the
toString()
returns"interface " + getName()
. If it is a primitive, it returns simplygetName()
. If it is something else (a class type, even if it is a pretty weird one), it returns"class " + getName()
.
The getCanonicalName()
method:
- For top-level classes and interfaces, the
getCanonicalName()
method returns just what thegetName()
method returns. - The
getCanonicalName()
method returnsnull
for anonymous or local classes and for array classes of those. - For inner and nested classes and interfaces, the
getCanonicalName()
method returns what thegetName()
method would replacing the compiler-introduced dollar-signs by dots. - For array classes, the
getCanonicalName()
method returnsnull
if the canonical name of the component type isnull
. Otherwise, it returns the canonical name of the component type followed by[]
.
The getSimpleName()
method:
- For top-level, nested, inner and local classes, the
getSimpleName()
returns the name of the class as written in the source file. - For anonymous classes the
getSimpleName()
returns an emptyString
. - For lambda classes the
getSimpleName()
just returns what thegetName()
would return without the package name. This do not makes much sense and looks like a bug for me, but there is no point in callinggetSimpleName()
on a lambda class to start with. - For array classes the
getSimpleName()
method returns the simple name of the component class followed by[]
. This have the funny/weird side-effect that array classes whose component type is an anonymous class have just[]
as their simple names.
[ad_2]