जावा में स्थैतिक विधि से getClass () कैसे कॉल करें?


350

मेरे पास एक वर्ग है जिसमें कुछ स्थिर तरीके होने चाहिए। इन स्थिर तरीकों के अंदर मुझे निम्न कॉल करने के लिए विधि getClass () को कॉल करने की आवश्यकता है:

public static void startMusic() {
  URL songPath = getClass().getClassLoader().getResource("background.midi");
}

हालाँकि ग्रहण मुझे बताता है:

Cannot make a static reference to the non-static method getClass() 
from the type Object

इस संकलन समय त्रुटि को ठीक करने का उपयुक्त तरीका क्या है?


का उपयोग getResource()करने से पहले वहाँ एक उपयोगकर्ता परिभाषित का एक उदाहरण है (उदाहरण के लिए गैर J2SE) वर्ग कभी कभी असफल हो जायेगी। समस्या यह है कि JRE उस स्तर पर बूटस्ट्रैप क्लास-लोडर का उपयोग कर रहा होगा, जिसमें क्लास-पथ (बूटस्ट्रैप लोडर) पर अनुप्रयोग संसाधन नहीं होंगे।
एंड्रयू थॉम्पसन

जवाबों:


617

उत्तर

के TheClassName.classबजाय का उपयोग करें getClass()

लकड़हारे की घोषणा

चूँकि यह एक विशिष्ट usecase के लिए इतना ध्यान जाता है - लॉग घोषणाओं को सम्मिलित करने का एक आसान तरीका प्रदान करने के लिए - मैंने सोचा कि मैं उस पर अपने विचार जोड़ूंगा। लॉग फ्रेमवर्क अक्सर उम्मीद करते हैं कि लॉग को एक निश्चित संदर्भ के लिए विवश किया जा सकता है, एक पूरी तरह से योग्य वर्ग नाम कहते हैं। इसलिए वे संशोधन के बिना कॉपी-पेस्टेबल नहीं हैं। पेस्ट-सुरक्षित लॉग घोषणाओं के सुझाव अन्य उत्तरों में दिए गए हैं, लेकिन उनके पास डाउनसाइड्स हैं जैसे कि बाईटेकोड को फुलाकर या रनटाइम आत्मनिरीक्षण जोड़ना। मैं इनकी सिफारिश नहीं करता। कॉपी-पेस्ट एक संपादक की चिंता है, इसलिए एक संपादक समाधान सबसे उपयुक्त है।

IntelliJ में, मैं एक लाइव टेम्पलेट जोड़ने की सलाह देता हूं:

  • संक्षिप्त नाम के रूप में "लॉग" का उपयोग करें
  • private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class);टेम्प्लेट टेक्स्ट के रूप में उपयोग करें ।
  • एडिट वेरिएबल्स पर क्लिक करें और एक्सप्रेशन का उपयोग करके CLASS जोड़ें className()
  • सुधार करने के लिए बक्से की जाँच करें और FQ नामों को छोटा करें।
  • संदर्भ को जावा में बदलें: घोषणा।

अब यदि आप टाइप log<tab>करते हैं तो यह अपने आप विस्तार हो जाएगा

private static final Logger logger = LoggerFactory.getLogger(ClassName.class);

और स्वचालित रूप से आपके लिए आयात का सुधार और अनुकूलन करता है।


6
यह एक अलग कक्षा में गलत कोड चलने पर कॉपी / पेस्ट और दु: खद परिणाम देगा।
विलियम एंट्रीकेन

1
@WilliamEntriken: अनाम आंतरिक वर्गों का उपयोग करना एक महान समाधान नहीं है, यह सिर्फ डेवलपर प्रयास के एक दो सेकंड को बचाने के लिए अतिरिक्त क्लासफाइल्स के साथ आपके बाईटकोड को खिलता है। मुझे यकीन नहीं है कि लोग क्या कर रहे हैं, जहां उन्हें हर जगह कॉपी / पेस्ट करना है, लेकिन इसे एक संपादक समाधान के साथ व्यवहार किया जाना चाहिए, न कि एक भाषा हैक के साथ। जैसे अगर IntelliJ का उपयोग करते हैं, तो एक लाइव टेम्पलेट का उपयोग करें जो क्लासनाम को सम्मिलित कर सकता है।
मार्क पीटर्स

"मुझे यकीन नहीं है कि लोग क्या कर रहे हैं, जहां उन्हें हर जगह कॉपी / पेस्ट करना पड़ता है" - जैसे कि Logएंड्रॉइड में उपयोग करना , जिसके लिए एक टैग की आवश्यकता होती है, आमतौर पर वर्ग का नाम। और शायद अन्य उदाहरण भी हैं। बेशक आप उसके लिए एक क्षेत्र घोषित कर सकते हैं (जो कि आम बात है), लेकिन वह अभी भी कॉपी और पेस्ट है।
user149408

@ user149408: हाँ, इस बारे में बहुत बात की गई है। हालाँकि इस usecase का वास्तव में मूल प्रश्न से कोई लेना-देना नहीं था, फिर भी यह एक सामान्य कारण है कि लोग इस प्रश्न पर जाते हैं इसलिए मैंने उत्तर में कुछ विचार जोड़े हैं।
मार्क पीटर्स

1
आप अपने लाइव टेम्प्लेट समाधान में एक बात भूल गए: "एडिट वेरिएबल्स" पर क्लिक करें और एक्सप्रेशन CLASSइन टाइप फॉर className()। यह सुनिश्चित करेगा कि $ CLASS $ वास्तव में वर्ग नाम के साथ बदल दिया गया है, अन्यथा यह सिर्फ खाली निकलेगा।
हर्बसीएसओ

122

प्रश्न में कोड उदाहरण के लिए, मानक समाधान अपने नाम से वर्ग को स्पष्ट रूप से संदर्भित करना है, और इसके बिना यह करना भी संभव है getClassLoader():

class MyClass {
  public static void startMusic() {
    URL songPath = MyClass.class.getResource("background.midi");
  }
}

इस दृष्टिकोण का अभी भी एक पक्ष है कि यह कॉपी / पेस्ट त्रुटियों के खिलाफ बहुत सुरक्षित नहीं है यदि आपको इस कोड को कई समान वर्गों को दोहराने की आवश्यकता है।

और हेडलाइन में सटीक प्रश्न के लिए, आसन्न धागे में एक ट्रिक पोस्ट की गई है :

Class currentClass = new Object() { }.getClass().getEnclosingClass();

यह Objectनिष्पादन के संदर्भ को पकड़ने के लिए एक नेस्टेड अनाम उपवर्ग का उपयोग करता है । इस ट्रिक में कॉपी / पेस्ट सुरक्षित होने का एक फायदा है ...

बेस क्लास में इसका उपयोग करते समय सावधानी बरतें कि अन्य वर्ग इनसे विरासत में मिले:

यह भी ध्यान देने योग्य है कि यदि इस स्निपेट को कुछ आधार वर्ग की स्थिर विधि के रूप में आकार दिया जाता है, तो currentClassमूल्य हमेशा उस आधार वर्ग के संदर्भ में होगा, बजाय किसी उपवर्ग के जो उस पद्धति का उपयोग कर रहा हो सकता है।


23
अब तक मेरा पसंदीदा जवाब। NameOfClass.class स्पष्ट है, लेकिन इसके लिए आपको अपनी कक्षा का नाम जानना आवश्यक है। GetEnclosingClass ट्रिक कॉपी-पेस्टिंग के लिए सिर्फ उपयोगी नहीं है, स्थैतिक आधार वर्ग विधियों के लिए भी उपयोगी है जो आत्मनिरीक्षण का उपयोग करते हैं
डोमिंगो इग्नासियो

1
संयोग Class.getResource()से थोड़ा अलग व्यवहार कर सकते हैं ClassLoader.getResource(); देखें stackoverflow.com/a/676273
19

68

Java7 + में आप इसे स्टैटिक मेथड्स / फील्ड्स में कर सकते हैं:

MethodHandles.lookup().lookupClass()

अच्छा समाधान अगर आपको केवल मुख्य विधि से सहायता प्रिंट करने के लिए getSimpleName () कॉल की आवश्यकता है ।
दिमित्री बुल्शेविच

6
मैं हर बार लकड़हारा जोड़ने के लिए एक 'कॉपी पेस्ट' समाधान की तलाश कर रहा था, हर बार कक्षा का नाम बदले बिना। आपने इसे मुझे दिया: private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
जुलिएन फेनीउ

सबसे अच्छा समाधान जहां यह समर्थित है, खामी यह है कि एंड्रॉइड एपीआई 26 तक इसका समर्थन नहीं करता है, यानी एंड्रॉइड 8.
user149408

24

मैंने खुद इसके साथ कुश्ती की। स्थिर संदर्भ में क्लास-बॉलर प्राप्त करने के लिए वर्तमान थ्रेड का उपयोग करने के लिए एक अच्छी चाल है। यह एक Hadoop MapReduce में भी काम करेगा। अन्य तरीके स्थानीय रूप से चलने पर काम करते हैं, लेकिन MapReduce में उपयोग किए जाने पर एक अशक्त इनपुटस्ट्रीम वापस करते हैं।

public static InputStream getResource(String resource) throws Exception {
   ClassLoader cl = Thread.currentThread().getContextClassLoader();
   InputStream is = cl.getResourceAsStream(resource);
   return is;
}


11

getClass() विधि को निम्न हस्ताक्षर के साथ ऑब्जेक्ट क्लास में परिभाषित किया गया है:

सार्वजनिक अंतिम वर्ग getClass ()

चूंकि इसे परिभाषित नहीं किया गया है static, आप इसे स्थिर कोड ब्लॉक के भीतर नहीं कह सकते। अधिक जानकारी के लिए ये उत्तर देखें: Q1 , Q2 , Q3

यदि आप एक स्थिर संदर्भ में हैं, तो आपको कक्षा प्राप्त करने के लिए वर्ग शाब्दिक अभिव्यक्ति का उपयोग करना होगा, इसलिए आपको मूल रूप से ऐसा करना होगा:

Foo.class

इस प्रकार की अभिव्यक्ति को क्लास लिटरल कहा जाता है और उन्हें जावा लैंग्वेज स्पेसिफिकेशन बुक में बताया गया है:

एक वर्ग शाब्दिक एक वर्ग, इंटरफ़ेस, सरणी, या आदिम प्रकार के नाम से युक्त एक अभिव्यक्ति है, जिसके बाद एक `'है। और टोकन वर्ग। वर्ग शाब्दिक का प्रकार वर्ग है। यह नाम प्रकार (या शून्य के लिए) के लिए वर्ग वस्तु का मूल्यांकन करता है जैसा कि वर्तमान उदाहरण के वर्ग के परिभाषित कक्षा लोडर द्वारा परिभाषित किया गया है।

आप क्लास के लिए एपीआई प्रलेखन पर इस विषय के बारे में भी जानकारी पा सकते हैं ।


9

कोशिश करो

Thread.currentThread().getStackTrace()[1].getClassName()

या

Thread.currentThread().getStackTrace()[2].getClassName()

इस दृष्टिकोण की सुंदरता यह है कि यह 8 (एपीआई 26) से पहले एंड्रॉइड संस्करणों पर भी काम करेगा। इस बात से सावधान रहें कि इंडेक्स [1]सभी लॉग संदेशों को Threadएंड्रॉइड 4.4.4 पर उनके स्रोत के रूप में रिपोर्ट करेगा । [2]Android और OpenJRE दोनों पर सही परिणाम देता है।
user149408

0

मान लीजिए कि एक उपयोगिता वर्ग है, तो नमूना कोड होगा -

    URL url = Utility.class.getClassLoader().getResource("customLocation/".concat("abc.txt"));

CustomLocation - यदि संसाधनों के भीतर कोई फ़ोल्डर संरचना अन्यथा इस स्ट्रिंग शाब्दिक को हटा दें।


-2

कुछ इस तरह की कोशिश करो। इससे मेरा काम बनता है। लोगो (कक्षा का नाम)

    String level= "";

    Properties prop = new Properties();

    InputStream in =
            Logg.class.getResourceAsStream("resources\\config");

    if (in != null) {
        prop.load(in);
    } else {
        throw new FileNotFoundException("property file '" + in + "' not found in the classpath");
    }

    level = prop.getProperty("Level");

1
सुनिश्चित नहीं हैं कि आप एक ही जवाब क्यों दे रहे हैं जो पहले से ही इस धागे में तीन बार है: 2011 से दो बार, 2013 से एक बार।
Antares42

यह समाधान काम करता है यदि क्लास लॉगग को "संसाधन \\ कॉन्फ़िगर" फ़ोल्डर तक पहुंच के साथ क्लास लोडर द्वारा लोड किया गया है। कुछ सर्वरों पर, जिनमें कई क्लास लोडर होते हैं (उदाहरण के लिए एक क्लास लोडर लिब फोल्डर को लोड करने के लिए और दूसरा ऐप लिबास और रिसोर्स लोड करने के लिए), यह सच नहीं है। उस कारण से, इस जवाब पर समाधान केवल संयोग से कभी-कभी काम करता है!
मैनुअल रोमेरो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.