हमें जावा में संरक्षित स्थैतिक का उपयोग क्यों नहीं करना चाहिए


122

मैं इस सवाल से गुजर रहा था कि क्या जावा में क्लास वेरिएबल को ओवरराइड करने का कोई तरीका है? 36 upvotes के साथ पहली टिप्पणी थी:

यदि आप कभी भी देखते हैं protected static, तो दौड़ें।

किसी को भी समझा सकता है कि क्यों एक protected staticपर आधारित है?


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

6
@ वीजीआर का finalमतलब यह नहीं है कि क्षेत्र अपरिवर्तनीय है। आप हमेशा संदर्भ चर objectद्वारा संदर्भित संशोधित कर सकते हैं final
जीशान

@ वीजीआर मैं असहमत हूं। केवल एक ही कारण है कि आप एक स्थिर वैरिएबल बना सकते हैं कि इसे केवल दूसरे पैकेज से प्राप्त किया जा सकता है। यह एक त्रुटिपूर्ण डिजाइन है, IMO, और यदि आप इसका सहारा लेते हैं, तो आपको संभवतः अपने आवेदन की संरचना पर पुनर्विचार करना चाहिए। हालांकि यह सिर्फ मेरी राय है।
डाइऑक्सिन

@LoneRider तुम सही हो। मैं अपरिवर्तनीय सोच रहा था, और अंतिम निश्चित रूप से इसकी गारंटी नहीं देता है।
वीजीआर

यहां तक ​​कि मैं भी इसी सवाल से यहां आया था।
राज राजेश्वर सिंह राठौर

जवाबों:


86

यह एक प्रत्यक्ष समस्या की तुलना में अधिक शैलीगत बात है। यह बताता है कि आपने कक्षा के साथ जो चल रहा है, उसके बारे में ठीक से नहीं सोचा है।

क्या staticमतलब है के बारे में सोचो :

यह चर वर्ग स्तर पर मौजूद है, यह प्रत्येक उदाहरण के लिए अलग से मौजूद नहीं है और इसका उन कक्षाओं में एक स्वतंत्र अस्तित्व नहीं है जो मुझे विस्तारित करते हैं

क्या protectedमतलब है के बारे में सोचो :

इस चर को इस वर्ग द्वारा देखा जा सकता है, एक ही पैकेज में कक्षाएं और कक्षाएं जो मुझे विस्तारित करती हैं

दो अर्थ बिल्कुल परस्पर अनन्य नहीं हैं, लेकिन यह बहुत करीब है।

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

ज्यादातर मामलों में, स्थिरांक को सार्वजनिक करना बेहतर होगा क्योंकि यह सब कुछ साफ करता है और लोगों को अधिक लचीलेपन को उप-वर्गीकृत करने की अनुमति देता है। कई मामलों में कुछ और के अलावा रचना विरासत के लिए बेहतर है, जबकि सार कक्षाएं विरासत में मजबूर करती हैं।

यह कैसे चीजों को तोड़ सकता है इसका एक उदाहरण देखने के लिए और यह समझने के लिए कि चर से मेरा क्या मतलब है एक स्वतंत्र अस्तित्व नहीं है इस उदाहरण कोड की कोशिश करें:

public class Program {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println(new Test2().getTest());
        Test.test = "changed";
        System.out.println(new Test2().getTest());
    }
}

abstract class Test {
    protected static String test = "test";
}

class Test2 extends Test {
    public String getTest() {
        return test;
    }
}

आप परिणाम देखेंगे:

test
changed

इसे स्वयं आज़माएँ: https://ideone.com/KM8u8O

वर्ग नाम को अर्हता प्राप्त करने की आवश्यकता के बिना Test2स्थैतिक सदस्य testतक पहुंचने में सक्षम है Test- लेकिन यह विरासत में नहीं मिलता है या अपनी प्रतिलिपि प्राप्त नहीं करता है। यह स्मृति में ठीक उसी वस्तु को देख रहा है।


4
तुम लोग विरासत पर लटके हुए हो। विशिष्ट मामला जहां यह देखा जाता है कि कोई व्यक्ति इसे सार्वजनिक किए बिना पैकेज एक्सेस चाहता है (जैसे एक यूनिट टेस्ट)।
spudone

3
@spudone लेकिन इकाई परीक्षण आम तौर पर एक ही पैकेज में रखे जाते हैं। उन्हें एक्सेस देने के लिए आप केवल डिफ़ॉल्ट (पैकेज) एक्सेस स्तर का उपयोग करें। संरक्षित उपवर्गों तक पहुँच प्रदान करता है, जो इकाई परीक्षण के लिए आवश्यक या प्रासंगिक नहीं है।
टिम बी

1
@ कामाफेदर संरक्षित का मतलब है कि बच्चे आपको विभिन्न कक्षाओं से देख सकते हैं और एक ही पैकेज में कोई भी वर्ग आपको देख सकता है। तो हाँ प्रोग्राम एक ही पैकेज में है और इसलिए संरक्षित सदस्य देख सकते हैं।
टिम बी

2
" विस्तारित वर्ग तब व्यवहार को संशोधित कर सकता था " यह लिस्कोव सबसेंशन सिद्धांत का उल्लंघन होगा। एक उपवर्ग को सुपरटाइप के व्यवहार को संशोधित नहीं करना चाहिए। यह पूरी तरह से "एक वर्ग आयत नहीं है" तर्क के तहत आता है: Rectangleसमानता सुनिश्चित करने के लिए चौड़ाई (ऊंचाई) को समायोजित करने के लिए सुपरक्लास ( ) को समायोजित करना ( Squareयदि) आप उप-प्रकार के उदाहरण के साथ हर सुपरटेप को प्रतिस्थापित करने के लिए अवांछित परिणाम उत्पन्न करेंगे।
डाइऑक्सिन

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

32

यह विरोधाभासी होने के कारण इस पर आधारित है।

एक वैरिएबल बनाने का protectedअर्थ है कि इसका उपयोग पैकेज के भीतर किया जाएगा या इसे एक उपवर्ग के भीतर विरासत में मिलेगा ।

वैरिएबल बनाने staticसे यह वर्ग का सदस्य बन जाता है, जो इसे विरासत में लाने के इरादों को समाप्त करता है । यह केवल एक पैकेज के भीतर इस्तेमाल होने का इरादा छोड़ देता है , और हमारे पास इसके package-privateलिए (कोई संशोधक) नहीं है।

केवल यही स्थिति मैं इस के लिए उपयोगी पा सकता था यदि आप एक वर्ग की घोषणा कर रहे थे जिसका उपयोग एप्लिकेशन को लॉन्च करने के लिए किया जाना चाहिए (जैसे कि JavaFX Application#launch, और केवल एक उपवर्ग से लॉन्च करने में सक्षम होना चाहता था। यदि ऐसा कर रहे हैं, तो सुनिश्चित करें कि विधि भी finalहै। छिपाने को अस्वीकार करें । लेकिन यह "आदर्श" नहीं है, और संभवतः अनुप्रयोगों को लॉन्च करने के लिए एक नया तरीका जोड़कर अधिक जटिलता को रोकने के लिए लागू किया गया था।

प्रत्येक संशोधक के उपयोग के स्तर को देखने के लिए, इसे देखें: जावा ट्यूटोरियल - एक वर्ग के सदस्यों तक पहुंच को नियंत्रित करना


4
मुझे समझ में नहीं आता कि staticइसे विरासत में लेने के इरादे कैसे खत्म होंगे । क्योंकि एक अन्य पैकेज में मेरे उपवर्ग को अभी भी सुपर के क्षेत्र की आवश्यकता है protected, भले ही यह एक्सेस हो staticpackage-privateमदद नहीं कर सकता
अबो यांग

@AoboYang तुम सही हो, यही कारण है कि कुछ लोग उपयोग करते हैं protected static। लेकिन यह एक कोड गंध है, इसलिए " रन " भाग है। प्रवेश संशोधक और विरासत दो अलग-अलग विषय हैं। हां, यदि आप एक सुपर क्लास से स्थैतिक सदस्य तक पहुँच नहीं पाएंगे, तो यह था package-private। लेकिन आपको staticपहली जगह में संदर्भ क्षेत्रों पर विरासत पर भरोसा नहीं करना चाहिए ; यह खराब डिजाइन का संकेत है। आप ओवरराइडिंग के staticतरीकों पर प्रयासों को नोटिस करेंगे , कोई परिणाम नहीं देंगे, जो कि एक स्पष्ट संकेत है कि वंशानुक्रम वर्ग आधारित नहीं है। यदि आपको कक्षा या पैकेज के बाहर पहुंच की आवश्यकता है, तो यह होना चाहिएpublic
डाइऑक्सिन

3
मेरे पास private staticपहली बार कुछ उपयोग कार्यों के साथ एक वर्ग है , लेकिन मुझे लगता है कि कोई मेरी कक्षा से सुधार या अनुकूलित करना चाहता है और ये उपयोग कार्य उन्हें सुविधा भी प्रदान कर सकते हैं। publicउपयोग उचित नहीं हो सकता है क्योंकि उपयोग विधियां मेरे वर्ग के उदाहरणों के उपयोगकर्ता के लिए नहीं हैं। क्या आप मेरी मदद कर सकते हैं इसके बजाय एक अच्छे डिजाइन का पता लगाने में protected? धन्यवाद
Aobo यांग

उस लिंक में, यह कहता है 'सबसे अधिक प्रतिबंधात्मक पहुंच स्तर का उपयोग करें जो किसी विशेष सदस्य के लिए समझ में आता है। जब तक आपके पास कोई अच्छा कारण न हो, निजी का उपयोग करें। ' , जो इस प्रश्न से विरोधाभास है, कोई विचार?
सेसिलिया

13

मुझे कोई विशेष कारण नहीं दिखता है कि इस पर ध्यान क्यों दिया जाए। समान व्यवहार को प्राप्त करने के लिए हमेशा विकल्प हो सकते हैं, और यह वास्तविक योग्यता पर निर्भर करेगा कि ये विकल्प संरक्षित स्थैतिक विधि की तुलना में "बेहतर" हैं या नहीं। लेकिन एक उदाहरण जहां एक संरक्षित स्थैतिक विधि उचित होगी, कम से कम, निम्नलिखित हो सकती है:

( protectedस्पष्ट उपयोग करने के लिए, अलग-अलग पैकेज में विभाजित करने के लिए संपादित )

package a;
import java.util.List;

public abstract class BaseClass
{
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeDefaultB(list);
    }

    protected static Integer computeDefaultA(List<Integer> list)
    {
        return 12;
    }
    protected static Integer computeDefaultB(List<Integer> list)
    {
        return 34;
    }
}

उससे व्युत्पन्न:

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassA extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeOwnB(list);
    }

    private static Integer computeOwnB(List<Integer> list)
    {
        return 56;
    }
}

एक और व्युत्पन्न वर्ग:

package a.b;

import java.util.List;

import a.BaseClass;

abstract class ExtendingClassB extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeOwnA(list)+computeDefaultB(list);
    }

    private static Integer computeOwnA(List<Integer> list)
    {
        return 78;
    }
}

protected staticसंशोधक निश्चित रूप से यहाँ उचित हो सकता है:

  • विधियाँ हो सकती हैं static, क्योंकि वे उदाहरण चर पर निर्भर नहीं करती हैं। वे सीधे एक बहुरूपी विधि के रूप में उपयोग करने के लिए अभिप्रेत नहीं हैं, बल्कि "उपयोगिता" विधियां हैं जो डिफ़ॉल्ट कार्यान्वयन की पेशकश करती हैं जो एक अधिक जटिल संगणना का हिस्सा हैं, और वास्तविक कार्यान्वयन के "बिल्डिंग ब्लॉक" के रूप में काम करते हैं।
  • विधियों को नहीं होना चाहिए public, क्योंकि वे एक कार्यान्वयन विवरण हैं। और वे नहीं हो सकते privateक्योंकि उन्हें फैली हुई कक्षाओं द्वारा बुलाया जाना चाहिए। उनके पास "डिफ़ॉल्ट" दृश्यता भी नहीं हो सकती है, क्योंकि तब वे अन्य संकुल में फैली कक्षाओं के लिए सुलभ नहीं होंगे।

(संपादित करें: कोई यह मान सकता है कि मूल टिप्पणी केवल फ़ील्ड्स के लिए संदर्भित है , और विधियों के लिए नहीं - फिर, हालांकि, यह बहुत सामान्य था)


इस मामले में, आपको डिफ़ॉल्ट कार्यान्वयन को परिभाषित करना चाहिए protected final(चूंकि आप उन्हें ओवरराइड नहीं करना चाहते हैं), नहीं static। तथ्य यह है कि एक विधि उदाहरण चर का उपयोग नहीं करता है इसका मतलब यह नहीं होना चाहिए static(हालांकि यह हो सकता है )।
बारफिन

2
@ थोमस ज़रूर, इस मामले में, यह भी संभव होगा। सामान्य तौर पर: यह निश्चित रूप से आंशिक रूप से व्यक्तिपरक है, लेकिन मेरे अंगूठे का नियम है: जब एक विधि का उपयोग पॉलीमॉर्फिक रूप से उपयोग करने का इरादा नहीं है, और यह स्थिर हो सकता है, तो मैं इसे स्थिर बनाता हूं। यह बनाने के विपरीत final, यह न केवल स्पष्ट है कि विधि ओवरराइड करने का इरादा नहीं है करता है, यह अतिरिक्त पाठक उस विधि उदाहरण चर का उपयोग नहीं करता है के लिए स्पष्ट करता है। इसलिए पूरी तरह से: बस इसे स्थिर नहीं बनाने का कोई कारण नहीं है
मार्को 13

1
जब एक विधि का उपयोग बहुरूपिक रूप से करने का इरादा नहीं है, और यह स्थिर हो सकता है, तो मैं इसे स्थिर बनाता हूं। - यह आपको मुसीबत में तब डालेगा जब आप यूनिट टेस्टिंग के लिए मॉक फ्रेमवर्क का इस्तेमाल करना शुरू करेंगे। लेकिन यह हमें एक अलग विषय की ओर ले जाता है ...
बरफिन

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

@ यूजीन कि टिप्पणी मुझे थोड़ा परेशान करती है। पैकेज-दृश्यता को किसी भी संशोधक के बिना प्राप्त किया जा सकता है, जबकि protected"इनहेरिटिंग क्लासेस (यहां तक ​​कि विभिन्न पैकेजों में)" का
अर्थ है

7

स्थैतिक सदस्यों को विरासत में नहीं मिला है, और संरक्षित सदस्य केवल उपवर्गों (और निश्चित रूप से युक्त वर्ग) के लिए दृश्यमान हैं, इसलिए कोडर द्वारा गलतफहमी का सुझाव देने protected staticके समान दृश्यता है static


1
क्या आप अपने पहले बयान के लिए एक स्रोत प्रदान कर सकते हैं? एक त्वरित परीक्षण में, एक संरक्षित स्थैतिक इंट को विरासत में मिला और एक समस्या के बिना उपवर्ग में पुन: उपयोग किया गया।
hiergiltdiestfu

संरक्षित स्टेटिक में पैकेज-प्राइवेट स्टेटिक के समान दृश्यता होती है, निजी स्थिर नहीं। इसे जोड़ने के लिए, यदि आप संरक्षित और स्थैतिक उपयोग कर रहे हैं, तो इसे पैकेज-निजी बनाने के लिए एक्सेस मॉडिफायर को हटाने का सबसे अच्छा तरीका है (यदि आपके इरादे पैकेज के भीतर इसे एक्सेस करने योग्य थे)
Dioxin

2
उम्म… नहीं। पैकेज निजी और protectedसमान नहीं हैं। यदि आप कहते हैं static, तो फ़ील्ड केवल एक ही पैकेज में उपवर्गों को दिखाई देती है।
आरोन दिगुल्ला

1
@AaronDigulla पैकेज के भीतर या उपवर्ग सेprotected static पहुंच की अनुमति देता है । एक वैरिएबल स्टैटिक बनाने से सबक्लासिंग के इरादे दूर हो जाते हैं, जिससे एकमात्र इरादा पैकेज के भीतर से एक्सेस हो जाता है।
डाइऑक्सिन

@VinceEmigh: क्षमा करें, मैं बोहेमियन से बात कर रहा था। इसे और स्पष्ट करना चाहिए था।
आरोन दिगुल्ला

5

वास्तव में मौलिक रूप से कुछ भी गलत नहीं है protected static। यदि आप वास्तव में एक स्थिर चर या विधि चाहते हैं जो पैकेज के लिए दिखाई दे रही है और घोषित वर्ग के सभी उपवर्ग हैं तो आगे बढ़ें और इसे बनाएं protected static

कुछ लोग आम तौर पर protectedविभिन्न कारणों से उपयोग करने से बचते हैं और कुछ लोगों को लगता है कि गैर-अंतिम staticचर को हर तरह से टाला जाना चाहिए (मैं व्यक्तिगत रूप से कुछ हद तक उत्तरार्द्ध के साथ सहानुभूति रखता हूं), इसलिए मुझे लगता है कि संयोजन संयोजन protectedऔर बुरेstatic दिखना चाहिए ^ 2 उन लोगों के लिए दोनों समूहों के हैं।


3

संरक्षित का उपयोग किया जाता है ताकि इसका उपयोग उपवर्गों में किया जा सके। कंक्रीट कक्षाओं के संदर्भ में उपयोग करते समय एक संरक्षित स्थैतिक को परिभाषित करने में कोई तर्क नहीं है क्योंकि आप एक ही चर का उपयोग कर सकते हैं एक स्थिर तरीका है। कभी-कभी सुपर क्लास स्थैतिक चर को स्थिर तरीके से उपयोग करने की चेतावनी देगा।


1

खैर, जैसा कि अधिकांश लोगों ने उत्तर दिया है:

  • protectedका अर्थ है - ' उप-वर्ग के लिए पैकेज-निजी + दृश्यता - संपत्ति / व्यवहार INHERITED है '
  • staticइसका अर्थ है - ' उदाहरण के विपरीत - यह एक वर्गीय संपत्ति / व्यवहार है, अर्थात यह अपरिहार्य नहीं है '

इसलिए वे थोड़े विरोधाभासी और असंगत हैं।

हालाँकि, हाल ही में मैं एक उपयोग के मामले में आया था जहाँ इन दोनों को एक साथ उपयोग करने का कोई अर्थ हो सकता है। कल्पना कीजिए कि आप एक ऐसा abstractवर्ग बनाना चाहते हैं, जो अपरिवर्तनीय प्रकारों के लिए एक माता-पिता हो और इसमें गुणों का एक समूह हो, जो उपप्रकारों के लिए आम हैं। अपरिवर्तनीयता को ठीक से लागू करने और पठनीयता बनाए रखने के लिए बिल्डर पैटर्न का उपयोग करने का निर्णय ले सकता है ।

package X;
public abstract class AbstractType {
    protected Object field1;
    protected Object field2;
    ...
    protected Object fieldN;

    protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
        private Object field1; // = some default value here
        private Object field2; // = some default value here
        ...
        private Object fieldN; // = some default value here

        public T field1(Object value) { this.field1 = value; return self();}
        public T field2(Object value) { this.field2 = value; return self();}
        ...
        public T fieldN(Object value) { this.fieldN = value; return self();}
        protected abstract T self(); // should always return this;
        public abstract AbstractType build();
    }

    private AbstractType(BaseBuilder<?> b) {
        this.field1 = b.field1;
        this.field2 = b.field2;
        ...
        this.fieldN = b.fieldN;
    }
}

और क्यों protected static? क्योंकि मैं एक गैर-अमूर्त उपप्रकार चाहता हूं, AbstactTypeजिसके अपने गैर-अमूर्त बिल्डर को लागू किया जाता है और बाहर package Xतक पहुँचने और पुन: उपयोग करने में सक्षम होने के लिए बाहर स्थित है BaseBuilder

package Y;
public MyType1 extends AbstractType {
    private Object filedN1;

    public static class Builder extends AbstractType.BaseBuilder<Builder> {
        private Object fieldN1; // = some default value here

        public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
        @Override protected Builder self() { return this; }
        @Override public MyType build() { return new MyType(this); }
    }

    private MyType(Builder b) {
        super(b);
        this.fieldN1 = b.fieldN1;
    }
}

बेशक हम BaseBuilderसार्वजनिक कर सकते हैं लेकिन फिर हम एक और विरोधाभासी बयान पर आते हैं:

  • हमारे पास एक गैर-तत्काल वर्ग (सार) है
  • हम इसके लिए एक सार्वजनिक बिल्डर प्रदान करते हैं

इसलिए, दोनों मामलों में protected staticऔर हम publicएक बिल्डर केabstract class विरोधाभासी बयानों को जोड़ते हैं। यह व्यक्तिगत प्राथमिकताओं की बात है।

हालांकि, मैं अभी भी एक publicबिल्डर कोabstract class पसंद करता हूं क्योंकि protected staticमेरे लिए एक OOD और OOP दुनिया में अधिक अप्राकृतिक लगता है!


0

होने में कुछ गलत नहीं है protected static। एक बात बहुत से लोग देख रहे हैं कि आप स्थैतिक तरीकों के लिए परीक्षण के मामले लिखना चाहते हैं जिन्हें आप सामान्य परिस्थितियों में उजागर नहीं करना चाहते हैं। मैंने देखा है कि यह उपयोगिता वर्गों में स्थिर विधि के लिए परीक्षण लिखने के लिए विशेष रूप से उपयोगी है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.