Java의 정적 메서드에서 클래스 이름 가져오기
해당 클래스의 정적 메서드에서 클래스 이름을 가져오려면 어떻게 해야 합니까?예를들면
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
MyClass.class.getSimpleName(); // class name and no more
Java 7+ 에서는, 이것을 스태틱한 메서드/필드로 실행할 수 있습니다.
MethodHandles.lookup().lookupClass()
@toolkit의 지시에 따릅니다.다음과 같은 작업을 수행하지 마십시오.
return new Object() { }.getClass().getEnclosingClass();
(편집: 이 답변이 작성된 지 한참 후에 나온 Java 버전을 사용하는 경우 @Rein).
클래스 풀 이름을 해야 하는 상황이 .MyClass.class
구문을 사용합니다.
예를 들어 kotlin 상위 수준 함수의 logger 인스턴스(이 경우 kotlin 코드에서 액세스할 수 없는 정적 Java 클래스 생성)와 같이 경우에 따라서는 매우 편리할 수 있습니다.
이 정보를 입수하기 위한 몇 가지 다른 종류가 있습니다.
new Object(){}.getClass().getEnclosingClass();
Tom Hawtin에 의해 언급 - 태클라인getClassContext()[0].getName();
SecurityManager
Christofer가 지적한new Throwable().getStackTrace()[0].getClassName();
루드비히 백작에 의하면Thread.currentThread().getStackTrace()[1].getClassName();
Keksi에서멋지다
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 후후 java java java java!
MethodHandles.lookup().lookupClass();
- Android 또는 Java 6에서 이 기능이 필요한 경우 차선책을 사용할 수 있습니다.속도도 빠르지만 사용 장소마다 익명의 클래스를 만듭니다.
new Object(){}.getClass().getEnclosingClass();
한 경우, 그리고 클래스로 인해 오르는 것을 않는 :
SecurityManager
친구(제3의 선택지)입니다.하지만 너 그렇다고전화만할 순 없어라고 부를 수 없습니다.
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()
예외 또는예외 또는 예외로부터에서Thread.currentThread()
매우 비효율적이며 클래스 이름만 반환할 수 있습니다.String
,,가지 않아니라Class<*>
사례.사례.
추신.
static kotlin utils용으로 로거인스턴스를 작성하는 경우 다음 도우미를 사용할 수 있습니다.
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
그리고 커피를 뛰어!
* 낄낄거리다
이를 사용하여 클래스 맨 위에 있는 Log4j Logger를 초기화하거나 주석을 달 수 있습니다.
PRO: 던질 수 있는 파일이 이미 로드되어 있으므로 "를 사용하지 않으면 리소스를 절약할 수 있습니다.I/O가 많은" Security Manager.
반대: 이것이 모든 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());
Security Manager 남용
System.getSecurityManager().getClassContext()[0].getName();
또는 설정되지 않은 경우 이를 확장하는 내부 클래스를 사용합니다(아래 예에서는 Real의 HowTo에서 수치스럽게 복사).
public static class CurrentClassGetter extends SecurityManager {
public String getClassName() {
return getClassContext()[1].getName();
}
}
패키지 이름 전체를 포함하려면 다음 번호로 문의하십시오.
String name = MyClass.class.getCanonicalName();
마지막 요소만 필요한 경우 다음 연락처로 문의하십시오.
String name = MyClass.class.getSimpleName();
같은 호출자의 클래스의Verbatim 사용이다.MyClass.class.getName()
는 실제로 작업을 수행하지만 이 클래스 이름을 필요로 하는 다수의 클래스/서브클래스에 이 코드를 전파하면 복사/복사 오류가 발생하기 쉽습니다.
그리고 Tom Hawtin의 레시피는 사실 나쁘지 않다.그냥 올바른 방법으로 요리하면 된다:)
서브클래스에서 호출할 수 있는 스태틱메서드를 가진 베이스 클래스가 있고, 이 스태틱메서드가 실제 발신자 클래스를 인식할 필요가 있는 경우는, 다음과 같이 됩니다.
class BaseClass {
static sharedStaticMethod (String callerClassName, Object... otherArgs) {
useCallerClassNameAsYouWish (callerClassName);
// and direct use of 'new Object() { }.getClass().getEnclosingClass().getName()'
// instead of 'callerClassName' is not going to help here,
// as it returns "BaseClass"
}
}
class SubClass1 extends BaseClass {
static someSubclassStaticMethod () {
// this call of the shared method is prone to copy/paste errors
sharedStaticMethod (SubClass1.class.getName(),
other_arguments);
// and this call is safe to copy/paste
sharedStaticMethod (new Object() { }.getClass().getEnclosingClass().getName(),
other_arguments);
}
}
리팩터링 안전, 컷 앤 페이스트 안전 솔루션.아래의 애드혹클래스의 정의를 회피합니다.
메서드 이름에 클래스 이름을 포함하도록 주의하면서 클래스 이름을 복구하는 정적 메서드를 작성합니다.
private static String getMyClassName(){
return MyClass.class.getName();
}
그런 다음 정적 방법으로 호출합니다.
public static void myMethod(){
Tracer.debug(getMyClassName(), "message");
}
리팩터링의 안전성은 스트링 사용을 회피함으로써 얻을 수 있으며, 발신자 메서드를 잘라내 붙여넣으면 타겟인 "MyClass2" 클래스에서 getMyClassName()을 찾을 수 없기 때문에 컷앤페이스트 안전성이 부여됩니다.
ClassName.class가 아닌 this.class와 같은 질문 이후?(이 질문은 클래스명이 아닌 클래스에 관한 것이므로 논쟁의 여지가 있다)에 대한 중복으로 표시되어 있습니다.이 답변은 여기에 게재합니다.
class MyService {
private static Class thisClass = MyService.class;
// or:
//private static Class thisClass = new Object() { }.getClass().getEnclosingClass();
...
static void startService(Context context) {
Intent i = new Intent(context, thisClass);
context.startService(i);
}
}
정의하는 것이 중요합니다.thisClass
비공개 사유:
1) 상속되지 않아야 함: 파생된 클래스는 자체 정의해야 함thisClass
또는 오류 메시지를 생성합니다.
2) 다른 클래스의 레퍼런스는 다음과 같이 실시합니다.ClassName.class
보다는ClassName.thisClass
.
와 함께thisClass
정의된 클래스 이름에 대한 접근은 다음과 같습니다.
thisClass.getName()
여러 클래스의 정적 메서드에 클래스 이름이 필요했기 때문에 다음 메서드로 JavaUtil 클래스를 구현했습니다.
public static String getClassName() {
String className = Thread.currentThread().getStackTrace()[2].getClassName();
int lastIndex = className.lastIndexOf('.');
return className.substring(lastIndex + 1);
}
도움이 되었으면 좋겠다!
나는 둘 다 이 두 가지 접근방식을 모두 사용해 왔습니다에 관한 두가지 방법이 사용되고 있다.static
그리고 그리고.non static
★★★★★★★★★★★★★★★★★★:
메인 클래스:
//For non static approach
public AndroidLogger(Object classObject) {
mClassName = classObject.getClass().getSimpleName();
}
//For static approach
public AndroidLogger(String className) {
mClassName = className;
}
클래스 이름 제공 방법:
비고정적 방법:
private AndroidLogger mLogger = new AndroidLogger(this);
정적 방법:
private static AndroidLogger mLogger = new AndroidLogger(Myclass.class.getSimpleName());
리플렉션을 사용하는 경우 Method 개체를 얻은 후 다음을 수행할 수 있습니다.
method.getDeclaringClass().getName()
Method 자체를 취득하려면 , 다음의 방법을 사용할 수 있습니다.
Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod ("method name", parameterTypes)
언급URL : https://stackoverflow.com/questions/936684/getting-the-class-name-from-a-static-method-in-java
'programing' 카테고리의 다른 글
Vue 리소스 - http 메서드를 동적으로 결정합니다. (0) | 2022.08.30 |
---|---|
CXF 또는 JAX-WS에서 생성된 웹 서비스 클라이언트에서 WSDL 위치를 지정할 필요가 없도록 하려면 어떻게 해야 합니까? (0) | 2022.08.30 |
vuex에서 상수 변수를 생성하시겠습니까? (0) | 2022.08.30 |
작업이 스토어 개체로 이동된 후 이벤트 중복이 있습니다. (0) | 2022.08.30 |
C의 버퍼 플러시 (0) | 2022.08.30 |