अनाम वर्ग के लिए पैरामीटर कैसे पास करें?


146

क्या पैरामीटर को पास करना संभव है, या किसी अनाम वर्ग के लिए बाहरी मापदंडों का उपयोग करना संभव है? उदाहरण के लिए:

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
    }
});

क्या श्रोता के लिए myVariable का उपयोग करने का कोई तरीका है या myVariable को वास्तविक नामांकित वर्ग के रूप में श्रोता बनाए बिना पारित किया जा सकता है?


7
आप finalस्थानीय चर को एन्क्लोजिंग विधि से संदर्भित कर सकते हैं ।
टॉम हैटिन -

मुझे एडम मैमेलोडज़िंस्की के एक निजी तरीके को परिभाषित करने के सुझाव की नज़र पसंद है जो निजी myVariable उदाहरण (ओं) को शुरू करता है और लौटने के कारण समापन ब्रेस पर बुलाया जा सकता है this
dlamblin

इस सवाल के कुछ साझा लक्ष्य हैं: stackoverflow.com/questions/362424/…
एलेस्टेयर मैककॉर्मैक

आप अनाम वर्ग के अंदर से वैश्विक वर्ग चर का भी उपयोग कर सकते हैं। शायद बहुत साफ नहीं है, लेकिन यह काम कर सकता है।
जोरी

जवाबों:


78

तकनीकी रूप से, नहीं, क्योंकि अनाम कक्षाओं में कंस्ट्रक्टर नहीं हो सकते हैं।

हालांकि, कक्षाएं स्कोप वाले चर को संदर्भित कर सकती हैं। एक अनाम वर्ग के लिए ये उदाहरण वाले चर (तों) या स्थानीय चर हो सकते हैं जो अंतिम रूप से चिह्नित हैं।

संपादित करें : जैसा कि पीटर ने बताया, आप अनाम वर्ग के सुपरक्लास के निर्माण के लिए पैरामीटर भी पास कर सकते हैं।


21
एक अनाम वर्ग उपयोग अपने माता-पिता के निर्माणकर्ताओं का उपयोग करता है। जैसेnew ArrayList(10) { }
पीटर लॉरी

अच्छी बात। तो यह अनाम श्रेणी के एक पैरामीटर को पारित करने का एक और तरीका होगा, हालांकि यह संभावना है कि आपके पास उस पैरामीटर पर नियंत्रण नहीं होगा।
मैथ्यू विलिस

अनाम कक्षाओं को कंस्ट्रक्टरों की आवश्यकता नहीं है
newacct

4
बेनामी कक्षाओं में इंस्टेंस इनिशियलाइज़र हो सकते हैं, जो अनाम कक्षाओं में पैरामीटर-कम कंस्ट्रक्टर के रूप में कार्य कर सकते हैं। इन्हें फ़ील्ड असाइनमेंट के बाद, यानी super()वास्तविक निर्माणकर्ता के बाकी हिस्सों से पहले और बाद में निष्पादित किया जाता है । new someclass(){ fields; {initializer} fields; methods(){} }। यह एक स्थिर इनिशियलाइज़र की तरह है लेकिन स्टैटिक कीवर्ड के बिना। docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.6
मार्क जेरोनिमस

यह देखें stackoverflow.com/a/3045185/1737819 यह कहता है कि बिना कंस्ट्रक्टर के कैसे लागू किया जाए।
डेवलपर Marius ėilėnas

336

हां, एक ऐसा आरंभिक तरीका जोड़कर जो 'यह' लौटाता है, और तुरंत उस विधि को बुला रहा है:

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    private int anonVar;
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
        // It's now here:
        System.out.println("Initialized with value: " + anonVar);
    }
    private ActionListener init(int var){
        anonVar = var;
        return this;
    }
}.init(myVariable)  );

किसी 'अंतिम' घोषणा की जरूरत नहीं।


4
वाह ... शानदार! मैं एक finalसंदर्भ वस्तु बनाने के लिए बहुत थक गया हूँ , इसलिए मैं अपनी अनाम कक्षाओं में जानकारी प्राप्त कर सकता हूँ। साझा करने के लिए धन्यवाद!
मैट क्लिन

7
init()फ़ंक्शन को वापस क्यों करना पड़ता है this? मैं वाक्यविन्यास वास्तव में नहीं मिलता है।
जोरी

11
क्योंकि आपका myButton.addActionListener (...) एक ActionListener ऑब्जेक्ट को एक ऑब्जेक्ट के रूप में उम्मीद करता है जो कि जब आप इसकी विधि कहते हैं तो वापस आ जाती है।

1
मुझे लगता है .. मुझे लगता है कि हालांकि खुद बदसूरत है, हालांकि यह काम करता है। मुझे ज्यादातर समय लगता है कि मैं बस आवश्यक चर और फ़ंक्शन मापदंडों को अंतिम और सीधे आंतरिक वर्ग से उन्हें संदर्भित करने के लिए खर्च कर सकता हूं, क्योंकि आमतौर पर वे केवल पढ़ रहे होते हैं।
थॉमस

2
सरल: निजी int anonVar = myVariable;
अनम

29

हाँ। आप वैरिएबल पर कब्जा कर सकते हैं, जो आंतरिक वर्ग को दिखाई देता है। एकमात्र सीमा यह है कि इसे अंतिम होना है


एक अनाम वर्ग से संदर्भित उदाहरण चर को अंतिम एफएक्यू नहीं होना चाहिए।
मैथ्यू विलिस

8
इंस्टेंस चर को संदर्भित किया जाता है thisजिसके माध्यम से अंतिम है।
पीटर लॉरी

क्या होगा अगर मैं नहीं चाहता कि चर को बदल दिया जाए final? मुझे कोई विकल्प नहीं मिल रहा है। यह मूल पैरामीटर को प्रभावित कर सकता है जो होने के लिए डिज़ाइन किया गया है final
एलस्टन

20

ऐशे ही:

final int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Now you can access it alright.
    }
});

14

यह जादू करेगा

int myVariable = 1;

myButton.addActionListener(new ActionListener() {

    int myVariable;

    public void actionPerformed(ActionEvent e) {
        // myVariable ...
    }

    public ActionListener setParams(int myVariable) {

        this.myVariable = myVariable;

        return this;
    }
}.setParams(myVariable));

8

जैसा कि http://www.coderanch.com/t/567294/java/java/declare-constructor-anonymous-class पर दिखाया गया है, आप एक उदाहरण इनिशियलाइज़र जोड़ सकते हैं। यह एक ऐसा ब्लॉक है जिसका कोई नाम नहीं है और इसे पहले (एक कंस्ट्रक्टर की तरह) निष्पादित किया जाता है।

ऐसा लगता है कि वे भी जावा इंस्टा इनिशियलाइज़र्स पर चर्चा कर रहे हैं ? और कैसे एक इंस्ट्रूमेंट एक इंस्ट्रूमेंट से अलग है? निर्माणकर्ताओं से मतभेदों पर चर्चा करता है।


यह पूछे जाने वाले प्रश्न को हल नहीं करता है। आपको अभी भी स्थानीय चर तक पहुँचने की समस्या होगी, इसलिए आपको या तो एडम मैलोडज़िन्स्की या एडारश से समाधान का उपयोग करने की आवश्यकता होगी
मैट क्लेन

1
@MattKlein मेरे लिए, ऐसा लगता है कि यह इसे हल करता है। यह वास्तव में एक ही बात है, और कम क्रिया है।
हेलिक्स

1
प्रश्न यह जानना चाहता था कि कक्षा में मापदंडों को कैसे पारित किया जाए, जैसे कि आप एक निर्माता के साथ पैरामीटर की आवश्यकता होती है। लिंक (जिसे यहाँ संक्षेप में प्रस्तुत किया जाना चाहिए था) केवल यह दर्शाता है कि कैसे एक पैरामीटर-कम उदाहरण इनिशलाइज़र है, जो प्रश्न का उत्तर नहीं देता है। इस तकनीक को finalaav द्वारा वर्णित चर के साथ इस्तेमाल किया जा सकता है , लेकिन यह जानकारी इस उत्तर में प्रदान नहीं की गई थी। अब तक, सबसे अच्छा जवाब एडम मैलोडोज़िंकी द्वारा दिया गया है (मैं अब इस पैटर्न का विशेष रूप से उपयोग करता हूं, कोई और फाइनल नहीं!)। मैं अपनी टिप्पणी से खड़ा हूं कि यह पूछे गए सवाल का जवाब नहीं देता है।
मैट क्लेन

7

मेरा समाधान एक ऐसी विधि का उपयोग करना है जो कार्यान्वित अनाम वर्ग को लौटाता है। नियमित तर्क पद्धति को पारित किया जा सकता है और अनाम वर्ग के भीतर उपलब्ध हैं।

उदाहरण के लिए: (कुछ GWT कोड से एक टेक्स्ट बॉक्स परिवर्तन को संभालने के लिए):

/* Regular method. Returns the required interface/abstract/class
   Arguments are defined as final */
private ChangeHandler newNameChangeHandler(final String axisId, final Logger logger) {

    // Return a new anonymous class
    return new ChangeHandler() {
        public void onChange(ChangeEvent event) {
            // Access method scope variables           
            logger.fine(axisId)
        }
     };
}

इस उदाहरण के लिए, नए अनाम वर्ग-विधि को संदर्भित किया जाएगा:

textBox.addChangeHandler(newNameChangeHandler(myAxisName, myLogger))

या , ओपी की आवश्यकताओं का उपयोग कर:

private ActionListener newActionListener(final int aVariable) {
    return new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Your variable is: " + aVariable);
        }
    };
}
...
int myVariable = 1;
newActionListener(myVariable);

यह अच्छा है, यह गुमनाम वर्ग को कुछ आसान-से पहचाने जाने योग्य चरों में प्रतिबंधित करता है और कुछ चरों को अंतिम रूप देने के निरस्तीकरण को हटा देता है।
दुखी चर

3

अन्य लोगों ने पहले ही उत्तर दिया है कि अनाम कक्षाएं केवल अंतिम चर तक पहुंच सकती हैं। लेकिन वे इस सवाल को खुला छोड़ देते हैं कि मूल चर को अंतिम रूप से कैसे रखा जाए। एडम Mlodzinski एक समाधान दिया है, लेकिन बहुत फूला हुआ है। समस्या का बहुत सरल समाधान है:

यदि आप myVariableअंतिम नहीं बनना चाहते हैं तो आपको इसे एक नए दायरे में लपेटना होगा जहां यह अंतिम हो, इससे कोई फर्क नहीं पड़ता।

int myVariable = 1;

{
    final int anonVar = myVariable;

    myButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // How would one access myVariable here?
            // Use anonVar instead of myVariable
        }
    });
}

एडम म्लोडज़िंस्की अपने जवाब में कुछ और नहीं बल्कि बहुत अधिक कोड के साथ करते हैं।


यह अभी भी अतिरिक्त दायरे के बिना काम करता है। यह प्रभावी रूप से अंतिम के उपयोग से अन्य उत्तरों के समान है।
एडम मेलोडज़िंस्की

@AdamMlodzinski नहीं यह प्रभावी रूप से आपके उत्तर के समान है, क्योंकि यह एक निजी दायरे में मूल चर के मूल्य के साथ एक नया चर पेश करता है।
21

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

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

मैं यह नहीं देखता कि यह finalचर समाधान का उपयोग करने से अलग कैसे है ।
केविन रवे

3

आप सादे लैम्ब्डा का उपयोग कर सकते हैं ("लैम्ब्डा एक्सप्रेशन वेरिएबल्स को कैप्चर कर सकते हैं")

int myVariable = 1;
ActionListener al = ae->System.out.println(myVariable);
myButton.addActionListener( al );

या यहां तक ​​कि एक समारोह

Function<Integer,ActionListener> printInt = 
    intvar -> ae -> System.out.println(intvar);

int myVariable = 1;
myButton.addActionListener( printInt.apply(myVariable) );

फ़ंक्शन का उपयोग करना डेकोरेटर और एडेप्टर को रिफ्लेक्टर करने का एक शानदार तरीका है, यहां देखें

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


1

बाहरी चर में कुछ मान रखने का एक सरल तरीका (अनाम वर्ग के लिए नहीं है) कैसे फ़ोलो है!

उसी तरह से यदि आप चाहते हैं कि बाहरी चर का मूल्य प्राप्त हो तो आप एक विधि बना सकते हैं जो आपको वापस चाहिए!

public class Example{

    private TypeParameter parameter;

    private void setMethod(TypeParameter parameter){

        this.parameter = parameter;

    }

    //...
    //into the anonymus class
    new AnonymusClass(){

        final TypeParameter parameterFinal = something;
        //you can call setMethod(TypeParameter parameter) here and pass the
        //parameterFinal
        setMethod(parameterFinal); 

        //now the variable out the class anonymus has the value of
        //of parameterFinal

    });

 }

-2

मुझे लगा कि अनाम कक्षाएं मूल रूप से लंबोदर की तरह थीं, लेकिन बदतर वाक्यविन्यास के साथ ... यह सच हो जाता है, लेकिन वाक्यविन्यास और भी बदतर है और स्थानीय चर (युक्तियां) होने का कारण बनता है।

आप मूल वर्ग के क्षेत्रों में बनाकर कोई भी अंतिम चर एक्सेस नहीं कर सकते।

उदाहरण के लिए

इंटरफेस:

public interface TextProcessor
{
    public String Process(String text);
}

वर्ग:

private String _key;

public String toJson()
{
    TextProcessor textProcessor = new TextProcessor() {
        @Override
        public String Process(String text)
        {
            return _key + ":" + text;
        }
    };

    JSONTypeProcessor typeProcessor = new JSONTypeProcessor(textProcessor);

    foreach(String key : keys)
    {
        _key = key;

        typeProcessor.doStuffThatUsesLambda();
    }

मुझे नहीं पता कि उन्होंने इसे java 8 में छांटा है (मैं EE दुनिया में फंस गया हूं और अभी तक 8 नहीं मिला) लेकिन C # में यह इस तरह दिखेगा:

    public string ToJson()
    {
        string key = null;
        var typeProcessor = new JSONTypeProcessor(text => key + ":" + text);

        foreach (var theKey in keys)
        {
            key = theKey;

            typeProcessor.doStuffThatUsesLambda();
        }
    }

आपको c # में एक अलग इंटरफ़ेस की आवश्यकता नहीं है ... मुझे यह याद है! मैं अपने आप को जावा में बदतर डिजाइन बना रहा हूं और अपने आप को और अधिक दोहरा रहा हूं क्योंकि कोड + जटिलता के लिए आपको कुछ पुन: उपयोग करने के लिए जावा में जोड़ना पड़ता है, बस कॉपी और पेस्ट करने से भी बदतर होता है।


ऐसा लगता है कि आप जिस अन्य हैक का उपयोग कर सकते हैं वह एक तत्व सरणी है जैसा कि यहां उल्लेख किया गया है stackoverflow.com/a/4732586/962696
जॉनी राए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.