2012-03-19 15 views
7

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

public class VeryBasicJava{ 
    public static void main(String[] args){ 
     int x = 3; 
     int y = 4; 
     swapMe(x, y); 
    } 
    private void swapMe(int a, int b){ 
     int a; 
     int b; 
     int tmp = a; 
     this.a = b; 
     this.b = a; 
    } 
} 

जब मैं संकलन, मैं खतरनाक "गैर स्थैतिक विधि swapMe (पूर्णांक, पूर्णांक) एक स्थिर संदर्भ से संदर्भित नहीं किया जा सकता" त्रुटि मिलती है। साथ ही, मुझे "पहले से ही swapMe (int, int) में परिभाषित किया गया है" और "बी पहले से ही swapMe (int, int) में परिभाषित किया गया है"

मुझे अंततः मेरी मोटी खोपड़ी के माध्यम से क्या प्राप्त करने की आवश्यकता है, "गैर -स्टैटिक विधि "त्रुटि, कैसे (क्यों) इसका कारण बनता है, और इससे कैसे बचें।

आगे, मैं इस धारणा के तहत था कि आप "swapMe" विधि में अपने 'ए' और 'बी' चर के साथ क्या करने का प्रयास कर रहे हैं। मैंने सोचा कि मैं 'ए' और 'बी' में गुजर सकता हूं, लेकिन नए चर 'ए' और 'बी' भी बना सकता हूं, और उन्हें "इस" कीवर्ड के साथ संदर्भित कर सकता हूं।

मुझे पता है कि यह बेहद बुनियादी है, लेकिन ये दो "मुद्दे" जावा के साथ मेरे मुख्य चिपकने वाले बिंदुओं में से दो हैं, और किसी कारण से, ठीक से सीखने के लिए प्रतीत नहीं होता है।

इसे पढ़ने के लिए समय निकालने के लिए सभी को धन्यवाद। आपका दिन अच्छा रहे।

+0

अच्छा सवाल है कि बहुत से शुरुआती जावा प्रोग्रामर इस माध्यम से जाते हैं:) – Shawn

+0

अच्छा सवाल है कि ज्यादातर लोग केवल कोड प्रदान करेंगे और वास्तव में यह नहीं बताएंगे कि क्या हो रहा है। – Nicholas

+1

क्या लोग * उदाहरण * देना बंद कर सकते हैं? प्रश्नकर्ता को कामकाजी कोड की आवश्यकता नहीं है, उसे ऑब्जेक्ट उन्मुख प्रोग्रामिंग अवधारणाओं को समझाने के लिए किसी की जरूरत है। – deworde

उत्तर

11

इसका मतलब है कि विधि swapMe() एक उदाहरण तरीका है और आप VeryBasicJava वर्ग का एक उदाहरण की जरूरत है यह आह्वान करने के लिए, इस तरह:

VeryBasicJava instance = new VeryBasicJava(); 
int x = 3; int y = 4; 
instance.swapMe(x, y); 

वैकल्पिक रूप से, आप static रूप swapMe() घोषित कर सकता है, कि में जिस तरह से आपको पहले एक उदाहरण बनाने की आवश्यकता नहीं होगी:

private static void swapMe(int a, int b) 
+0

लेकिन, swapMe मुख्य वर्ग के समान वर्ग में है, जो वर्ग VeryBasicJava है। एक विधि को स्वयं से कॉल करने के लिए मुझे अतिबासिक जावा का एक उदाहरण बनाने की आवश्यकता क्यों है? मेरे लिए, यह example.x = 3, और example.y = 4. मुझे लगता है कि मुझे यह भी कहना चाहिए कि मैं एक प्रक्रियात्मक व्यक्ति हूं, मैंने सी – Brian

+0

के साथ प्रोग्रामिंग सीखा क्योंकि आप इसे कॉल कर रहे हैं एक स्थिर विधि के अंदर से। यदि आपने अन्य गैर-स्थैतिक विधि से स्वैप को बुलाया है तो आपको कक्षा के उदाहरण की आवश्यकता नहीं होगी। – Raevik

+0

जावा परेशान है, जो मुझे बिल्कुल समझ में नहीं आता है। मैं कहता हूं, सी जावा के बारे में कभी भी सोचा गया है। – Brian

1

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

स्थिर तरीके और फ़ील्ड कक्षा के किसी भी विशिष्ट उदाहरण से बंधे नहीं हैं।

तो इस विधि के बिना आप जिस विधि को आमंत्रित करना चाहते हैं, उसके बिना एक स्थिर विधि से क्लास इंस्टेंस विधि को आमंत्रित करने का कोई मतलब नहीं है। आपके उदाहरण में, this एक उदाहरण का संदर्भ है, लेकिन आपके पास कोई उदाहरण नहीं है ....

1

अपने दूसरे प्रश्न के लिए, जब आप कोई फ़ंक्शन बनाते हैं, तो यह इसके सभी चर के लिए अपना स्वयं का छोटा ढेर बनाता है। अपने तर्कों कि ढेर में शामिल हैं - हां, तो आपके ढेर इस तरह दिखता है:

int a; //this is the first argument 
    int b; //this is the second argument 
    int a; //this is the first line of your function 
    int b; //this is the second line of your function 

है यही कारण है कि आप एक मुद्दा हो रही है - ए और बी यदि आप यह घोषणा अपने तर्क अपने तर्क के साथ परस्पर विरोधी हैं के बाद, नहीं "इस एए "और" यह.बी "।

आपका पहला प्रश्न पहले से ही उत्तर दिया जा चुका है।

0

स्वैप मुझे इसे आमंत्रित करने के लिए अतिबासिक जावा का एक उदाहरण चाहिए। स्टेटिक नहीं है।

उस ऑब्जेक्ट के बाहर से, आप कॉल कर सकते हैं: VeryBasicJava.main (args)।

ऑब्जेक्ट के बाहर से, आपको (नया VeryBasicJava()) करना होगा। SwapMe (a, b) उस विधि को आमंत्रित करने के लिए।

स्वैपमे के अंदर आपको त्रुटियां मिल रही हैं क्योंकि आप उन चर को दो बार परिभाषित कर रहे हैं। हस्ताक्षर रेखा ने उन्हें आपके लिए उस नामस्थान में घोषित किया। उस विधि में, आपके पास पहले से ही एक int है। फिर पहली पंक्ति पर, आप फिर से int घोषित करते हैं।

क्या आप अपने स्वैप में क्या करना चाहते हैं कुछ इस तरह है:

private void swapMe(int a, int b){ 
    int tmp = a; 
    a = b; 
    b = tmp; 
} 
बेशक

चर ए और बी केवल इसलिए जितनी जल्दी विधि समाप्त होता है के रूप में अपने काम के लिए खो दिया है कि विधि में मौजूद हैं। यदि आप इसे रखना चाहते हैं, तो वैरिएबल क्लास वेरिएबल्स बनाएं और उनके लिए गेटर्स और सेटर्स प्रदान करें।

1

ठीक के रूप में प्रदान किया गया है, मैं जोड़ना चाहते हैं:

स्थिर तरीकों केवल अन्य स्थिर तरीकों और पहुँच केवल स्थैतिक चर सीधे (जावा में) कॉल कर सकते हैं।

गैर स्थैतिक तरीकों को कॉल करने के लिए, आपने उस वर्ग का एक उदाहरण बनाया है और फिर विधियों को कॉल किया है।

5

आपके पास कुछ मामूली समस्याएं हैं। आपने एक टिप्पणी में उल्लेख किया है कि आपके पास सी के साथ कुछ अनुभव है, इसलिए मैं कुछ बुनियादी अनुरूपताओं को आकर्षित करने की कोशिश करूंगा। एक static विधि (जैसे main) सामान्य सी फ़ंक्शन की तरह व्यवहार करती है। एक गैर-static विधि, हालांकि, एक छिपी पैरामीटर लेता है: this, जो ऑब्जेक्ट पर संदर्भित करता है जिस पर वह विधि संचालित होती है। जब आप इस जैसे एक विधि लिखें:

private void swapMe(VeryBasicJava this, int a, int b){ 
    //    ^^^^^^^^^^^^^^^^^^^^ 
    // ... 

क्योंकि this पैरामीटर विशेष रूप से व्यवहार किया जाता है, वहाँ पर गैर static तरीकों फोन करने के लिए एक विशेष वाक्य रचना है:

private void swapMe(int a, int b) { 
    // ... 

यह वास्तव में कुछ इस तरह का मतलब वस्तुओं:

myInstance.swapMe(someA, someB); 
// ^^^^^^^^^^  ^^^^^ ^^^^^ 
//  this    a  b 

और क्योंकि swapMestatic घोषित नहीं है, यह अब की तरह कहा जा करने की उम्मीद ove।

तथ्य यह है कि mainVeryBasicJava वर्ग के अंदर घोषित किया जाता है इसका मतलब यह नहीं है कि आप स्वचालित रूप से एक VeryBasicJavaवस्तु है।फिर, क्योंकि mainstatic है, यह सिर्फ एक साधारण सी समारोह की तरह है:

void VeryBasicJava_main(...) { 
    // ... 

आदेश में को एक वस्तु का एक उदाहरण बनाने के लिए, आप new का उपयोग करें:

VeryBasicJava vbj = new VeryBasicJava(); 

इस के अनुरूप है सी में malloc:

VeryBasicJava *vbj = malloc(sizeof(VeryBasicJava)); 
VeryBasicJava_construct(vbj); 

एक उदाहरण के साथ, आप एक विधि आह्वान कर सकते हैं:

vbj.swapMe(spam, eggs); 

आपका अन्य मुद्दा दोहरा है: में से एक गुंजाइश, और के सदस्यों। जैसा कि आप जानते हैं, दायरा को संदर्भित करता है जहां एक चर मौजूद है। इस समारोह लें:

1: private void swapMe(int a, int b) { 
2:  int a; 
3:  int b; 
4:  int tmp = a; 
5:  this.a = b; 
6:  this.b = a; 
7: } 

जब इस विधि कहा जाता है, तो निम्न बातें होती हैं:

  1. a और b बनाई गई हैं, मूल्यों swapMe करने के लिए कॉल में निर्दिष्ट दिया।

  2. एक नया a डिफ़ॉल्ट मूल्य 0 के साथ swapMe पर स्थानीय बनाया गया है। यह aछिपा पैरामीटर a, और उन्हें अलग करने का कोई तरीका नहीं है।

  3. एक नया b भी सख्ती से स्थानीय बनाया गया है। इसमें भी डिफ़ॉल्ट 0 मान है, और पैरामीटर b को छुपाता है।

  4. tmp बनाया गया है, और इसका मूल्य नव घोषित a पर सेट है, इसलिए यह भी 0 है।

  5. , [ नीचे देखें]

  6. [ नीचे देखें]

  7. स्थानीय लोगों a और b संघर्ष अस्तित्व के लिए के रूप में मानकों a और b है।

लाइनों 5 और 6, आप वाक्य रचना this.a उपयोग करने के लिए नहीं बल्कि पैरामीटर से स्थानीय a का उल्लेख करने का प्रयास। यद्यपि जावा में यह वाक्यविन्यास मौजूद है, लेकिन यह आपके द्वारा किए जाने वाले कार्यों का पालन नहीं करता है। पैरामीटर्स को स्थानीय चर के समान ही माना जाता है, इसलिए उन दो श्रेणियों के बीच अंतर करने की बजाय this.a स्थानीय और सदस्यों के बीच अंतर करता है। अब, सदस्य क्या हैं?ठीक है, का कहना है कि अपने वर्ग घोषणा चर घोषणाओं में शामिल हैं:

class VeryBasicJava { 

    private int a; 
    private int b; 

    // ... 

} 

यह एक सी struct में सिर्फ सदस्य घोषणाओं की तरह है:

struct VeryBasicJava { 
    int a; 
    int b; 
}; 

क्या इसका मतलब यह है कि जब आप VeryBasicJava का एक उदाहरण बनाने के लिए:

VeryBasicJava vbj = new VeryBasicJava(); 

उस उदाहरण के अपने चर a और b हैं, जिनका उपयोग किसी भी में किया जा सकता है गैर static विधि:

public void print() { 
    System.out.println("a is " + a); 
    System.out.println("b is " + b); 
} 

आप एक सदस्य के रूप में एक ही नाम के साथ एक स्थानीय चर है, तो आप this का उपयोग करना चाहिए जो स्पष्ट रूप से करने के लिए है कि आप सदस्य का उल्लेख करना चाहते हैं। यह पूरा कार्यक्रम सदस्यों और स्थानीय लोगों के बीच घोषित करने, उपयोग करने और अंतर करने का तरीका बताता है।

class VeryBasicJava { 

    private int a; 
    private int b; 
    private int c; 

    public static void main(String[] args) { 
     VeryBasicJava vbj = new VeryBasicJava(); 
     vbj.a = 3; 
     vbj.b = 4; 
     vbj.c = 5; 
     vbj.print(1); 
    } 

    public void print(int a) { 
     int b = 2; 
     System.out.println("a is " + a); 
     System.out.println("b is " + b); 
     System.out.println("c is " + c); 
     System.out.println("this.a is " + this.a); 
     System.out.println("this.b is " + this.b); 
     System.out.println("this.c is " + this.c); 
    } 

} 

यह इस उत्पादन का उत्पादन होगा:

a is 1 
b is 2 
c is 5 
this.a is 3 
this.b is 4 
this.c is 5 

मुझे आशा है कि इन उदाहरणों और स्पष्टीकरण सहायक होते हैं।

+0

बहुत अच्छा, व्यापक उत्तर! – o0rebelious0o

2

आपकी समस्याएं समझने से नहीं आती हैं कि वस्तु-उन्मुख प्रतिमान कैसे काम करता है।

विचार यह है कि आप एक वर्ग को परिभाषित करते हैं, जो "चीज़ का प्रकार" है। उस वर्ग से, आप उदाहरण बनाते हैं, जो उस प्रकार की चीज़ों के प्रभावी उदाहरण हैं।

उदाहरण के लिए

, जब आप एक वर्ग "बटुआ", निर्धारित करती है कि आपके प्रणाली पर्स व्यवहार करेगा (वे क्या कर सकते जैसे कि, और क्या आप उनके साथ कर सकते हैं) पैदा करते हैं। अब आप उदाहरण वेल्ट्स बना सकते हैं, जो विभिन्न मानों को संग्रहीत करते हैं, लेकिन फिर भी वैसे ही काम करते हैं। (उदाहरण के लिए "माईवालेट" और "योरवालेट" दोनों वॉलेट्स हैं, इसलिए आप पैसे ले सकते हैं और पैसा लगा सकते हैं, लेकिन अगर मैं में अपना वॉलेट चेक करता हूं, तो मुझे 50 का मूल्य मिलता है, जबकि यदि मैं मूल्य की जांच करता हूं myWallet में, मैं) 20 के एक मूल्य

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

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

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

सिद्धांत मुद्दों में से एक जावा के साथ कि यह बांध एक वर्ग करने के लिए सब कुछ है (यह encapsulation की एक व्याख्या वास्तव में नीचे छीन लिया है)। यह मुख्य विधि के लिए एक समस्या का कारण बनता है, जिसे प्रोग्राम शुरू करना है, क्योंकि इसमें अभी तक कोई उदाहरण नहीं है, लेकिन अभी भी कक्षा का हिस्सा होना चाहिए। इसलिए मुख्य विधि हमेशा स्थिर होना चाहिए। यह नए प्रोग्रामर को भ्रमित करने का प्रयास करता है, क्योंकि हमेशा मुख्य विधि के भीतर आप जो पहली चीज करते हैं वह कक्षा के उदाहरण "अंदर" का उदाहरण बनाते हैं।

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

जब मैं मूल रूप से जावा के साथ शुरू कर रहा था, मैंने कक्षा के मुख्य() विधि को प्रभावी ढंग से इलाज किया जैसे कि यह कक्षा का हिस्सा नहीं था। संकल्पनात्मक रूप से, इससे मदद मिली, क्योंकि आप गैर स्थैतिक सामानों के बारे में सोचने से रोकते हैं जो पहले से मौजूद है (जो आपका मुख्य मुद्दा है)। लेकिन आपकी सिफारिश try reading through this है। लेकिन ऑब्जेक्ट उन्मुख प्रोग्रामिंग सीखने के लिए वहां कुछ बहुत अच्छे संक्रमण पाठ्यक्रम हैं, और आप इन्हें निवेश करना चाहते हैं।

+0

ठीक है, इस के अनुसार (http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html) आलेख, स्थिर मान कक्षा से बनाए गए सभी ऑब्जेक्ट्स के लिए आम हैं। तो, क्यों नहीं [आपके उदाहरण से] कक्षा से बनाए गए सभी वस्तुओं से मुझे एक स्थिर विधि सुलभ क्यों होगी? यदि "नकद" स्थैतिक है, और "चेककैश()" स्थिर है, तो उसे वही काम करना चाहिए, और मुझे बनाए गए प्रत्येक वॉलेट के लिए एक ही जवाब दें ... सही ??? – Brian

+0

हां, आप वहां सही हैं। किसी भी उदाहरण से स्थैतिक तरीकों का उपयोग किया जा सकता है (उस दस्तावेज़ में संख्याऑफबाइक देखें)। लेकिन उपर्युक्त प्रश्न में आप जो कर रहे हैं वह गैर-स्टेटिक (उदाहरण) सदस्य फ़ंक्शन "स्वैपमे" को एक स्थिर विधि से एक्सेस कर रहा है: "मुख्य", जो कि दूसरी तरफ है, और यह काम नहीं करेगा, क्योंकि कुछ भी नहीं है स्वैप को रोकें, विशिष्ट उदाहरण सदस्यों तक पहुंचने से जो एक उदाहरण के बिना मौजूद नहीं होंगे। त्रुटि "स्थैतिक संदर्भ से गैर स्थैतिक विधि तक पहुंच" है, ** ** ** "गैर स्थैतिक संदर्भ से स्थैतिक विधि तक पहुंच नहीं" – deworde

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