किसी एनोटेशन फ़ील्ड के लिए डिफ़ॉल्ट अशक्त मान सेट करने में त्रुटि


79

मुझे एक त्रुटि क्यों मिल रही है "गुण मान स्थिर होना चाहिए"। अशक्त नहीं है ???

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class<? extends Foo> bar() default null;// this doesn't compile
}

किसी को इसकी आवश्यकता क्यों होगी (संकलन या समाधान के लिए)? एक ही "कार्यक्षमता" पहले से ही द्वारा दी जाती है Class<? extends Foo> bar();
xxx593

3
क्योंकि वहाँ के रूप में कोई डिफ़ॉल्ट अब और है, क्षेत्र एनोटेशन के उपयोग में अनिवार्य हो जाता है
Donatello

जवाबों:


64

मुझे पता नहीं क्यों, लेकिन जेएलएस बहुत स्पष्ट है:

 Discussion

 Note that null is not a legal element value for any element type. 

और एक डिफ़ॉल्ट तत्व की परिभाषा है:

     DefaultValue:
         default ElementValue

दुर्भाग्य से मुझे पता चलता है कि जब आप भाषा से नहीं जुड़ते हैं तो नई भाषा की विशेषताएँ (एनम और अब एनोटेशन) में बहुत ही बेकार कम्पाइलर त्रुटि संदेश होते हैं।

संपादित करें: JSR-308 में थोड़ा सा Googleing निम्नलिखित पाया गया , जहां वे इस स्थिति में नल की अनुमति देने के लिए तर्क देते हैं:

हम प्रस्ताव पर कुछ संभावित आपत्तियों पर ध्यान देते हैं।

प्रस्ताव कुछ भी संभव नहीं बनाता है जो पहले संभव नहीं था।

प्रोग्रामर-परिभाषित विशेष मूल्य शून्य से बेहतर प्रलेखन प्रदान करता है, जिसका अर्थ हो सकता है "कोई नहीं", "असिंचित", स्वयं को शून्य, आदि।

प्रस्ताव अधिक त्रुटिपूर्ण है। एक स्पष्ट मूल्य के लिए जाँच करने की तुलना में अशक्त के खिलाफ जाँच को भूलना बहुत आसान है।

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

मुझे लगता है कि केवल अंतिम दो बिंदु "पहले स्थान पर क्यों नहीं" के लिए प्रासंगिक हैं। अंतिम बिंदु निश्चित रूप से एक अच्छा बिंदु लाता है - एक एनोटेशन प्रोसेसर को कभी भी चिंतित नहीं होना पड़ता है कि उन्हें एनोटेशन मूल्य पर एक अशक्त मिलेगा। मैं देख रहा हूं कि एनोटेशन प्रोसेसर और इस तरह के अन्य फ्रेमवर्क कोड के रूप में अधिक काम करने के लिए डेवलपर्स कोड को स्पष्ट करने के लिए उस तरह की जांच करनी होगी, बजाय इसके कि अन्य तरीके से, लेकिन यह निश्चित रूप से इसे बदलने का औचित्य साबित करने के लिए कठिन बना देगा।


67

इसे इस्तेमाल करे

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class bar() default void.class;
}

इसके लिए किसी नए वर्ग की आवश्यकता नहीं है और यह जावा में पहले से ही एक कीवर्ड है जिसका अर्थ है कुछ भी नहीं।


8
मुझें यह पसंद है। एकमात्र समस्या - मूल प्रश्न के संदर्भ में - यह है कि यह उत्तर प्रकार के मापदंडों का समर्थन Class<? extends Foo> bar() default void.null नहीं करता है : संकलन नहीं करता है।
कारीम

3
Void.class को आम तौर पर लागू नहीं किया जा सकता है: public @interface NoNullDefault {स्ट्रिंग मान () डिफ़ॉल्ट void .class; }
wjohnson

ग्रूवी के लिए यह ठीक काम करता है, यहां तक ​​कि टिप्पणियों में उल्लिखित मामलों में भी
पिशाच

LOL: कि मतलब है कुछ भी नहीं बनाम कि इसका मतलब है "कुछ भी नहीं"
एंड्रियास

55

ऐसा लगता है कि यह अवैध है, हालांकि जेएलएस इस पर बहुत फजी है।

मैंने एक मौजूदा एनोटेशन के बारे में सोचने की कोशिश करने के लिए अपनी मेमोरी को मिटा दिया, जिसमें एनोटेशन के लिए एक क्लास विशेषता थी, और इसे JAXB API से याद किया गया था:

@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER})        
public @interface XmlJavaTypeAdapter {
    Class type() default DEFAULT.class;

    static final class DEFAULT {}    
}

आप देख सकते हैं कि एक अशक्त के बराबर धारण करने के लिए उन्हें एक डमी स्थिर वर्ग को कैसे परिभाषित करना था।

अप्रिय।


3
हां, हम कुछ ऐसा ही करते हैं (हम डिफ़ॉल्ट रूप में Foo.class का उपयोग करते हैं)। चूसता है।
ripper234

7
और स्ट्रिंग फ़ील्ड्स के मामले में, आपको जादू के तारों का सहारा लेना होगा । जाहिरा तौर पर अच्छी तरह से ज्ञात एंटीपैटर्न अच्छी तरह से समझी जाने वाली भाषा सुविधाओं की तुलना में बेहतर हैं।
टिम येट्स

3
@TimYates यह मुझे देखने के लिए मारता है कि लोग अपने स्वयं के "नो वैल्यू" प्रहरी मूल्य को परिभाषित करते हैं जब अशक्त उपलब्ध होता है और सार्वभौमिक समझ में आता है। और अब यह भाषा द्वारा ही आवश्यक है ?! सौभाग्य से, आप अपने "जादू के तार" को सार्वजनिक स्थिरांक के रूप में परिभाषित कर सकते हैं। यह अभी भी आदर्श नहीं है, लेकिन कम से कम कोड जो आपके एनोटेशन की तलाश में है, हर जगह शाब्दिक का उपयोग करने के बजाय निरंतर का संदर्भ दे सकता है।
स्पाकार्की

11

ऐसा लगता है कि इसे करने का एक और तरीका है।

मुझे यह पसंद नहीं है, लेकिन यह काम कर सकता है।

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeInterface {
    Class<? extends Foo>[] bar() default {};
}

तो मूल रूप से आप इसके बजाय एक खाली ऐरे बनाते हैं। यह एक डिफ़ॉल्ट मान की अनुमति देता है।


3
Class<? extends Foo> bar() default null;// this doesn't compile

जैसा कि उल्लेख किया गया है, जावा भाषा विनिर्देश एनोटेशन डिफॉल्ट में अशक्त मूल्यों की अनुमति नहीं देता है।

मैं जो करना चाहता हूं DEFAULT_VALUEवह है एनोटेशन परिभाषा के शीर्ष पर स्थिरांक को परिभाषित करना । कुछ इस तरह:

public @interface MyAnnotation {
    public static final String DEFAULT_PREFIX = "__class-name-here__ default";
    ...
    public String prefix() default DEFAULT_PREFIX;
}

फिर मेरे कोड में मैं कुछ ऐसा करता हूं:

if (myAnnotation.prefix().equals(MyAnnotation.DEFAULT_PREFIX)) { ... }

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

public @interface MyAnnotation {
    public static Class<? extends Foo> DEFAULT_BAR = DefaultBar.class;
    ...
    Class<? extends Foo> bar() default DEFAULT_BAR;
}

आपकी DefaultFooकक्षा केवल एक खाली कार्यान्वयन होगी ताकि कोड कर सकें:

if (myAnnotation.bar() == MyAnnotation.DEFAULT_BAR) { ... }

उम्मीद है की यह मदद करेगा।


संयोग से, मैंने सिर्फ एक स्ट्रिंग के साथ यह कोशिश की, और यह काम नहीं करता है। आप एक ही स्ट्रिंग वस्तु वापस नहीं मिलता है।
डोरैडस

आपने @Doradus का उपयोग किया .equals()और नहीं ==? क्या आपको एक अलग मूल्य या एक अलग वस्तु मिली ।
ग्रे

अलग वस्तु। मैंने इस्तेमाल किया ==
डोरैडस

वैसे क्लास एक सिंगलटन @ डोरैडस है। मैंने स्ट्रिंग को एक सिंगलटन होने की उम्मीद की होगी, लेकिन मुझे लगता है कि यह नहीं है और आपको उपयोग करने की आवश्यकता होगी .equals()। चौंका देने वाला।
ग्रे

1

यह त्रुटि संदेश भ्रामक है, लेकिन, नहीं, nullशाब्दिक एक स्थिर अभिव्यक्ति नहीं है, जैसा कि जावा भाषा विनिर्देश में परिभाषित किया गया है, यहां

इसके अलावा, जावा लैंग्वेज स्पेसिफिकेशन कहता है

यह एक संकलित-समय की त्रुटि है यदि तत्व का प्रकार निर्दिष्ट डिफ़ॉल्ट मान के साथ कम्यूटेट (.79.7) नहीं है

और यह समझाने के लिए कि इसका क्या मतलब है

यदि तत्व प्रकार तत्व मान के अनुरूप नहीं है तो यह एक संकलन-समय त्रुटि है। एक तत्व प्रकार T एक तत्व मान के साथ V है और यदि केवल निम्न में से कोई एक सत्य है:

  • T एक सरणी प्रकार है E[] , और या तो:
    • [...]
  • Tएक सरणी प्रकार नहीं है , और Vअसाइनमेंट का प्रकार ()5.2) संगत है T, और :
    • यदि Tएक आदिम प्रकार है या String, तो Vएक स्थिर अभिव्यक्ति है (.215.28)।
    • अगर Tहै Classया की एक मंगलाचरण Class(§4.5), तोV एक वर्ग शाब्दिक (§15.8.2) है।
    • यदि Tएक एनुम प्रकार (.98.9) है, तो Vएक एनम स्थिरांक (en8.9.1) है।
    • V शून्य नहीं है

तो यहां, आपका तत्व प्रकार, Class<? extends Foo>डिफ़ॉल्ट मान के अनुरूप नहीं है, क्योंकि वह मान है null


आपका समाधान कॉपी और पेस्ट के लिए उपयुक्त नहीं है ;-) कुछ सोचकर पसंद नहीं करते, जब पढ़ते हैं
Matthias M

1
IMHO हाँ, आपने (लेकिन यह मुझे नहीं था)। आपकी अभिव्यक्ति "जब (...) या (शून्य नहीं है)" की तरह पढ़ती है , जो किसी भी गैर-शून्य मान की तरह लगता है सही होगा। JLS सूत्रीकरण एक वास्तविक जानवर है, लेकिन एक बाहरी orऔर एक आंतरिक है and, जिसे बाहर नहीं छोड़ा जा सकता है।
माआर्टिनस

@maaartinus ने बहुत समय पहले आपकी टिप्पणी नहीं देखी थी, पूरे उद्धरण को जोड़ने के लिए मेरे उत्तर को अपडेट किया।
सोतीरियोस डेलिमोलिस

1

जैसा कि दूसरों ने कहा है, एक नियम है जो कहता है कि शून्य जावा में मान्य डिफ़ॉल्ट मान नहीं है।

यदि आपके पास सीमित संख्या में संभावित मान हैं, जो क्षेत्र में हो सकते हैं , तो इसके लिए काम करने का एक विकल्प यह है कि फ़ील्ड प्रकार को कस्टम एनम बनाया जाए जिसमें स्वयं एक नल शामिल है। उदाहरण के लिए, कल्पना करें कि मेरे पास निम्नलिखित एनोटेशन है जिसके लिए मुझे एक डिफ़ॉल्ट अशांति चाहिए:

public @interface MyAnnotation {
   Class<?> value() default null;
}

जैसा कि हमने स्थापित किया है, इसकी अनुमति नहीं है। इसके बजाय हम क्या कर सकते हैं परिभाषित करना है:

public enum MyClassEnum {
    NULL(null),
    MY_CLASS1(MyClass1.class),
    MY_CLASS2(MyClass2.class),
    ;

    public final Class<?> myClass;

    MyClassEnum(Class<?> aClass) {
        myClass = aClass;
    }
}

और एनोटेशन को इस तरह बदलें:

public @interface MyAnnotation {
  MyClassEnum value() default MyClassEnum.NULL;
}

इसका मुख्य नकारात्मक पहलू (आपके संभावित मूल्यों को मानने की आवश्यकता से) यह है कि आपने अब अपने मान को एनम में लपेट लिया है, इसलिए आपको मान प्राप्त करने के लिए एनम पर संपत्ति / प्राप्तकर्ता को आमंत्रित करना होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.