ดังนั้นเราจึงมีสถานการณ์เมื่อเราจำเป็นต้องรับคลาสอ็อบเจ็กต์หรือชื่อเต็ม / คลาสแบบง่ายโดยไม่มีการใช้MyClass.class
ไวยากรณ์อย่างชัดเจน
มันมีประโยชน์จริงๆในบางกรณีเช่นอินสแตนซ์คนตัดไม้ของ Kotlin ฟังก์ชั่นระดับบน (ในกรณีนี้ kotlin สร้างคลาส Java แบบคงที่ไม่สามารถเข้าถึงได้จากรหัส kotlin)
เรามีตัวแปรที่แตกต่างกันเล็กน้อยในการรับข้อมูลนี้:
new Object(){}.getClass().getEnclosingClass();
บันทึกโดยTom Hawtin - tackline
getClassContext()[0].getName();
จากSecurityManager
บันทึกของChristoffer
new Throwable().getStackTrace()[0].getClassName();
โดยนับลุดวิก
Thread.currentThread().getStackTrace()[1].getClassName();
จากKeksi
และในที่สุดก็ยอดเยี่ยม
MethodHandles.lookup().lookupClass();
จากRein
ฉันได้เตรียม 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();
ถ้าคุณต้องการมันในหลาย ๆ ที่และไม่ต้องการให้ bytecode ของคุณขยายตัวเนื่องจากมีคลาสนิรนามมากมาย - 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()
ไม่มีประสิทธิภาพมากและสามารถส่งกลับเฉพาะชื่อคลาสเป็น a ไม่ใช่อินสแตนซ์Thread.currentThread()
String
Class<*>
PS
หากคุณต้องการสร้างอินสแตนซ์คนตัดไม้สำหรับ utlet 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
}
try{ throw new RuntimeEsception();} catch(RuntimeEcxeption e){return e.getstackTrace()[1].getClassName();
}