जावा में मार्कर इंटरफेस?


134

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

लेकिन हाल ही में मैंने सीखा है कि इसका वास्तव में कंपाइलर या जेवीएम से कोई लेना-देना नहीं है। उदाहरण के लिए, Serializableइंटरफ़ेस के मामले में , विधि writeObject(Object)का पता लगाने के लिए ObjectOutputStreamकुछ करना पसंद instanceOf Serializableहै कि क्या वर्ग तदनुसार लागू करता है Serializableऔर फेंकता है NotSerializableException। सब कुछ कोड में संभाला जाता है और यह एक डिज़ाइन-पैटर्न प्रतीत होता है, इसलिए मुझे लगता है कि हम अपने स्वयं के मार्कर इंटरफेस को परिभाषित कर सकते हैं।

अब मेरी शंका:

  1. क्या 1 बिंदु में ऊपर उल्लिखित मार्कर इंटरफ़ेस की परिभाषा गलत है? हम फिर एक मार्कर इंटरफ़ेस कैसे परिभाषित कर सकते हैं?

  2. और instanceOfऑपरेटर का उपयोग करने के बजाय विधि कुछ ऐसा क्यों नहीं हो सकताwriteObject(Serializable) ताकि रनटाइम के बजाय एक संकलन-समय प्रकार की जाँच हो?

  3. मार्कर इंटरफेसेस की तुलना में एनोटेशन कैसे बेहतर हैं?


8
Serializableएनोटेशन बकवास है और @NonNullइंटरफ़ेस के रूप में बकवास है। मैं कहूंगा: एनोटेशन मार्कर + मेटाडेटा हैं। BTW: फॉरएफ्टनर ऑफ़ एनोटेशन्स XDoclet था, जिसका जन्म जावेदोक में हुआ था, जो एनोटेशन द्वारा मारा गया था।
ग्रिम

जवाबों:


117
  1. 1 अंक में ऊपर उल्लिखित मार्कर इंटरफ़ेस की परिभाषा गलत है? - यह उन हिस्सों में सही है कि (1) एक मार्कर इंटरफ़ेस खाली होना चाहिए, और (2) इसे लागू करने का मतलब कार्यान्वयन वर्ग के कुछ विशेष उपचार का मतलब है। जो हिस्सा गलत है वह यह है कि इसका मतलब है कि जेवीएम या कंपाइलर उस वर्ग की वस्तुओं का अलग तरह से व्यवहार करेंगे: आप यह देखने में सही हैं कि यह जावा क्लास लाइब्रेरी का कोड है जो इन वस्तुओं को क्लोन करने योग्य, क्रमबद्ध करने योग्य, इत्यादि के रूप में व्यवहार करता है। संकलक या जेवीएम के साथ कुछ नहीं करना है।
  2. इंस्टाफॉरेप्टर ऑपरेटर का उपयोग करने के बजाय विधि कुछ ऐसा क्यों नहीं हो सकता है writeObject(Serializable)ताकि एक संकलन-समय प्रकार की जाँच हो सके - यह आपको "सादा Object" की आवश्यकता होने पर मार्कर इंटरफ़ेस के नाम के साथ अपने कोड को प्रदूषित करने से बचाता है। उदाहरण के लिए, यदि आप एक ऐसा वर्ग बनाते हैं, जिसे क्रमबद्ध होने की आवश्यकता है, और जिसमें ऑब्जेक्ट सदस्य हैं, तो आपको या तो कास्टिंग करने के लिए मजबूर किया जाएगा या Serializableसंकलन समय पर अपनी वस्तुओं को बनाने के लिए। यह असुविधाजनक है, क्योंकि इंटरफ़ेस किसी भी कार्यक्षमता से रहित है।
  3. मार्कर इंटरफेसेस की तुलना में एनोटेशन कैसे बेहतर हैं? - वे आपको इसके लिए एक अलग प्रकार का निर्माण किए बिना अपने उपभोक्ताओं को वर्ग के बारे में मेटाडेटा व्यक्त करने का एक ही उद्देश्य प्राप्त करने देते हैं। एनोटेशन अधिक शक्तिशाली होते हैं, साथ ही, प्रोग्रामर कक्षाओं को अधिक परिष्कृत जानकारी देते हैं जो इसे "उपभोग" करते हैं।

14
जिस तरह से मैंने हमेशा यह समझा है कि एनोटेशन एक तरह का 'मार्कर इंटरफेसेस 2.0' है: जावा 1.1 के बाद से सीरियल करने योग्य मौजूद है, एनोटेशन 1.5 में जोड़ा गया
ब्लाग

और क्योंकि writeObjectनिजी है, इसका मतलब है कि उदाहरण के लिए एक वर्ग को सुपरक्लास कार्यान्वयन को कॉल करने की आवश्यकता नहीं है
शाफ़्ट सनकी

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

ठीक है, के मामले में Cloneableयह स्पष्ट नहीं है कि यह लाइब्रेरी या जेवीएम द्वारा बदले गए उदाहरण का उपचार है या नहीं।
होल्गर

"[...] इसके लिए एक अलग प्रकार का निर्माण किए बिना।" - मैं कहेंगे कि यह ठीक है कि क्या उन्हें अलग: एक मार्कर इंटरफ़ेस करता है एक प्रकार का परिचय है, जबकि एनोटेशन (तरह का) शामिल नहीं है।
एरियोब

22

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

   Object x = "abc";
   if (x instanceof Serializable) {
   }

मूल श्रेणी ( Object) क्रमबद्ध नहीं है और इसके पैरामीटर-कम कंस्ट्रक्टर का उपयोग करके आरंभ किया जाएगा। द्वारा संदर्भित मूल्य x, String, serializable है और सशर्त बयान चलाए जा सकें।


6

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

ऊपर एक ब्लॉग पोस्ट की एक प्रति के रूप में शुरू किया गया है लेकिन व्याकरण के लिए हल्के ढंग से संपादित किया गया है।


6
कॉपी करना ठीक है, लेकिन कृपया स्रोत का भी उल्लेख करें: javarevisited.blogspot.com/2012/01/… । इसके अलावा, यह अच्छा होगा यदि आप वर्तनी त्रुटियों को भी कॉपी न करें। :)
सौरभ पाटिल

6

मैंने संदेह 1 और 2 को हल करने के लिए एक सरल प्रदर्शन किया है:

हमारे पास जंगम इंटरफ़ेस होगा जो कि MobilePhone.javaकक्षा द्वारा लागू किया जाएगा और एक और वर्ग LandlinePhone.javaजो ऐसा नहीं करता है चल इंटरफ़ेस को लागू

हमारा मार्कर इंटरफ़ेस:

package com;

public interface Movable {

}

LandLinePhone.java तथा MobilePhone.java

 package com;

 class LandLinePhone {
    // more code here
 }
 class MobilePhone implements Movable {
    // more code here
 }

हमारे कस्टम अपवाद कक्षा: पैकेज कॉम;

public class NotMovableException extends Exception {

private static final long serialVersionUID = 1L;

    @Override
    public String getMessage() {
        return "this object is not movable";
    }
    // more code here
    }

हमारी टेस्ट क्लास: TestMArkerInterface.java

package com;

public class TestMarkerInterface {

public static void main(String[] args) throws NotMovableException {
    MobilePhone mobilePhone = new MobilePhone();
    LandLinePhone landLinePhone = new LandLinePhone();

    TestMarkerInterface.goTravel(mobilePhone);
    TestMarkerInterface.goTravel(landLinePhone);
}

public static void goTravel(Object o) throws NotMovableException {
    if (!(o instanceof Movable)) {
        System.out.println("you cannot use :" + o.getClass().getName() + "   while travelling");
        throw new NotMovableException();
    }

    System.out.println("you can use :" + o.getClass().getName() + "   while travelling");
}}

अब जब हम मुख्य वर्ग को निष्पादित करते हैं:

you can use :com.MobilePhone while travelling
you cannot use :com.LandLinePhone while travelling
Exception in thread "main" com.NotMovableException: this object is not movable
    at com.TestMarkerInterface.goTravel(TestMarkerInterface.java:22)
    at com.TestMarkerInterface.main(TestMarkerInterface.java:14)

तो जो कभी वर्ग मार्कर इंटरफ़ेस लागू करता है Movable को पास करेगा, परीक्षण त्रुटि संदेश प्रदर्शित होगा।

यह जिस तरह से instanceOfऑपरेटर की जाँच Serializable , Cloneable आदि के लिए की जाती है


5

a / A मार्कर इंटरफ़ेस जैसा कि इसके नाम से ही पता चलता है कि इसके बारे में जानने वाले किसी भी व्यक्ति को सूचित करने के लिए मौजूद है कि एक वर्ग कुछ घोषित करता है। Serializableइंटरफ़ेस के लिए JDK कक्षाएं कुछ भी हो सकती हैं , या कोई भी वर्ग जो आप कस्टम के लिए अपना लेखन करते हैं।

b / यदि यह एक मार्कर इंटरफ़ेस है, तो यह किसी भी विधि का अस्तित्व नहीं होना चाहिए - इंटरफ़ेस में निहित विधि को शामिल करना बेहतर होगा। लेकिन आप इसे डिजाइन करने का निर्णय ले सकते हैं जैसा आप चाहते हैं कि आप जानते हैं कि आप क्यों इसकी आवश्यकता है

c / एक खाली इंटरफ़ेस और एक एनोटेशन के बीच बहुत कम अंतर है जो बिना मूल्य या पैरामीटर का उपयोग करता है। लेकिन अंतर यह है: एक एनोटेशन उन चाबियों / मूल्यों की एक सूची की घोषणा कर सकता है जो रन टाइम पर सुलभ होंगे।


3

ए। मैंने हमेशा उन्हें एक डिज़ाइन पैटर्न के रूप में देखा है और कुछ भी नहीं JVM-Special मैंने कई स्थितियों में उस पैटर्न का उपयोग किया है।

सी। मुझे लगता है कि कुछ चिन्हों को चिन्हित करने के लिए मार्कर इंटरफेस का उपयोग करना बेहतर समाधान है। सिर्फ इसलिए कि टाइप्स / क्लासेस के सामान्य इंटरफेस को परिभाषित करने के उद्देश्य से इंटरफेस पहले स्थान पर हैं। वे वर्ग-श्रेणी का हिस्सा हैं।

एनोटेशन का उद्देश्य कोड को मेटा-इनफॉर्मेशन प्रदान करना है, और मुझे लगता है कि मार्कर मेटा-informations हैं। तो वे वास्तव में उस उपयोग-मामले के लिए हैं।


3
  1. जेवीएम और संकलक के साथ इसका (आवश्यक) कुछ भी नहीं है, इसका किसी भी कोड के साथ कुछ करना है जो किसी रुचि वाले इंटरफ़ेस के लिए परीक्षण कर रहा है और कर रहा है।

  2. यह एक डिजाइन निर्णय है और यह एक अच्छे कारण के लिए किया गया है। ऑड्रियस मेकॉस्कस से उत्तर देखें।

  3. इस विशेष विषय के संबंध में, मुझे नहीं लगता कि यह बेहतर या बदतर होने की बात है। मार्कर इंटरफ़ेस वही कर रहा है जो इसे ठीक करने वाला है।


क्या आप "ऑड्रियस मेककॉस्कस से जवाब" के लिए एक लिंक जोड़ सकते हैं? मुझे इस नाम के साथ इस पृष्ठ पर कुछ भी दिखाई नहीं दे रहा है।
सारा मेसर

2

मार्कर इंटरफेस का मुख्य उद्देश्य विशेष प्रकार का निर्माण करना है जहां प्रकारों का स्वयं का कोई व्यवहार नहीं है।

public interface MarkerEntity {

}

public boolean save(Object object) throws InvalidEntityFoundException {
   if(!(object instanceof MarkerEntity)) {
       throw new InvalidEntityFoundException("Invalid Entity Found, can't be  saved);
   } 
   return db.save(object);
}

यहां सेव मेथड यह सुनिश्चित करता है कि मार्केरनेट इंटरफेस को लागू करने वाली कक्षाओं की केवल ऑब्जेक्ट्स को ही बचाया जाए, अन्य प्रकार के लिए InvalidEntityFoundException को फेंक दिया जाता है। तो यहाँ MarkerEntity मार्कर इंटरफ़ेस एक प्रकार को परिभाषित कर रहा है जो इसे लागू करने वाली कक्षाओं के लिए विशेष व्यवहार जोड़ता है।

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

लेकिन मार्कर एनोटेशन पूरी तरह से मार्कर इंटरफेस की जगह नहीं ले सकते क्योंकि; मार्कर इंटरफेस का उपयोग प्रकार को परिभाषित करने के लिए किया जाता है (जैसा कि पहले ही ऊपर बताया गया है) जहां मार्कर एनोटेशन नहीं होते हैं।

मार्कर इंटरफ़ेस टिप्पणी के लिए स्रोत


1
+1 यह दिखाने के लिए कि इसका वास्तव में "सुरक्षा" हुक के रूप में उपयोग किया जाता है, जिसे प्रोग्रामर को स्पष्ट रूप से यह कहना पड़ता है कि इसे डेटाबेस का उदाहरण देने के लिए सहेजा जा सकता है।
लुडविग डब्ल्यू

1

मैं सबसे पहले यह तर्क दूंगा कि सीरियल करने योग्य और क्लोन करने योग्य मार्कर इंटरफेस के बुरे उदाहरण हैं। यकीन है, वे तरीकों के साथ इंटरफेस कर रहे हैं, लेकिन वे इस तरह के तरीकों, मतलब हैwriteObject(ObjectOutputStream) । ( writeObject(ObjectOutputStream)यदि आप इसे ओवरराइड नहीं करते हैं और आपके पास पहले से clone()मौजूद सभी ऑब्जेक्ट हैं , तो कंपाइलर आपके लिए एक clone()विधि बनाएगा, लेकिन कंपाइलर फिर से आपके लिए एक वास्तविक विधि बनाएगा, लेकिन कैविटीज़ के साथ। ये दोनों अजीब एज केस हैं जो वास्तव में नहीं हैं। अच्छा डिजाइन उदाहरण।)

मार्कर इंटरफेस आमतौर पर दो उद्देश्यों में से एक के लिए उपयोग किए जाते हैं:

1) अत्यधिक लंबे प्रकार से बचने के लिए एक शॉर्टकट के रूप में, जो बहुत सारी जेनरिक के साथ हो सकता है। उदाहरण के लिए, मान लें कि आपके पास यह विधि हस्ताक्षर है:

public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }

यह टाइप करने के लिए गन्दा और कष्टप्रद है, और इससे भी महत्वपूर्ण बात, समझना मुश्किल है। इसके बजाय इस पर विचार करें:

public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }

तब आपकी विधि इस प्रकार दिखती है:

public void doSomething(Widget widget) { ... }

न केवल यह स्पष्ट है, बल्कि अब आप विजेट इंटरफ़ेस जावदोक कर सकते हैं, और यह आपके विजेट के कोड में सभी घटनाओं की खोज करना भी आसान है।

2) मार्कर इंटरफेस का उपयोग जावा के चौराहे प्रकारों की कमी के आसपास भी किया जा सकता है। एक मार्कर इंटरफ़ेस के साथ, आपको दो अलग-अलग प्रकारों के लिए कुछ की आवश्यकता हो सकती है, जैसे कि विधि हस्ताक्षर। मान लें कि आपके आवेदन में कुछ इंटरफ़ेस विजेट हैं, जैसे कि हमने ऊपर वर्णित किया है। यदि आपके पास एक ऐसी विधि है जिसके लिए एक विजेट की आवश्यकता होती है जो आपको उस पर पुनरावृति करने के लिए भी होता है (यह विवादित है, लेकिन मेरे साथ यहां काम करें), आपका एकमात्र अच्छा समाधान एक मार्कर इंटरफ़ेस बनाना है जो दोनों इंटरफेस का विस्तार करता है:

public interface IterableWidget extends Iterable<String>, Widget { }

और आपके कोड में:

public void doSomething(IterableWidget widget) {
    for (String s : widget) { ... }
}

1
संकलक करता है नहीं किसी भी तरीकों बनाने यदि आपका वर्ग औजार Serializableया Cloneable। आप अपनी कक्षा की फाइलों का निरीक्षण करके इसे सत्यापित कर सकते हैं। इसके अलावा, "शॉर्टकट इंटरफेस" बनाना मार्कर इंटरफेस के बारे में क्या नहीं है। और यह एक वास्तविक खराब कोडिंग अभ्यास है क्योंकि इसके लिए अतिरिक्त इंटरफेस को पूरा करने के लिए अतिरिक्त कार्यान्वयन कक्षाएं बनाने की आवश्यकता होगी । वैसे, जावा में अब एक दशक से चौराहे प्रकार हैं। जेनरिक के बारे में जानें ...
होल्गर

क्लोन करने योग्य के लिए, आप सही हैं। यह करता है क्या Object.clone () करता है। यह अभी भी भयानक है। जोश बलोच लिंक देखें शॉर्टकट इंटरफेस जरूरी अच्छा डिज़ाइन पैटर्न नहीं है, जैसा कि आप मनमाने ढंग से प्रतिबंधित करते हैं कि आप एक विधि को क्या भेज सकते हैं। उसी समय, मुझे लगता है कि स्पष्ट लेखन, यदि थोड़ा अधिक प्रतिबंधक कोड, आमतौर पर एक उचित व्यापार है। चौराहे प्रकारों के लिए, यह केवल जेनरिक पर लागू होता है, और गैर-संप्रदायी होते हैं, और इस प्रकार कई अवसरों में बेकार हो जाते हैं। एक उदाहरण चर होने की कोशिश करें जो कि धारावाहिक और, अच्छी तरह से, कुछ भी हो।
मिकीबी

0

यदि किसी इंटरफ़ेस में कोई विधि नहीं है और उस इंटरफ़ेस को लागू करने से यदि हमारी वस्तु को कुछ क्षमता मिलेगी तो इस प्रकार के इंटरफेस को मार्कर इंटरफेस कहा जाता है।

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