2015-06-11 3 views
5

में कैद रूपांतरण को देखते हुए निम्न दो वर्ग परिभाषाएँ:Parameterization खैर प्रकार से निर्मित और जावा

class C1<T extends C1<T>> {} 

class C2<U> extends C1<C2<U>> {} 

और निम्नलिखित प्रकार घोषणा:

C1<C2<?>> a; 

Intuitively यह घोषित प्रकार a लगता है मान्य होना चाहिए लेकिन जेडीके -8u45 व्यवहार नहीं करता है। इसके बजाय हम निम्नलिखित उत्पादन की तरह कुछ मिलता है:

Test.java:3: error: type argument C2<?> is not within bounds of type-variable T 
     C1<C2<?>> a; 
      ^
    where T is a type-variable: 
    T extends C1<T> declared in class C1 
1 error 

(संपादित करें: मैं एक dingus यहाँ किया जा रहा था, इस हिस्से उत्तर दिया गया है: C2<?>C1<C2<?>> का विस्तार नहीं करता नीचे c की घोषणा के बारे में मुद्दा। अभी भी एक खुला सवाल है, हालांकि है।)

लेकिन C2<?> का विस्तार करता है C1<C2<?>>, जो तुच्छता से बाध्य को पूरा करने के प्रदर्शित होगी। JLS की परीक्षा अब तक कोई और रोशनी प्रदान नहीं करती है जैसा कि मैं देख सकता हूं। यह वास्तव में उपप्रकार संबंध द्वारा बाध्यता को संतुष्ट करने के समान सरल होना चाहिए, क्योंकि C2<?> वाइल्डकार्ड प्रकार नहीं है और इसलिए रूपांतरण पर कब्जा केवल तर्क पर एक पहचान रूपांतरण है।

स्थितियों में, जहां यह उदाहरण के लिए थोड़ा कम स्पष्ट हो जाता है, कर रहे हैं, ले निम्नलिखित वर्ग परिभाषाएँ:

class C3<T extends C3<?>> {} 

class C4<Y, Z> extends C3<C4<Z, Y>> {} 

class C5<X extends C3<X>> { 
    void accept(X x); 
} 

यह सब है ठीक है, लेकिन फिर अगर हम निम्नलिखित घोषणा की कोशिश:

C5<C6<?, ?>> b; 

चीजें अजनबी बन गईं। C6<?, ?>C3<C6<?, ?>> का एक उप प्रकार है, इसलिए घोषणापत्र C1<C2<?>> घोषणा के संबंध में ऊपर दिए गए विनिर्देश की मेरी व्याख्या के अनुसार मान्य होना चाहिए। समस्या स्पष्ट रूप से नहीं C6<?, ?> के हर संभव उप प्रकार वास्तव में संतुष्ट करता है कि उस बाध्य है, इसलिए अब उदाहरण C5.accept() के लिए अपने पैरामीटर प्रकार C6<?, ?> को हल करता है और इसलिए तर्क जो X पर सीमांकन का उल्लंघन, यानी किसी भी जहां Y और Z की parameterizations नहीं स्वीकार कर सकते हैं है समान।

मैं यहां गलत कहां जा रहा हूं? क्या उपप्रकार संबंध की मेरी समझ अपर्याप्त है?

(संपादित करें: प्रश्न के निम्नलिखित हिस्सा अभी भी अनुत्तरित है, लेकिन मैं इसे एक नया सवाल here क्योंकि यह एक पूरी तरह से अलग मुद्दा वास्तव में है ... एक मेस बनाने और साइट का उपयोग नहीं करने के लिए क्षमा करें करने के लिए स्थानांतरित कर दिया है बहुत अच्छी हाहा ...)

इसके अलावा, मुझे इसी तरह की स्थितियों में रूपांतरण को पकड़ने में कुछ समस्याएं भी हैं। निम्नलिखित प्रकार घोषणा लें: शुरू में समान घोषणा a विपरीत

C1<? extends C2<?>> c; 

, इस JDK-8u45 में ठीक संकलित करता है। यदि हम specification for capture conversion की जांच करते हैं, हालांकि, ऐसा लगता है कि यह घोषणा परिणामस्वरूप इस समय संकलित समय त्रुटि में होनी चाहिए।

विशेष रूप से, नए प्रकार के चर पर कब्जा CAP#T इस मामले Bi में glb(Bi, Ui[A1:=S1,...,An:=Sn]), जहां द्वारा दिया जाता है की ऊपरी सीमा को हल करता है करने के लिए वाइल्डकार्ड बाध्य C2<?> और Ui[A1:=S1,...,An:=Sn]C1<CAP#T> को हल करता है।

इस से, glb(C2<?>, C1<CAP#T>) चौराहे प्रकार C2<?> & C1<CAP#T> है, जो अवैध है, क्योंकि C2<?> और C1<CAP#T>, दोनों वर्ग प्रकार के होते हैं प्रकार के इंटरफेस नहीं ले कर जाता है, लेकिन उनमें से कोई भी एक दूसरे के एक उप-प्रकार है।

यह (स्पष्ट) नियम उल्लंघन definition of the intersection type में स्वयं को और स्पष्ट कर दिया गया है।

मुझे यकीन है कि यह एक बग नहीं है कर रहा हूँ और मैं बस कुछ सरल गलतियों कहीं बना रही हूँ ... लेकिन यहाँ कोई भी मेरे लिए यह पर किसी भी प्रकाश डाला सकता है अगर मैं संकलक-देव मेलिंग सूची या कुछ और की कोशिश करेंगे।

किसी भी मदद के लिए धन्यवाद!

+0

यह एक आकर्षक मुद्दा है। मैं सिर्फ उत्सुक हूं, क्या यह आपके पास कुछ सैद्धांतिक समस्या है या क्या आपके पास इसके लिए कुछ वास्तविक विश्व कक्षाएं हैं? मैं तो बस जहां एक का प्रयोग करेंगे कल्पना नहीं कर सकते 'वर्ग सी 1 <टी फैली सी 1 > {}' या 'वर्ग सी 2 फैली सी 1 > {}'। – Kris

+0

मान्य सवाल! मेरे पास इस विशेष मुद्दे का कोई विशिष्ट वास्तविक विश्व अनुप्रयोग नहीं है ... लेकिन मुझे * अपेक्षित व्यवहार को समझने की आवश्यकता है, क्योंकि मैं टाइप सिस्टम पर प्रतिबिंबित उपयोगिताओं का एक गुच्छा लिख ​​रहा हूं और व्यवहार को spec/JDK। वर्तमान में यह ज्यादातर काम कर रहा है, जिसमें जेनेरिक विधि आमंत्रण के प्रकार अनुमान शामिल हैं, लेकिन कुछ किनारे के मामले हैं (इस तरह) जो मुद्दों का कारण बनता है। यदि आप इसे देखना चाहते हैं तो इसे यहां होस्ट किया गया है: https://github.com/StrangeSkies/uk.co.strangeskies। अभी तक कोई विकी नहीं है, लेकिन javadocs सभी '.reflection' पैकेज के लिए मौजूद हैं। –

+0

यह वास्तव में कैप्चर रूपांतरण के साथ बहुत कम करने के लिए है। इसके बजाय, आपको उत्तर के लिए 4.10.2 और 4.5.1 में देखना चाहिए। जब तक आप इसे कैप्चर रूपांतरण से संबंधित मानते हैं, तब तक आपको गुमराह किया जा रहा है। उदाहरण के लिए, क्यों आपका कारण 'सी 1 बढ़ाता है> 'संकलन नहीं करना चाहिए बकवास है। (मुझे लगता है कि यह भी गलत है, मुझे नहीं लगता कि एक चौराहे प्रकार यदि कब्जा रूपांतरण * * लागू किया गया है, क्योंकि [कब्जा रूपांतरण रिकर्सिवली लागू नहीं किया जा होगा] है (http://stackoverflow.com/a/30385343/2891664) लेकिन मैं बस जाग गया, इसलिए मैं थोड़ी गड़बड़ी कर रहा हूं।) – Radiodef

उत्तर

3

जबकि किसी भी संदर्भ प्रकार x के लिए
C2<x> extends C1<C2<x>>,
यह मामला है कि
C2<?> extends C1<C2<?>>

किसी वाइल्डकार्ड ?नहीं एक प्रकार है नहीं है। यह प्रकार तर्क है। हालांकि वाक्यविन्यास बहुत धोखा दे रहा है (डिजाइन द्वारा)।

चलिए एक अलग वाक्यविन्यास का उपयोग करते हैं - यदि कोई प्रथम स्तर का वाइल्डकार्ड है, तो के बजाय {} का उपयोग करें, उदा।

List{?}, Map{String, ? extends Number} 

{?} का अर्थ एक संघ प्रकार

List{? extends Number} == union of List<Number>, List<Integer>, List<Long>, .... 

ऐसा नहीं है कि देखना आसान है, List<Integer>List{? extends Number} की एक उप-प्रकार है घोषित करने के लिए है, और
List{? extends Number}, List{? extends Object}

हालांकि की एक उप-प्रकार है कोई रास्ता नहीं है कि Foo{?} एक Foo<x> की एक उप-प्रकार है।


हमारे वाक्य रचना में, <> प्रकार प्रतिस्थापन के लिए आरक्षित है प्रकार साथ वार्स। इसलिए हम
List<String>, C2<Integer> लिखते हैं, आदि यह उनके अर्थ को समझने में आसान है - बस List के स्रोत कोड में String साथ T की जगह ले, हम एक अच्छे पुराने सादे वर्ग मिलता है।

interface List<String> 
     String get(int) 

यह वाइल्डकार्ड के लिए नहीं किया जा सकता है - यह कोई मतलब नहीं

interface List<?> 
     ? get(int) 

तो यह new ArrayList{?}() की अनुमति नहीं है, या class MyList implements List{?}

तो, हम List{?} का उपयोग कर सकते है?हम किस तरीके पर कॉल कर सकते हैं?

जब एक अभिव्यक्ति के प्रकार के एक List{?} है, हम जानते हैं कि यह एक वस्तु है, और वस्तु किसी अज्ञात प्रकारx के लिए List<x> का एक उपवर्ग से संबंधित होना चाहिए। यह वाइल्डकार्ड कब्जा

obj is a List{?} => obj is a List<x>, where x a subtype of Object. 

हालांकि x का सही प्रकार संकलन समय पर अज्ञात है, हम अभी भी प्रतिस्थापन

interface List<x> 
     x get(int) 

तो हम कॉल obj.get(0) का मतलब कर सकते हैं कर सकते हैं; यह x देता है, और xObject का उप प्रकार है; इसलिए हम वापसी मान को Object पर असाइन कर सकते हैं।

+0

आह हाँ, ठीक है आप हैं, यह मेरे हिस्से पर एक मस्तिष्क गोज़ का थोड़ा सा था। बहुत बहुत धन्यवाद! 'सी 1 <पर कोई विचार?सी 2 > सी; 'ऊपरी बाउंड पर चौराहे प्रकार के साथ मुद्दा बढ़ाता है? मुझे लगता है कि थोड़ा और मुश्किल हो सकता है, लेकिन शायद नहीं ... –

+0

मैंने प्रश्न का दूसरा भाग एक नए प्रश्न में डाल दिया है, इसलिए मैं सिर्फ आपके उत्तर को सही के रूप में चिह्नित कर सकता हूं और सभी क्रुफ्ट से छुटकारा पा सकता हूं, क्योंकि दूसरा भाग मूल रूप से एक पूरी तरह से अलग मुद्दा है। नया सवाल यहां है: http://stackoverflow.com/questions/30788366/capture-conversion-issue-in-java-wrt-reconciliation-of-jls-and-actual-jdk-behav –

संबंधित मुद्दे