Java 클래스에서 표준 이름, 단순 이름 및 클래스 이름의 차이점은 무엇입니까?
Java에서 이들의 차이점은 무엇입니까?
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
Javadoc을 여러 번 확인했지만 이것이 잘 설명되지 않습니다. 나는 또한 테스트를 실행했으며 이러한 메서드가 호출되는 방식의 실제 의미를 반영하지 않았습니다.
확실하지 않은 경우 먼저 테스트를 작성해보십시오.
난 이걸했다:
class ClassNameTest {
public static void main(final String... arguments) {
printNamesForClass(
int.class,
"int.class (primitive)");
printNamesForClass(
String.class,
"String.class (ordinary class)");
printNamesForClass(
java.util.HashMap.SimpleEntry.class,
"java.util.HashMap.SimpleEntry.class (nested class)");
printNamesForClass(
new java.io.Serializable(){}.getClass(),
"new java.io.Serializable(){}.getClass() (anonymous inner class)");
}
private static void printNamesForClass(final Class<?> clazz, final String label) {
System.out.println(label + ":");
System.out.println(" getName(): " + clazz.getName());
System.out.println(" getCanonicalName(): " + clazz.getCanonicalName());
System.out.println(" getSimpleName(): " + clazz.getSimpleName());
System.out.println(" getTypeName(): " + clazz.getTypeName()); // added in Java 8
System.out.println();
}
}
인쇄물:
int.class (기본) : getName () : 정수 getCanonicalName () : 정수 getSimpleName () : 정수 getTypeName () : 정수 String.class (일반 클래스) : getName () : java.lang.String getCanonicalName () : java.lang.String getSimpleName () : 문자열 getTypeName () : java.lang.String java.util.HashMap.SimpleEntry.class (중첩 클래스) : getName () : java.util.AbstractMap $ SimpleEntry getCanonicalName () : java.util.AbstractMap.SimpleEntry getSimpleName () : SimpleEntry getTypeName () : java.util.AbstractMap $ SimpleEntry new java.io.Serializable () {}. getClass () (익명 내부 클래스) : getName () : ClassNameTest $ 1 getCanonicalName () : null getSimpleName () : getTypeName () : ClassNameTest $ 1
getSimpleName
빈 문자열을 반환하는 마지막 블록에 빈 항목이 있습니다 .
이것을 보는 결과는 다음과 같습니다.
- 이름은 동적으로, 예를 들어, 전화를 가진 클래스를로드하는 데 사용하는 거라고 이름입니다
Class.forName
기본으로ClassLoader
. 특정 범위 내에서ClassLoader
모든 클래스는 고유 한 이름을 갖습니다. - 정식 이름은 import 문에 사용되는 이름입니다.
toString
또는 로깅 작업 중에 유용 할 수 있습니다 .javac
컴파일러가 클래스 경로에 대한 전체보기를 가지고 있으면 컴파일 타임에 정규화 된 클래스 및 패키지 이름을 충돌시켜 정식 이름의 고유성을 적용합니다. 그러나 JVM은 이러한 이름 충돌을 허용해야하므로 정식 이름은ClassLoader
. (돌아 보면이 getter의 더 나은 이름이되었을 것입니다getJavaName
. 그러나이 메소드는 JVM이 Java 프로그램을 실행하는 데만 사용 된 때부터 시작되었습니다.) - 간단한 이름은 느슨하게 동안 유용 할 수 있습니다 다시 클래스를 식별
toString
또는 기록 작업을하지만, 고유하지 않을 수도 있습니다. - 형의 이름 반환, "그것은) toString (같은 : 그것은 순전히 정보의 어떠한 계약 금액이 없습니다" "이러한 유형의 이름에 대한 정보를 문자열"(sir4ur0n에 의해 작성된로)
toString()
이전 두 답변을 완료하기 위해 로컬 클래스, 람다 및 메서드를 추가 합니다. 또한 람다 배열과 익명 클래스 배열을 추가합니다 (실제로는 의미가 없음).
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 {}
다음은 전체 출력입니다.
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;
그래서 여기에 규칙이 있습니다. 먼저 기본 유형부터 시작하겠습니다 void
.
- 클래스 객체가 기본 유형 또는을 나타내는 경우
void
네 가지 메서드는 모두 해당 이름을 반환합니다.
이제 getName()
방법에 대한 규칙 :
- 모든 비 람다 및 비 배열 클래스 또는 인터페이스 (예 : 최상위, 중첩, 내부, 로컬 및 익명)에는
getName()
패키지 이름 뒤에 점 (패키지가있는 경우 )이 오는 이름 (에서 반환 됨 )이 있습니다. ) 뒤에 컴파일러에 의해 생성 된 클래스 파일의 이름이옵니다 (접미사없이.class
). 패키지가 없으면 단순히 클래스 파일의 이름입니다. 클래스가 내부, 중첩, 로컬 또는 익명 클래스 인 경우 컴파일러는$
클래스 파일 이름에 하나 이상의 클래스를 생성해야합니다 . 익명 클래스의 경우 클래스 이름은 달러 기호와 숫자로 끝납니다. - Lambda 클래스 이름은 일반적으로 예측할 수 없으며 어쨌든 신경 쓰지 않아야합니다. 정확히 그 이름은 둘러싸는 클래스의 이름
$$Lambda$
, 뒤에, 숫자, 슬래시, 다른 숫자 순입니다. - 프리미티브의 클래스 설명자는
Z
forboolean
,B
forbyte
,S
forshort
,C
forchar
,I
forint
,J
forlong
,F
forfloat
및D
fordouble
입니다. 비 배열 클래스 및 인터페이스의 클래스 디스크립터되어L
주어진 어떤이어서getName()
하였다;
. 배열 클래스의 경우 클래스 설명자[
다음에 구성 요소 유형의 클래스 설명자가옵니다 (그 자체가 다른 배열 클래스 일 수 있음). - 배열 클래스의 경우
getName()
메서드는 클래스 설명자를 반환합니다. 이 규칙은 구성 요소 유형이 람다 (버그 일 수 있음) 인 배열 클래스에 대해서만 실패하는 것처럼 보이지만, 구성 요소 유형이 람다 인 배열 클래스의 존재 여부에 대해서도 의미가 없기 때문에 어쨌든 이것은 중요하지 않습니다.
이제 toString()
방법 :
- 클래스 인스턴스는 인터페이스 (또는 인터페이스의 특별한 유형 주석,)에 나타내는 경우
toString()
반환"interface " + getName()
. 프리미티브 인 경우 단순히를 반환합니다getName()
. 그것이 다른 것이라면 (아주 이상한 것이더라도 클래스 유형)"class " + getName()
.
getCanonicalName()
방법 :
- 최상위 클래스 및 인터페이스의 경우
getCanonicalName()
메서드가 반환하는 것만getName()
반환합니다. - 이
getCanonicalName()
메서드는null
익명 또는 로컬 클래스와 그 배열 클래스에 대해 반환 합니다. - 내부 및 중첩 클래스 및 인터페이스의 경우
getCanonicalName()
메서드는getName()
컴파일러에서 도입 한 달러 기호를 점으로 대체 할 메서드를 반환합니다 . - 어레이 클래스의
getCanonicalName()
메소드는 반환null
성분 형의 정식 이름 인 경우null
. 그렇지 않으면 구성 요소 유형의 정식 이름 뒤에[]
.
getSimpleName()
방법 :
- 최상위, 중첩, 내부 및 로컬 클래스
getSimpleName()
의 경우는 소스 파일에 작성된 클래스 이름을 반환합니다. - 익명 클래스의
getSimpleName()
경우 빈String
. - 람다 클래스의 경우 패키지 이름없이 반환
getSimpleName()
되는getName()
것을 반환합니다. 이것은별로 말이 안되고 버그처럼 보이지만getSimpleName()
시작하기 위해 람다 클래스를 호출 하는 것은 의미가 없습니다 . - 배열 클래스의 경우
getSimpleName()
메서드는 구성 요소 클래스의 간단한 이름 뒤에[]
. 이것은 구성 요소 유형이 익명 클래스 인 배열 클래스가[]
단순한 이름과 마찬가지로 재미 있고 이상한 부작용이 있습니다 .
Nick Holt의 관찰 외에도 Array
데이터 유형에 대한 몇 가지 사례를 실행했습니다 .
//primitive Array
int demo[] = new int[5];
Class<? extends int[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
System.out.println();
//Object Array
Integer demo[] = new Integer[5];
Class<? extends Integer[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
위의 코드 스 니펫은 다음을 인쇄합니다.
[I
int[]
int[]
[Ljava.lang.Integer;
java.lang.Integer[]
Integer[]
나는 다양한 이름 지정 체계에 대해서도 혼란 스러웠고 여기에서이 질문을 발견했을 때 이것에 대해 내 자신의 질문을 묻고 대답하려고했습니다. 내 결과가 충분히 적합하고 이미 여기에있는 것을 보완한다고 생각합니다. 내 초점은 다양한 용어에 대한 문서 를 찾고 다른 곳에서 나타날 수있는 관련 용어를 추가하는 것입니다.
다음 예를 고려하십시오.
package a.b;
class C {
static class D extends C {
}
D d;
D[] ds;
}
의 간단한 이름 은
D
입니다D
. 이것은 클래스를 선언 할 때 작성한 부분입니다. 익명 클래스 에는 단순한 이름이 없습니다.Class.getSimpleName()
이 이름 또는 빈 문자열을 반환합니다. JLS 섹션 3.8에 따라 식별자의 유효한 부분$
이기 때문에 간단한 이름에 a를 포함 할 수 있습니다 (약간 권장하지 않더라도).$
에 따르면 JLS 섹션 6.7 , 모두
a.b.C.D
와는a.b.C.D.D.D
것 정규화 된 이름 ,하지만a.b.C.D
것 정식 이름 의D
. 따라서 모든 정식 이름은 정규화 된 이름이지만 수렴이 항상 사실은 아닙니다.Class.getCanonicalName()
정식 이름 또는null
.Class.getName()
JLS 섹션 13.1에 지정된대로 바이너리 이름 을 반환하도록 문서화되어 있습니다. 이 경우 for 및 for를 반환 합니다 .a.b.C$D
D
[La.b.C$D;
D[]
이 대답 은 동일한 클래스 로더에 의해로드 된 두 개의 클래스가 동일한 표준 이름 이지만 별개의 이진 이름 을 가질 수 있음을 보여줍니다 . 두 이름 모두 다른 이름을 안정적으로 추론하기에 충분하지 않습니다. 정식 이름이 있으면 이름의 어느 부분이 패키지이고 어떤 부분이 클래스를 포함하는지 알 수 없습니다. 이진 이름이 있으면
$
구분자로 도입 된 것과 간단한 이름의 일부인 것을 알 수 없습니다 . (클래스 파일 을 저장 바이너리 이름 의 클래스 자체 와 그 둘러싸는 클래스 런타임이 할 수 있습니다, 이 구별을 .)Anonymous classes and local classes have no fully qualified names but still have a binary name. The same holds for classes nested inside such classes. Every class has a binary name.
Running
javap -v -private
ona/b/C.class
shows that the bytecode refers to the type ofd
asLa/b/C$D;
and that of the arrayds
as[La/b/C$D;
. These are called descriptors, and they are specified in JVMS section 4.3.The class name
a/b/C$D
used in both of these descriptors is what you get by replacing.
by/
in the binary name. The JVM spec apparently calls this the internal form of the binary name. JVMS section 4.2.1 describes it, and states that the difference from the binary name were for historical reasons.The file name of a class in one of the typical filename-based class loaders is what you get if you interpret the
/
in the internal form of the binary name as a directory separator, and append the file name extension.class
to it. It's resolved relative to the class path used by the class loader in question.
this is best document I found describing getName(), getSimpleName(), getCanonicalName()
// Primitive type
int.class.getName(); // -> int
int.class.getCanonicalName(); // -> int
int.class.getSimpleName(); // -> int
// Standard class
Integer.class.getName(); // -> java.lang.Integer
Integer.class.getCanonicalName(); // -> java.lang.Integer
Integer.class.getSimpleName(); // -> Integer
// Inner class
Map.Entry.class.getName(); // -> java.util.Map$Entry
Map.Entry.class.getCanonicalName(); // -> java.util.Map.Entry
Map.Entry.class.getSimpleName(); // -> Entry
// Anonymous inner class
Class<?> anonymousInnerClass = new Cloneable() {}.getClass();
anonymousInnerClass.getName(); // -> somepackage.SomeClass$1
anonymousInnerClass.getCanonicalName(); // -> null
anonymousInnerClass.getSimpleName(); // -> // An empty string
// Array of primitives
Class<?> primitiveArrayClass = new int[0].getClass();
primitiveArrayClass.getName(); // -> [I
primitiveArrayClass.getCanonicalName(); // -> int[]
primitiveArrayClass.getSimpleName(); // -> int[]
// Array of objects
Class<?> objectArrayClass = new Integer[0].getClass();
objectArrayClass.getName(); // -> [Ljava.lang.Integer;
objectArrayClass.getCanonicalName(); // -> java.lang.Integer[]
objectArrayClass.getSimpleName(); // -> Integer[]
It is interesting to note that getCanonicalName()
and getSimpleName()
can raise InternalError
when the class name is malformed. This happens for some non-Java JVM languages, e.g., Scala.
Consider the following (Scala 2.11 on Java 8):
scala> case class C()
defined class C
scala> val c = C()
c: C = C()
scala> c.getClass.getSimpleName
java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1330)
... 32 elided
scala> c.getClass.getCanonicalName
java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1330)
at java.lang.Class.getCanonicalName(Class.java:1399)
... 32 elided
scala> c.getClass.getName
res2: String = C
This can be a problem for mixed language environments or environments that dynamically load bytecode, e.g., app servers and other platform software.
public void printReflectionClassNames(){
StringBuffer buffer = new StringBuffer();
Class clazz= buffer.getClass();
System.out.println("Reflection on String Buffer Class");
System.out.println("Name: "+clazz.getName());
System.out.println("Simple Name: "+clazz.getSimpleName());
System.out.println("Canonical Name: "+clazz.getCanonicalName());
System.out.println("Type Name: "+clazz.getTypeName());
}
outputs:
Reflection on String Buffer Class
Name: java.lang.StringBuffer
Simple Name: StringBuffer
Canonical Name: java.lang.StringBuffer
Type Name: java.lang.StringBuffer
getName() – returns the name of the entity (class, interface, array class, primitive type, or void) represented by this Class object, as a String.
getCanonicalName() – returns the canonical name of the underlying class as defined by the Java Language Specification.
getSimpleName() – returns the simple name of the underlying class, that is the name it has been given in the source code.
package com.practice;
public class ClassName {
public static void main(String[] args) {
ClassName c = new ClassName();
Class cls = c.getClass();
// returns the canonical name of the underlying class if it exists
System.out.println("Class = " + cls.getCanonicalName()); //Class = com.practice.ClassName
System.out.println("Class = " + cls.getName()); //Class = com.practice.ClassName
System.out.println("Class = " + cls.getSimpleName()); //Class = ClassName
System.out.println("Class = " + Map.Entry.class.getName()); // -> Class = java.util.Map$Entry
System.out.println("Class = " + Map.Entry.class.getCanonicalName()); // -> Class = java.util.Map.Entry
System.out.println("Class = " + Map.Entry.class.getSimpleName()); // -> Class = Entry
}
}
One difference is that if you use an anonymous class you can get a null value when trying to get the name of the class using the getCanonicalName()
Another fact is that getName()
method behaves differently than the getCanonicalName()
method for inner classes. getName()
uses a dollar as the separator between the enclosing class canonical name and the inner class simple name.
To know more about retrieving a class name in Java.
'programing' 카테고리의 다른 글
Android에서 가로 모드를 비활성화하는 방법은 무엇입니까? (0) | 2020.09.28 |
---|---|
Android 레이아웃 파일에서 "tools : context"는 무엇입니까? (0) | 2020.09.28 |
: :( 이중 콜론) 연산자 (Java 8) (0) | 2020.09.28 |
드로어 블을 비트 맵으로 변환하는 방법은 무엇입니까? (0) | 2020.09.28 |
생성자와 ngOnInit의 차이점 (0) | 2020.09.28 |