해당 클래스의 정적 메소드에서 클래스 이름을 얻는 방법은 무엇입니까? 예를 들어
public class MyClass {
public static String getClassName() {
String name = ????; // what goes here so the string "MyClass" is returned
return name;
}
}
문맥에 맞추기 위해 실제로 예외의 메시지의 일부로 클래스 이름을 반환하려고합니다.
답변
리팩토링을 올바르게 지원하려면 (클래스 이름 바꾸기) 다음 중 하나를 사용해야합니다.
MyClass.class.getName(); // full name with package
또는 ( @James Van Huis 덕분에 ) :
MyClass.class.getSimpleName(); // class name and no more
답변
툴킷의 기능을 수행하십시오. 다음과 같이하지 마십시오 :
return new Object() { }.getClass().getEnclosingClass();
답변
Java 7 이상에서는 정적 메소드 / 필드에서이를 수행 할 수 있습니다.
MethodHandles.lookup().lookupClass()
답변
따라서 MyClass.class
구문을 명시 적으로 사용하지 않고 클래스 객체 또는 클래스 전체 / 간단한 이름을 정적으로 가져와야하는 상황이 있습니다.
경우에 따라 로거 인스턴스와 같은 경우에 정말 유용 할 수 있습니다. 코 틀린 상위 레벨 함수 (이 경우 kotlin은 kotlin 코드에서 액세스 할 수없는 정적 Java 클래스를 작성 함)
이 정보를 얻기위한 몇 가지 변형이 있습니다.
-
new Object(){}.getClass().getEnclosingClass();
에 의해 지적 톰 Hawtin의 – tackline -
getClassContext()[0].getName();
Christoffer 의SecurityManager
언급 에서 -
new Throwable().getStackTrace()[0].getClassName();
에 의해 계산 루드비히 -
Thread.currentThread().getStackTrace()[1].getClassName();
에서 Keksi -
그리고 마침내 Rein
MethodHandles.lookup().lookupClass();
에서 최고
나는 준비했다 jmh 모든 변형 및 결과에 대한 벤치 마크는 다음과 같습니다.
# Run complete. Total time: 00:04:18
Benchmark Mode Cnt Score Error Units
StaticClassLookup.MethodHandles_lookup_lookupClass avgt 30 3.630 ± 0.024 ns/op
StaticClassLookup.AnonymousObject_getClass_enclosingClass avgt 30 282.486 ± 1.980 ns/op
StaticClassLookup.SecurityManager_classContext_1 avgt 30 680.385 ± 21.665 ns/op
StaticClassLookup.Thread_currentThread_stackTrace_1_className avgt 30 11179.460 ± 286.293 ns/op
StaticClassLookup.Throwable_stackTrace_0_className avgt 30 10221.209 ± 176.847 ns/op
결론
- 사용하기 가장 좋은 변형 , 오히려 깨끗하고 엄청나게 빠릅니다.
Java 7 및 Android API 26 이후에만 사용 가능합니다!
MethodHandles.lookup().lookupClass();
- Android 또는 Java 6에이 기능이 필요한 경우 두 번째 최상의 변형을 사용할 수 있습니다. 그것은 빠르고 너무 오히려입니다, 하지만 각각의 사용 대신에 익명의 클래스를 만듭니다 🙁
new Object(){}.getClass().getEnclosingClass();
-
많은 곳에서 필요하고 수많은 익명 클래스로 인해 바이트 코드가 부풀어 오르기를 원하지 않는다면
SecurityManager
친구입니다 (세 번째 최선의 선택).그러나 당신은 단지 전화 할 수 없습니다
getClassContext()
– 그것은SecurityManager
수업 에서 보호됩니다 . 다음과 같은 도우미 클래스가 필요합니다.
// Helper class
public final class CallerClassGetter extends SecurityManager
{
private static final CallerClassGetter INSTANCE = new CallerClassGetter();
private CallerClassGetter() {}
public static Class<?> getCallerClass() {
return INSTANCE.getClassContext()[1];
}
}
// Usage example:
class FooBar
{
static final Logger LOGGER = LoggerFactory.getLogger(CallerClassGetter.getCallerClass())
}
getStackTrace()
from 예외 또는 에 기반하여 마지막 두 변형을 사용할 필요는 없습니다Thread.currentThread()
. 매우 비효율적이며 인스턴스 이름이String
아닌 클래스 이름 만 반환 할 수 있습니다Class<*>
.
추신
정적 kotlin 유틸리티 (예 : 나와 같은)에 대한 로거 인스턴스를 작성하려는 경우이 헬퍼를 사용할 수 있습니다.
import org.slf4j.Logger
import org.slf4j.LoggerFactory
// Should be inlined to get an actual class instead of the one where this helper declared
// Will work only since Java 7 and Android API 26!
@Suppress("NOTHING_TO_INLINE")
inline fun loggerFactoryStatic(): Logger
= LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())
사용 예 :
private val LOGGER = loggerFactoryStatic()
/**
* Returns a pseudo-random, uniformly distributed value between the
* given least value (inclusive) and bound (exclusive).
*
* @param min the least value returned
* @param max the upper bound (exclusive)
*
* @return the next value
* @throws IllegalArgumentException if least greater than or equal to bound
* @see java.util.concurrent.ThreadLocalRandom.nextDouble(double, double)
*/
fun Random.nextDouble(min: Double = .0, max: Double = 1.0): Double {
if (min >= max) {
if (min == max) return max
LOGGER.warn("nextDouble: min $min > max $max")
return min
}
return nextDouble() * (max - min) + min
}
답변
이 지침은 잘 작동합니다.
Thread.currentThread().getStackTrace()[1].getClassName();
답변
다음과 같이 JNI를 사용하여 정말 달콤한 것을 할 수 있습니다.
MyObject.java :
public class MyObject
{
static
{
System.loadLibrary( "classname" );
}
public static native String getClassName();
public static void main( String[] args )
{
System.out.println( getClassName() );
}
}
그때:
javac MyObject.java
javah -jni MyObject
그때:
MyObject.c :
#include "MyObject.h"
JNIEXPORT jstring JNICALL Java_MyObject_getClassName( JNIEnv *env, jclass cls )
{
jclass javaLangClass = (*env)->FindClass( env, "java/lang/Class" );
jmethodID getName = (*env)->GetMethodID( env, javaLangClass, "getName",
"()Ljava/lang/String;" );
return (*env)->CallObjectMethod( env, cls, getName );
}
그런 다음 C를 공유 라이브러리로 컴파일하고 libclassname.so
java!
*킬킬 웃음
답변
이 클래스를 사용하여 클래스 상단에 Log4j 로거를 초기화하거나 주석을 달 수 있습니다.
PRO : Throwable이 이미로드되어 있으며 “IO heavy”SecurityManager를 사용하지 않으면 자원을 절약 할 수 있습니다.
CON : 이것이 모든 JVM에서 작동하는지에 대한 질문입니다.
// Log4j . Logger --- Get class name in static context by creating an anonymous Throwable and
// getting the top of its stack-trace.
// NOTE you must use: getClassName() because getClass() just returns StackTraceElement.class
static final Logger logger = Logger.getLogger(new Throwable() .getStackTrace()[0].getClassName());