সুতরাং, আমাদের এমন একটি পরিস্থিতি রয়েছে যখন আমাদের স্ট্যাটিকভাবে MyClass.class
সিনট্যাক্সের স্পষ্ট ব্যবহার ছাড়াই ক্লাস অবজেক্ট বা শ্রেণীর পুরো / সাধারণ নামটি পেতে হবে ।
এটি কিছু ক্ষেত্রে সত্যিই সুবিধাজনক হতে পারে, যেমন: লগারের উদাহরণটি kotlin উচ্চ স্তরের ফাংশন (এই ক্ষেত্রে কোটলিন একটি স্ট্যাটিক জাভা ক্লাস তৈরি করে যা কোটলিন কোড থেকে অ্যাক্সেসযোগ্য নয়)।
এই তথ্যটি পাওয়ার জন্য আমাদের কয়েকটি পৃথক রূপ রয়েছে:
new Object(){}.getClass().getEnclosingClass();
টম হাটিন
দ্বারা উল্লিখিত - ট্যাকলাইন
getClassContext()[0].getName();
ক্রিস্টোফারSecurityManager
দ্বারা উল্লিখিত থেকে
new Throwable().getStackTrace()[0].getClassName();
গণনা
দ্বারা ludwig
Thread.currentThread().getStackTrace()[1].getClassName();
কেকসি
থেকে
এবং অবশেষে রেইন
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
উপসংহার
- ব্যবহারের জন্য সেরা বৈকল্পিক , বরং পরিষ্কার এবং মারাত্মকভাবে দ্রুত।
কেবল জাভা 7 এবং অ্যান্ড্রয়েড এপিআই 26 এর পরে উপলব্ধ!
MethodHandles.lookup().lookupClass();
- আপনার যদি অ্যান্ড্রয়েড বা জাভা 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()
ব্যতিক্রম বা এর উপর ভিত্তি করে আপনার সম্ভবত শেষ দুটি রূপগুলি ব্যবহার করার দরকার নেই Thread.currentThread()
। খুব অদক্ষ এবং শুধুমাত্র হিসাবে শ্রেণীর নাম ফিরে আসতে পারেString
, Class<*>
উদাহরণ নয়।
পুনশ্চ
আপনি যদি স্থির কোটলিন ব্যবহারের জন্য লগার উদাহরণ তৈরি করতে চান (আমার মতো :), আপনি এই সহায়কটি ব্যবহার করতে পারেন:
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();
}