Java'da Marker Arayüzleri?


134

Java'daki Marker arayüzünün boş bir arayüz olduğu ve bu arayüzü uygulayan sınıfın nesnelerine serileştirme, klonlama vb.

Ancak son zamanlarda bunun derleyici veya JVM ile hiçbir ilgisi olmadığını öğrendim. Örneğin, söz konusu Serializablearabirim yöntemi writeObject(Object)arasında ObjectOutputStreamböyle bir şey yapar instanceOf Serializablesınıfının uyguladığı olmadığını tespit etmek için Serializableve atar NotSerializableExceptionbuna göre. Her şey kodunda ele alınır ve bu bir tasarım deseni gibi görünüyor, bu yüzden kendi marker arayüzlerimizi tanımlayabileceğimizi düşünüyorum.

Şimdi şüphelerim:

  1. Yukarıda 1. maddede belirtilen bir işaretleyici arabiriminin tanımı yanlış mı? O zaman bir Marker arayüzünü nasıl tanımlayabiliriz?

  2. Ve instanceOfişleci kullanmak yerine , yöntem neden writeObject(Serializable)çalışma zamanı yerine derleme zamanı türü denetimi olacak şekilde bir şey olamaz?

  3. Ek Açıklamalar Marker Arayüzlerinden nasıl daha iyidir?


8
SerializableEk Açıklama saçmadır ve @NonNullArayüz saçmadır. Şunu söyleyebilirim: Ek açıklamalar Marker + Meta verilerdir. BTW: Ek Açıklamaların İşveren'i, Javadoc'ta doğan ve Ek Açıklamalar tarafından öldürülen XDoclet idi.
Grim

Yanıtlar:


117
  1. Yukarıda 1. maddede belirtilen bir işaretleyici arabiriminin tanımı yanlış mı? - (1) Bir marker arayüzünün boş olması ve (2) uygulanması, uygulayıcı sınıfın bazı özel muamelelerini ima etmesi gerektiği kısımlarında doğrudur. Yanlış olan bölüm, JVM veya derleyicinin bu sınıftaki nesnelere farklı davranacağını ima etmesidir: bu nesneleri klonlanabilir, serileştirilebilir vb. derleyici veya JVM ile ilgisi yoktur.
  2. instanceOf operatörünü kullanmak yerine, neden writeObject(Serializable)derleme zamanı tür denetimi yapmak için yöntem böyle bir şey olamaz - Bu, bir "düz Object" gerektiğinde kodunuzu işaretleyici arabiriminin adıyla kirletmekten kaçınmanızı sağlar . Örneğin, serileştirilebilir olması gereken ve nesne üyeleri olan bir sınıf yaparsanız Serializable, derleme sırasında ya döküm yapmak ya da nesnelerinizi yapmak zorunda kalırsınız . Arayüz herhangi bir işlevsellikten yoksun olduğu için bu elverişsizdir.
  3. Ek Açıklamalar Marker Arayüzlerinden Nasıl Daha İyi? - Sınıfla ilgili meta verileri, kendisi için ayrı bir tür oluşturmadan tüketicilerine iletmekle aynı amaca ulaşmanızı sağlarlar. Ek açıklamalar da daha güçlüdür, programcıların "tüketen" sınıflara daha sofistike bilgi aktarmalarına izin verir.

14
Her zaman anladığım şekilde, Ek Açıklamaların bir tür 'Marker Arayüzleri 2.0' olduğu
söylenebilir

ve writeObjectözel olduğu için, bu, örneğin bir sınıfın üst sınıf uygulamasını çağırması gerekmediği anlamına gelir
cırcır ucube

15
Akılda tutulması gereken bir şey, standart kütüphanenin orijinal olarak tasarlanmasından yıllar sonra dile ek açıklamaların eklenmiş olmasıdır. Ek açıklamalar başlangıçtan itibaren dilde olsaydı, Serializable'ın bir arabirim olacağı şüphelidir, muhtemelen bir ek açıklama olurdu.
Theodore Norvell

Peki, Cloneabledeğişmiş örneğin bir kütüphane mi yoksa JVM mi olduğu belli değil.
Holger

"[...] bunun için ayrı bir tür oluşturmadan." Bir işaret arayüzü: - Bu onları ayıran şeydir söyleyebilirim yapar , bir tür tanıtmak ek açıklamalar (tür) ise does't.
aioobe

22

Zorlamak mümkün değildir Serializableüzerinde writeObjectserileştirilebilir olmayan sınıfın çocukları seri olabilir çünkü ama onların örneklerini üst sınıfa upcasted geri olabilir. Sonuç olarak, serileştirilemeyen (örneğin Object) bir şeye başvurmak , söz konusu örneğin gerçekten serileştirilemeyeceği anlamına gelmez. Örneğin

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

üst sınıf ( Object) serileştirilemez ve parametresiz yapıcı kullanılarak başlatılır. x,, Tarafından başvurulan değer Stringserileştirilebilir ve koşullu ifade çalışır.


6

Java'da bir işaretçi arabirimi, alan veya yöntem içermeyen bir arabirimdir. Daha basit bir ifadeyle, Java'daki boş bir arayüze işaretleyici arabirimi denir. İşaretleyici arabirimlere örnek Serializable, Cloneableve Remotearabirimlerdir. Bunlar derleyicilere veya JVM'lere bazı bilgileri belirtmek için kullanılır. Dolayısıyla, JVM bir sınıf olduğunu görürse, Serializableüzerinde bazı özel işlemler yapabilir. Benzer şekilde, JVM bir sınıfın uygulandığını görürse Cloneable, klonlamayı desteklemek için bazı işlemler gerçekleştirebilir. Aynı şey RMI ve Remotearayüz için de geçerlidir . Kısacası, bir işaretleyici arayüzü derleyiciye veya JVM'ye bir sinyal veya komut gösterir.

Yukarıdakiler bir blog yayınının bir kopyası olarak başladı, ancak dilbilgisi için hafifçe düzenlendi.


6
Kopyalamakta sorun yok ama lütfen kaynağı da belirtin : javarevisited.blogspot.com/2012/01/… . Ayrıca yazım hatalarını da kopyalamıyorsanız iyi olur. :)
Saurabh Patil

6

1 ve 2 numaralı şüpheleri çözmek için basit bir gösteri yaptım:

Biz Hareketli tarafından uygulanacak arayüze sahip olacak MobilePhone.javaClass ve bir daha sınıf LandlinePhone.javado DEĞİL Hareketli arabirimini uygulamak

Marker Arayüzümüz:

package com;

public interface Movable {

}

LandLinePhone.java ve MobilePhone.java

 package com;

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

Özel İstisna Sınıfımız: package com;

public class NotMovableException extends Exception {

private static final long serialVersionUID = 1L;

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

Test sınıfımız: 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");
}}

Şimdi ana sınıfı yürüttüğümüzde:

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)

Böylece hangi sınıf uygulayan marker arayüzü Movabletesti geçecek başka hata mesajı görüntülenecektir.

Seri , Klonlanabilir vb. instanceOfİçin operatör kontrolünün yapılma şekli budur.


5

a / A işaretleyici arabirimi, adından da anlaşılacağı gibi, yalnızca bir sınıfın bir şey bildirdiğini bilen her şeyi bildirmek için vardır. Her şey, Serializablearabirim için JDK sınıfları veya özel bir sınıf için kendi yazdığınız herhangi bir sınıf olabilir.

b / Bir işaretleyici arayüzü ise, herhangi bir yöntemin varlığını ima etmemelidir - ima edilen yöntemin arayüze dahil edilmesi daha iyi olacaktır. Eğer biliyorsanız istediğiniz kadar Ama bunu tasarlamak için karar verebilir neden sen lüzum

c / Boş bir arabirim ile değer veya parametre kullanmayan bir ek açıklama arasında çok az fark vardır. Ancak fark var: bir açıklama, çalışma zamanında erişilebilecek anahtarların / değerlerin bir listesini bildirebilir.


3

a. Onları her zaman bir tasarım deseni olarak gördüm ve JVM-Special hiçbir şey Bu deseni birkaç durumda kullandım.

c. Bir şeyi işaretlemek için Ek Açıklamalar kullanmanın işaretleyici arayüzlerini kullanmaktan daha iyi bir çözüm olduğuna inanıyorum. Çünkü Arayüzler ilk etapta Türler / Sınıfların ortak arayüzlerini tanımlamayı amaçlamaktadır. Sınıf hiyerarşisinin bir parçasıdırlar.

Ek açıklamalar, Kod'a Meta Bilgi sağlamayı amaçlamaktadır ve bence bu işaretin meta bilgi olduğunu düşünüyorum. Yani tam olarak bu kullanım için.


3
  1. JVM ve derleyicilerle (mutlaka) ilgisi yoktur, belirli bir işaretleyici arayüzü ile ilgilenen ve test eden herhangi bir kodla ilgisi vardır.

  2. Bu bir tasarım kararı ve bunun iyi bir nedeni var. Audrius Meškauskas'ın cevabına bakınız.

  3. Bu konu ile ilgili olarak, bunun daha iyi veya daha kötü olma meselesi olduğunu düşünmüyorum. Marker arayüzü, iyi yapması gereken şeyi yapıyor.


"Audrius Meškauskas'ın cevabı" na link ekleyebilir misiniz? Bu sayfada bu ada sahip hiçbir şey görmüyorum.
Sarah Messer

2

Marker arayüzlerinin temel amacı, tiplerin kendilerine ait davranışları olmayan özel tipler yaratmaktır.

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);
}

Burada save yöntemi, yalnızca MarkerEntity arabirimini uygulayan sınıf nesnelerinin kaydedildiğinden emin olur, diğer türler için InvalidEntityFoundException atılır. Burada MarkerEntity işaretleyici arayüzü, onu uygulayan sınıflara özel davranışlar ekleyen bir tür tanımlamaktadır.

Ek açıklamalar şimdi bazı özel tedaviler için sınıfları işaretlemek için de kullanılabilir, ancak işaretleyici ek açıklamalar Marker arabirimleri için değil adlandırma modelinin yerini almıştır.

Ancak işaretçi ek açıklamaları işaretçi arabirimlerinin yerini tamamen alamaz çünkü; işaretleyici arabirimleri, işaretçi ek açıklamalarının belirtmediği türü (yukarıda açıklandığı gibi) tanımlamak için kullanılır.

İşaretleyici arayüzü yorumu için kaynak


1
+1, aslında bir programcının açıkça bir veritabanına kaydedilebileceğini söylemek zorunda olduğu bir "güvenlik" kancası olarak kullanıldığını göstermek için.
Ludvig K

1

Öncelikle, Serializable ve Cloneable'un marker arayüzlerinin kötü örnekleri olduğunu iddia ediyorum. Tabii, bunlar yöntemlerle arayüzler, ancak gibi yöntemler ima ediyorlar writeObject(ObjectOutputStream). (Derleyici, writeObject(ObjectOutputStream)geçersiz kılmadıysanız ve zaten tüm nesneler varsa, sizin için bir yöntem oluşturur clone(), ancak derleyici yine clone()sizin için ancak uyarılarla gerçek bir yöntem oluşturur . Her ikisi de gerçekten olmayan garip kenar durumlarıdır iyi tasarım örnekleri.)

İşaretleme arayüzleri genellikle iki amaçtan biri için kullanılır:

1) Çok sayıda jenerik ile olabilen aşırı uzun bir tipten kaçınmak için bir kısayol olarak. Örneğin, bu yöntem imzasına sahip olduğunuzu varsayalım:

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

Yazmak dağınık ve sinir bozucu ve daha da önemlisi anlaşılması zor. Bunun yerine şunu düşünün:

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

Sonra yönteminiz şöyle görünür:

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

Sadece daha net değil, aynı zamanda artık Widget Widget arayüzünü de kullanabilirsiniz ve ayrıca Widget kodunuzdaki tüm oluşumları aramak daha kolaydır.

2) Marker arayüzleri, Java'nın kavşak tiplerinin olmaması konusunda da bir yol olarak kullanılabilir. Bir işaretçi arabirimiyle, bir yöntem imzası gibi iki farklı türde bir şeye ihtiyaç duyabilirsiniz. Yukarıda açıkladığımız gibi, uygulamanızda bazı arayüz Widget'ınız olduğunu varsayalım. Üzerinde yinelemenize izin veren bir Widget gerektiren bir yönteminiz varsa (yapışık, ancak burada benimle çalışın), tek iyi çözümünüz her iki arayüzü de genişleten bir işaretleyici arayüzü oluşturmaktır:

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

Ve kodunuzda:

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

1
Derleyici yok değil sınıf uygular varsa yöntemlerini oluşturmak Serializableveya Cloneable. Sınıf dosyalarınızı inceleyerek doğrulayabilirsiniz. Ayrıca, “kısayol arayüzleri” oluşturmak işaretleyici arayüzlerinin konusu değildir . Ek arayüzleri yerine getirmek için ek uygulama sınıfları oluşturmayı gerektireceği için bu gerçekten kötü bir kodlama uygulamasıdır . Bu arada, Java vardır artık on yıldır kesişme türleri. Generics hakkında bilgi edinin…
Holger

Klonlanabilir için haklısın. Object.clone () 'in yaptıklarını değiştirir. Hala korkunç. Bkz. Josh Bloch bağlantısı Kısayol arayüzleri, bir yönteme gönderebileceklerinizi keyfi olarak kısıtladığınız için mutlaka iyi bir tasarım deseni değildir. Aynı zamanda, biraz daha kısıtlayıcı bir kod varsa, daha net yazmanın genellikle makul bir tutarsızlık olduğunu hissediyorum. Kavşak tiplerine gelince, bu sadece jenerikler için geçerlidir ve sınırsızdır ve bu nedenle birçok durumda işe yaramaz. Hem Serileştirilebilir hem de başka bir şey olan bir örnek değişkenine sahip olmayı deneyin.
MikeyB

0

Bir arabirim herhangi bir yöntem içermiyorsa ve bu arabirimi uygulayarak nesnemiz biraz yetenek kazanırsa, bu tür arabirimlere marker arabirimleri denir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.