2009-09-17 18 views
5

आज, मैंने पाया कि संग्रह। सिंक्रनाइज़ XXXXX का उपयोग प्रतिबिंब के साथ अच्छी तरह से नहीं खेलता है।जावा संग्रह के लिए वर्कअराउंड रैपर प्रतिबिंब तोड़ने

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class Weird{ 
    public static void main(String[] args) { 
    List<String> list = new ArrayList<String>(); 
    list.add("Hello World"); 

    List<String> wrappedList = Collections.synchronizedList(list); 

    printSizeUsingReflection(list); 
    printSizeUsingReflection(wrappedList); 
    } 

    private static void printSizeUsingReflection(List<String> list) { 
    try { 
     System.out.println(
      "size = " + list.getClass().getMethod("size").invoke(list)); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 
} 

printSizeUsingReflection करने के लिए पहली कॉल आकार (यानी "1"), में दूसरी कॉल परिणाम प्रिंट:

java.lang.IllegalAccessException: Class Weird can not access a member of class 
    java.util.Collections$SynchronizedCollection with modifiers "public" 
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65) 
    at java.lang.reflect.Method.invoke(Method.java:588) 
    at Weird.printSizeUsingReflection(Weird.java:18) 
    at Weird.main(Weird.java:13) 

यह एक छोटे से आश्चर्य की बात है और

यहाँ एक सरल उदाहरण है कष्टप्रद। क्या कोई अच्छा कामकाज है? मुझे पता है कि java.util.concurrent में एक थ्रेड-सुरक्षित सूची कार्यान्वयन है, लेकिन यह कार्यान्वयन Collections.synchronizedList() का उपयोग करने से धीमा लगता है।

उत्तर

5

अपवाद उत्पन्न होने के लिए कारण यह है कि वर्ग लाइन

System.out.println("size = " + list.getClass().getMethod("size").invoke(list)); 

वास्तविक प्रकार रिटर्न में मंगलाचरण

list.getClass() 

द्वारा प्राप्त है। सिंक्रनाइज़ किया गया चयन वर्ग संग्रह वर्ग का एक आंतरिक वर्ग होता है, जिसे आप एक्सेस नहीं कर सकते, इसलिए अपवाद।

इस अपवाद को बाईपास करने का सबसे अच्छा तरीका एक उपयुक्त वर्ग/इंटरफेस पर आकार विधि का आह्वान करना है - आमतौर पर यह कार्यान्वयन वर्ग होता है (क्योंकि इसमें निश्चित रूप से विधि घोषणा या परिभाषा होगी), लेकिन हमारे मामले में हमें सार्वजनिक प्रकार पर आकार() को आमंत्रित करने की आवश्यकता है क्योंकि obj.getClass() ने एक गैर-सार्वजनिक प्रकार वापस कर दिया है। विशिष्ट होने के लिए, हमें java.util.Collection (super) इंटरफ़ेस या java.util.List इंटरफ़ेस पर आकार() को आमंत्रित करने की आवश्यकता है। "आकार = 1"

निम्नलिखित बयान प्रिंट होगा कंसोल में:

System.out.println("size = " + Collection.class.getMethod("size").invoke(list)); 
System.out.println("size = " + List.class.getMethod("size").invoke(list)); 

अद्यतन

मामले में आप सोच रहे थे आकार() विधि प्रतिबिंब के माध्यम से लागू किया सिंक्रनाइज़ है कि क्या है या नहीं, जवाब हाँ है, यह सिंक्रनाइज़ है। सुपर प्रकार - संग्रह/सूची पर आकार() विधि का आविष्कार करने के बावजूद, सिंक्रनाइज़ किए गए कोलेक्शन में आकार() विधि को आंतरिक कक्षा में शामिल किया जाता है, और यह सिंक्रनाइज़ होता है। यह एक कार्यान्वयन विस्तार है हालांकि, संग्रह लपेटने के बाद से काम करने की गारंटी है।

इसके अलावा, the supertype - the Collection interface contains the size() method पर प्रतिबिंब का उपयोग करना अच्छा विचार नहीं है।

3

Collection.class से विधि प्राप्त करें (आमतौर पर कुछ सार्वजनिक खोजने के लिए सुपर क्लास (और इंटरफेस) को फिर से शुरू करें)। या सिर्फ प्रतिबिंब का उपयोग न करें। java.util.Collections $ SynchronizedCollection -

+0

+1 प्रतिबिंब का उपयोग न करें। 'list.size() 'इन स्थितियों में अच्छी तरह से काम करता है। – akf

+0

अगर मैं कर सकता तो मैं प्रतिबिंब से बचूंगा। इस मामले में, मेरे पास Google Guice द्वारा स्थापित एक एओपी इंटरसेप्टर है, और मैं विधि तर्कों के बारे में उपयोगी चीजों को लॉग करने का प्रयास कर रहा हूं - दुर्भाग्यवश, कक्षा के प्रकार मूल रूप से एकमात्र सोच हैं जो मुझे तर्कों के बारे में पता है। संग्रह.क्लास टिप के लिए धन्यवाद .. एक आकर्षण की तरह काम करता है! –

0

क्या आप सुनिश्चित हैं java.util.concurrent विकल्प धीमे हो जाएंगे (या, चिंता करने के लिए पर्याप्त धीमे?)।

मुझे लगता है कि अपने 2 विकल्प हैं:

  1. LinkedBlockingQueue
  2. CopyOnWriteArrayList

मैं कुछ उपयोग के मामलों के लिए लगता है, इन कार्यान्वयन वास्तव में तेजी हो सकता है। और एक साइड नोट के रूप में, यदि आपको अंततः इसकी आवश्यकता है, तो java.util.concurrent में संग्रह समवर्ती संशोधन को संभाल सकता है।

CopyOnWriteArrayList एक तुल्यकालन सूची कि कुछ सामान्य स्थितियों में बेहतर संगामिति प्रदान करता है और लॉक करने के लिए या की आवश्यकता समाप्त के लिए एक समवर्ती प्रतिस्थापन है:

की Concurrent Collections अनुभाग "जावा संगामिति अभ्यास में" से

पुनरावृत्ति के दौरान संग्रह की प्रतिलिपि बनाएँ। (इसी प्रकार, CopyOnWriteArraySet एक तुल्यकालन सेट के लिए एक समवर्ती प्रतिस्थापन है।)

1

java.util.Collections $ SynchronizedCollection गैर सरकारी वर्ग है।

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