2013-06-07 12 views
7

पारित तर्कों के लिए लागू नहीं है मेरे पास जावा जेनरिक के बारे में "अजीब" समस्या है।जावा जेनेरिक क्लास की विधि

Service.class

package jse.generics.service; 

public interface Service { 

} 

ServiceProvider.class

package jse.generics.service; 

public interface ServiceProvider<T extends Service> { 

    public T getService(); 
} 

ServiceProviderRegistry.class

:

सबसे पहले मैं अपने कोड की सूची

package jse.generics.service; 

import java.util.HashMap; 
import java.util.Map; 

public class ServiceProviderRegistry<T extends Service> { 

    private Map<Class<T>, ServiceProvider<T>> map = new HashMap<Class<T>, ServiceProvider<T>>(); 

    public void register(Class<T> clazz, ServiceProvider<T> provider) { 
      map.put(clazz, provider); 
    } 
} 

FooService.class

package jse.generics.service; 

public class FooService implements Service { 

} 

FooServiceProvider.class

package jse.generics.service; 

public class FooServiceProvider implements ServiceProvider<FooService> { 

    @Override 
    public FooService getService() { 
      return new FooService(); 
    } 

} 

ServiceTest.class

package jse.generics.service; 

public class ServiceTest { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
      ServiceProviderRegistry<? extends Service> registry = new ServiceProviderRegistry<Service>(); 
      registry.register(FooService.class, new FooServiceProvider()); 
    } 

} 

सर्विसटेस्ट क्लास में संकलक शिकायतें कि रजिस्ट्री.register विधि इसे पास किए गए तर्कों के लिए लागू नहीं है। मुझे नहीं पता कि ऐसा क्यों होता है। इसलिए मैं इस समस्या को हल करने के लिए आपको लड़के की मदद की प्रतीक्षा कर रहा हूं।

+0

puhhh ... अपने विवरण का प्रारूप कृपया ... :-) –

+0

कहाँ 'है T' घोषित 'ServiceProvider.getService()' में? – hertzsprung

उत्तर

5

इस मामले में आप से बेहतर हो सकता है अगर ServiceProviderRegistryनहीं एक पैरामिट्रीकृत वर्ग के थे, लेकिन इसके बजाय register विधि (और शायद इसी देखने विधि) सामान्य हैं। आपके वर्तमान दृष्टिकोण में ServiceProviderRegistry<Service>केवल सेवा Service.class पंजीकृत नहीं है, सेवा के किसी भी उप-वर्ग नहीं।

आप सभी को वास्तव में परवाह है कि कक्षा और प्रदाता register एक दूसरे से मेल खाते हैं, जो एक सामान्य विधि के लिए एक आदर्श मामला है।

public class ServiceProviderRegistry { 
    private Map<Class<?>, ServiceProvider<?>> registry = new HashMap<>(); 

    public <T extends Service> void register(Class<T> cls, ServiceProvider<T> provider) { 
    registry.put(cls, provider); 
    } 

    @SuppressWarnings("unchecked") 
    public <T extends Service> ServiceProvider<T> lookup(Class<T> cls) { 
    return (ServiceProvider<T>)registry.get(cls); 
    } 
} 

आप @SuppressWarnings एनोटेशन की आवश्यकता होगी - यह एक तरीका है कि पूरी तरह से संकलक, जो केवल संकलन समय प्रकार की पहुंच है को पूरा करेगा में एक के बिना इस पद्धति लागू करने के लिए असंभव है। इस मामले में आप जानते हैं कि कलाकार हमेशा रनटाइम पर सुरक्षित रहेगा क्योंकि register एकमात्र चीज है जो registry मानचित्र को संशोधित करती है, इसलिए @SuppressWarnings उचित है। Jon Skeet's answer to this related question यह योग अप बहुत अच्छी तरह से

कभी कभी जावा जेनरिक सिर्फ तुम क्या आप चाहते हैं नहीं करता है, और आप को प्रभावी ढंग से संकलक है कि क्या तुम सच में कर रहे हैं निष्पादन समय पर कानूनी हो जाएगा बताने के लिए की जरूरत है।

+0

'नया हैश मैप <>() 'केवल जावा 7 और उसके बाद के लिए काम करता है। जावा 6 और नीचे के लिए आपको 'नया हैश मैप , सर्विसप्रोवाइडर >() ' –

+0

की आवश्यकता होगी, इसके अलावा, आपकी' रजिस्टर' विधि में वह 'शून्य' वापस लौटा रहा है। –

+0

@राजेश अदवानी धन्यवाद, मैं ग्रोवी में बहुत अधिक प्रोग्रामिंग को दोषी ठहराता हूं :-) –

5

विधि हस्ताक्षर

public void register(Class clazz, ServiceProvider provider) 

आप यहाँ दो Class उदाहरण गुजर रहे है:

registry.register(FooService.class, FooServiceProvider.class); 

आप एक वर्ग जो register() से पीछे तर्क के रूप में ServiceProvider इंटरफ़ेस लागू करता है का एक उदाहरण उत्तीर्ण करने की आवश्यकता तरीका।

+0

गलत प्रकार के लिए खेद है। मैं दूसरे पैरामीटर को नए FooServiceProvider() के साथ प्रतिस्थापित करता हूं और शिकायत अभी भी मौजूद है। –

0

आपका विधि हस्ताक्षर की तरह है:

public void register(Class clazz, ServiceProvider provider) 

लेकिन आप करने के लिए दो कक्षा उदाहरणों से गुजर रहे हैं रजिस्टर-विधि

registry.register(FooService.class, FooServiceProvider.class); 

आप एक वर्ग जो ServiceProvider इंटरफ़ेस लागू करता है का एक उदाहरण पारित करने के लिए है विधि के लिए दूसरे तर्क के रूप में।

आपको सामान्य प्रकार और कच्चे प्रकार का उपयोग करना चाहिए। जैसे कक्षा के साथ टाइप किया गया? बजाय केवल कक्षा

+0

कृपया पहले उन उत्तरों को पढ़ें जो पहले से मौजूद हैं ... –

+0

sry मैंने अपनी पोस्ट करने से पहले पृष्ठ को रीफ्रेश नहीं किया था। लेकिन मैं कच्चे प्रकार और अन्य पदों का उपयोग न करने का सुझाव देता हूं। – Holger

0

अजीब, अजीब जेनरिक।

public class ServiceProviderRegistry<T extends Service> { 

    private Map<Class<? extends T>, ServiceProvider<? extends T>> map = new HashMap<Class<? extends T>, ServiceProvider<? extends T>>(); 

    public void register(Class<? extends T> clazz, ServiceProvider<? extends T> provider) { 
     map.put(clazz, provider); 
    } 

    public ServiceProvider<? extends T> lookup(Class<? extends T> cls) { 
     return map.get(cls); 
    } 
} 

और मुख्य: यहाँ मेरी हल है

public static void main(String[] args) { 
    ServiceProviderRegistry<Service> registry = new ServiceProviderRegistry<Service>(); 
    registry.register(FooService.class, new FooServiceProvider()); 
    ServiceProvider sp = registry.lookup(FooService.class); 
    Service s = sp.getService(); //safe! 
} 

सुरक्षित है और अभी भी टाइप किया

+0

आप 'main' की अंतिम पंक्ति पर कच्चे' ServiceProvider' प्रकार का उपयोग कर रहे हैं। लेकिन इस कार्यान्वयन में 'सेवाप्रदाता sp = रजिस्ट्री.lookup (FooService।कक्षा); 'संकलित नहीं होगा, क्योंकि' लुकअप '' लुकअप (एक्स.क्लास) 'को' सेवाप्रदाता 'टाइप करने के लिए मजबूर नहीं करता है (केवल' सेवाप्रदाता

+0

बिना किसी कलाकार के ServiceProviderRegistry से ServiceProvider । यह अजीब काम है। माता-पिता को स्पष्ट रूप से बच्चे को नहीं डाला जा सकता है। – Mikhail

+0

यह मेरा मुद्दा था - ServiceProviderRegistry बिल्कुल पैरामीटरयुक्त वर्ग नहीं होना चाहिए, लेकिन रजिस्टर और लुकअप विधियां सामान्य होनी चाहिए और प्रकारों के मिलान को लागू करना चाहिए। –

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