Arayüzlerde Korumalı


111

Neden tüm yöntemler interfaceörtük olarak bir tanım içindedir public? Neden bir protectedyönteme izin vermiyor ?


22
Çok güzel soru. Java'daki hemen hemen her şey için, yapılan seçimler için gerçek bir neden buldum, ancak bunun için bulamadım. Bir arabirimde, aynı paket içindeki başka bir sınıfın, bu yöntemi ifşa etmeye gerek kalmadan uygulama nesnesi üzerinde kullanmasına izin veren korumalı bir yöntemi tanımlamak benim için mükemmel bir anlam ifade ediyor; paket üyeleri, dünyanın geri kalanına.
Markus A.

4
@MarkusA. Ancak arayüzler iki yönlü çalışır, yani mevcut paketin dışındaki sınıflar tarafından da uygulanabilir (ve daha sonra bu paket içindeki yöntemlere argüman olarak iletilebilir). Mevcut paketin dışındaki bir sınıf, bazı genel arayüzlerin "korumalı" yöntemlerini nasıl uygulayabilir?
MartinStettner

8
@MartinStettner: Olmaz. Konu bu olacaktır. Bir paket, bir arabirimi uygulayan birden fazla ilgisiz sınıfa sahip olabilir ve bu arabirim türünün bir başvurusunu alan herhangi bir koda, belirli bir şekilde davranacağını garanti etmek isteyebilir. Böyle bir garanti, dış kodun sözleşmesine aykırı bir şekilde davranırken arayüzü uygulamayı iddia etmesi engellenebilirse çok daha güçlü hale getirilebilir.
supercat

1
@MarkusA. iyi bir noktaya değindiniz, bunu Java 9'un modül sistemiyle
Nir Alfasi

1
arayüzün protectedyöntemi varsa , tüm uygulama sınıfı arayüzün bir alt türü olarak görülecektir. ve tüm bu sınıflar korumalı yöntemlere erişebilir. o yapmak doesnt protectedyararsız yönteme keyword? Bu arayüzü kimin uygulayacağını kısıtlamak için herhangi bir yolumuz olmadığı sürece , yöntemde korumalı anahtar kelime işe yaramaz. Yanlışsam düzelt!
amarnath harish

Yanıtlar:


67

Çünkü arayüz, "sınıfın dışından görebileceğiniz şeyler" anlamına gelmelidir. Kamuya açık olmayan yöntemler eklemek mantıklı olmaz.


16
Ama neden sadece arayüzle aynı paketin üyelerinin "sınıfın dışından görebileceği" işlevler olmasın? Bunu dilediğim birkaç kullanım durumum oldu.
Markus A.

5
@MarkusA. Bunun geç olduğunun farkındayım, ancak sonra tam olarak abstract class, yani hepsi olan bir tane yapabilir interfaceve istediğiniz erişimi belirleyebilirsiniz. Bunun interface, Java'da bulunan birden fazla uygulamanın avantajını kaybettiği kabul edilir , ancak dürüst olmak gerekirse, başka bir paketin sınırlamalarına uyan bir sözleşme oluşturmak test edilemez ve kafa karıştırıcı olacaktır, çünkü bu paketin dışındaki kendi uygulamanızın yöntemine pratik olarak erişemeyeceksiniz. .
2013

10
@pickypg Ancak arayüzü uygulayacak sınıf zaten başka bir sınıfı genişletiyorsa, başka bir sınıfı genişletemezsiniz. Sadece bir paket içinde kullanılan bir arayüz için kafa karıştırıcı bulmazdım.
Flamma

24
@Raveline, -1, Bu, "neden bir arayüzün sınıfın dışından görebileceğiniz anlamına gelmesi gerekiyor?" Sorusunu akla getiriyor. Java 8 zaten arayüzlerde yöntem gövdesine izin veriyor, öyleyse neden korumalı soyut yöntemlere de izin vermiyorsunuz?
Pacerier

8
Bu açıklamayı sık sık okurum ama yanlış IMHO. Arabirim, ister OOP, iletişim API'si veya donanım hakkında konuşsun, bir tür "standart değişim protokolü" dür. Bilgisayarımdaki USB bağlantı noktası açıkça genel bir arabirimdir. Ancak, isteğe bağlı USB bağlantı noktalarına erişim sağlayan, ana kartımdaki, yani anahtar kilitli bir kasanın arkasındaki pinler açıkça "korumalı" bir arabirimdir. O zaman, aynı zamanda standartlaştırılmış bir arayüz olan BIOS yongasına sahibiz, ancak hiçbir şekilde halka açıklanmadı, yalnızca birkaç şirket özel olarak tam ayrıntıları biliyor. Yani, elbette, arayüzler herhangi bir görünürlük sağlayabilir! Neden OOP'de değil?
Foo Bar

55

Sıklıkla dile getirilen neden "arayüzlerin genel API'leri tanımlaması" olmasına rağmen, bence bu aşırı bir basitleştirme. (Ve dairesel mantığın da "kokusu" var.)

Erişim değiştiricilerinin bir karışımına sahip arayüzlere sahip olmak anlamsız olmayacaktır; örneğin, kısmen genel ve kısmen arayüzle aynı paketteki diğer sınıflarla sınırlıdır. Aslında, bazı durumlarda bu çok yararlı olabilir, IMO.

Aslında, bir arayüzün üyelerini örtük olarak herkese açık hale getirmenin arkasındaki mantığın parçası , Java dilini daha basit hale getirmesi olduğunu düşünüyorum :

  • Örtük olarak genel arayüz üyeleri, programcıların uğraşması için daha kolaydır. Yöntem erişim değiştiricilerinin görünüşte rastgele seçildiği kodu (sınıfları) kaç kez gördünüz? Pek çok "sıradan" programcı, Java soyutlama sınırlarının en iyi nasıl yönetileceğini anlamakta güçlük çekiyor 1 . Arayüzlere genel / korumalı / özel paket eklemek, işleri onlar için daha da zorlaştırır.

  • Örtük olarak genel arabirim üyeleri, dil belirtimini basitleştirir ... ve dolayısıyla Java derleyici yazarları ve Yansıma API'lerini uygulayanlar için görevi basitleştirir.

"Arayüzlerin genel API'leri tanımladığı" düşüncesi, muhtemelen basitleştirici dil tasarım kararının bir sonucudur (veya karakteristiğidir) ... tam tersi değil. Fakat gerçekte, Java tasarımcılarının zihinlerinde muhtemelen iki düşünce çizgisi paralel olarak gelişti.

Her halükarda, JDK-8179193'teki RFE'ye verilen resmi yanıt , Java tasarım ekibinin , arabirimlere izin vermenin çok az gerçek fayda sağlayacak şekilde karmaşıklık eklediğine 2 karar verdiğini açıkça ortaya koymaktadır protected. Kudos için @skomisa için kanıt bulma .

RFE'deki kanıt sorunu çözüyor. Bunun eklenmemesinin resmi nedeni budur.


1 - Tabii ki, en iyi programcılar bu konularda zorluk çekmezler ve daha zengin bir erişim kontrol özellikleri paletini memnuniyetle karşılayabilir. Ancak, kodları bakımı için başka birine verildiğinde ne olur?

2 - Kararlarına veya beyan ettikleri gerekçeye katılmayabilirsiniz, ancak bu tartışmalıdır.


21

Java 8'de varsayılan yöntemlerin tanıtılmasıyla bu sorunun yeniden açıldığını söylemeliyim. Şu anda üzerinde çalıştığım proje, bir arayüzün temel doğasına benzer şekilde, niyetin uygulamadan soyutlanmasıdır.

Kodumu "varsayılan korumalı" bir yöntemle büyük ölçüde basitleştirebileceğim birkaç durum vardır. Arayüzler hala Java 7 mantığına bağlı kaldığından, bunun gerçekten çalışmadığı ortaya çıktı. Normal korumalı bir yöntem, yukarıda belirtilen nedenlerden ötürü özellikle mantıklı değildir; ancak varsayılan bir genel yöntem, muhtemelen değişmeyecek ve korumalı bir yöntemle sağlanabilecek düşük seviyeli bir kaynak gerektiriyorsa, bana öyle geliyor ki, "varsayılan korumalı" çalışmaya sahip olmak yalnızca daha temiz kod sağlamakla kalmaz, aynı zamanda gelecekteki kullanıcıları kazara suistimaller.

(Bu trajik bir şekilde, kodumu başka türlü gereksiz özetlerle aşırı karmaşık hale getirmem gerektiği gerçeğini değiştirmez; ancak Oracle'a bir özellik isteği eklemeyi düşünüyorum.)


% 100 katılıyorum. Soyut sınıflar, varsayılan yöntemlerin tanıtılmasından önce mantıklı bir alternatifti. Bununla birlikte, çoklu mirasa koydukları sınırlamalar, mükemmel olmadıkları anlamına gelir. Varsayılan yöntemlerle arayüzler normalde> = JDK 1.8 dünyasında daha iyi bir alternatiftir, ancak durumu depolayamadıkları için durumu ortaya çıkarmak için diğer soyut yöntemleri tanımlamaya güvenirler, bu da devletin kamuya açık olduğu anlamına gelir, bu her zaman böyle değildir. İstediğiniz.
Fr Jeremy Krieg

10

Çünkü arayüzler genel API'leri tanımlar. Korunan her şey, bir arayüze ait olmayan dahili bir ayrıntıdır.

Soyut sınıfları korumalı soyut yöntemlerle kullanabilirsiniz, ancak arabirimler genel yöntemler ve genel statik son alanlarla sınırlıdır.


5
"Arayüzler genel API'leri tanımladığı için" dediniz. Öyleyse, arayüzlerin yalnızca publicAPI'leri tanımlamasının nedeni nedir? "İç ayrıntı" ile "uygulama ayrıntısı" arasında bir fark vardır, protectedJava'da kesinlikle bir iç ayrıntı değildir, çünkü artık alt sınıflandırma yapabilen herkese , yani temelde tüm dünyaya yayınlanan bir genel arabirimdir .
Pacerier

1
Java 8'in varsayılan yöntemleriyle artık doğru değil.
Mario Rossi

@MarioRossi Ayrıca Java 9'un özel arayüz yöntemleriyle de artık doğru değil.
skomisa

7

Belki de bir arayüz olduğu için , yani müşterilere ne yapamayacaklarını söylemek yerine örneklerle neler yapabileceklerini söylemek için var.


1
Bir arayüzün neden alt sınıflara bu uygulamayı dış dünyaya göstermeden neler yapabileceklerini söyleyemediğini anlamıyorum. Bu, soyut sınıfların mükemmel bir alternatif olarak kullanılabileceği bir zamanda verilen bir tasarım kararıydı. Ancak arayüzlerde varsayılan yöntemlerin ortaya çıkmasıyla, soyut sınıflar artık mükemmel olmayan bir alternatiftir.
Fr Jeremy Krieg

6

Ben kuvvetle arayüzleri korumalı yöntemleri izin vermelidir hissediyorum; arayüzlerin tüm dünyadaki herkes tarafından görülebilir olması gerektiğini kim söyledi? "Sıradan" (okuma: beceriksiz) programcıların kafasını karıştırabileceğine gelince: OOP'nin çoğu, nesneleri, sınıfları, paketleri vb. çok daha büyük bir problem. Java edildi inşa şeyin türü için.


Bu soruya cevap vermiyor.
Stephen C

5

Buradaki birkaç cevap, arayüz yöntemlerinin neden korunamayacağını açıklamak için döngüsel akıl yürütme kullanır: bunun nedeni, halka açık olmaları gerektiğidir, bu yüzden açıkça korunamazlar!

Bu hiçbir şeyi açıklamıyor, ancak neyse ki bir kişi , birkaç yıl önce bir JDK hatası olarak arabirimlerde korunan yöntemler için bir geliştirme talebinde bulundu ve bu konuya biraz ışık tutuyor:

Arayüzlerde korumalı yöntemler: paketler arasında paylaşın

Java'da değiştiriciler biraz sınırlı olduğundan, yöntemleri paketler arasında paylaşmanın bir yolu genel yöntemlerle sınırlıdır. Bazen bir yöntemi halka açık hale getirmek tehlikelidir, ancak uygun değiştiricilerin eksikliğinden kaynaklanması gerekir. Benim çözümüm bu sınırlamanın üstesinden geliyor.

Java dili belirtimi şu anda arabirim yöntemleri için korumalı değiştiriciye izin vermiyor. Bu olgudan faydalanabilir ve bu yeni özellik için arayüz için korumalı yöntemleri kullanabiliriz.

Bir arabirim yöntemi korumalı olarak işaretlenirse ve arabirim başka bir paketteki bir sınıf tarafından uygulanırsa, yöntemin genel olması gerekmez, ancak özel veya en azından paket korumalı da olabilir. Yöntem görünürdür, sınıf ne olursa olsun ve ek olarak arabirimin kaynak paketinde (ve alt paketlerde?) Görünür.

Bu şekilde, iyi bilinen paketler arasında belirli yöntemleri paylaşabilirdik.

Durumla kapatılan bu geliştirme isteğine verilen yanıt şudur Won't fix:

Bu öneri, bir sorunu, çok az gerçek kazanç için karmaşıklık ve özel durumlar ekleyerek çözmeye çalışır. Bu sorunu çözmenin tipik bir yolu, genel bir arabirim uygulayan özel bir sınıfa sahip olmaktır. Uygulama yöntemleri geneldir, ancak özel bir sınıf içindedir, bu nedenle özel kalırlar.

Java 9'dan başlayarak kullanılabilen bir alternatif, sınıfları ve yöntemleri herkese açık hale getirmektir, ancak genel olarak dışa aktarılmak yerine belirli "arkadaş" modüllerine nitelikli dışa aktarımı olan bir modül içinde.

Dolayısıyla, bu hata raporundan elde edilen güvenilir çıkarımlar şunlardır:

  • Mevcut durum değişmeyecek; arayüzlerin protectedyöntemleri destekleme olasılığı düşüktür .
  • protectedArayüzlerde yöntemleri desteklememesinin gerekçesi, " az gerçek kazanç için karmaşıklık ve özel durumlar eklemesidir ".
  • Java 9'dan beri, yöntemlere paket düzeyinde erişim sağlamak için alternatif bir yaklaşım vardır. Kullanım Java Platform Modülü Sistemi (JPMS) için " 'yerine halka ihraç edilme modüllerin arkadaşı yapmak sınıflar ve kamu yöntemlerle, ancak belirli bir nitelikli ihracatı olan bir modül içinde' ".

4

Uygulama sınıfı, arayüzünüzde bildirilen TÜM yöntemleri uygulamak zorunda olduğundan, uygulama sınıfınız farklı bir pakette olsaydı ne olurdu?


2

Arayüz Açıkladığınız gibi bir şey kullanmak istiyorsanız, soyut sınıflarla veya iç içe arayüzlerle devam edin.

Arayüz değişkenleri hakkında Kod Stilinden bir alıntı , ancak yine de yöntemler için geçerlidir:

Arayüz değişkenleri dolaylı olarak halka açıktır çünkü arayüzler, Java programcıları tarafından kendi uygulamalarında referans ve uygulama için tamamen erişilebilir olan bir Uygulama Programlama Arayüzü (API) sağlamayı amaçlamaktadır. Java paketlerinde kendi arayüzlerinden farklı bir arayüz kullanılabileceğinden, genel görünürlük program kodunun değişkene erişebilmesini sağlar.

2

Dahili alt protectedarayüzleri bildirmek iyi bir uygulamadır, ancak teknik olarak Java'daki bir arayüzde olduğu gibi dahili yöntemlerinizi açıklayamazsınız .

Tabii ki, dahili kullanım için ortak arayüzü genişleten başka bir arayüz oluşturabilirsiniz:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

InternalInterfaceArabirimi paketin içinde kullanabilirsiniz , ancak aşağıdakilerin herhangi bir alt türünü kabul etmelisiniz PublicInterface(genel yöntemlerde):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Paket dışı kullanıcılar sorunsuz kullanabilirler PublicInterface.

Genellikle programcılar benzer durumlarda soyut sınıflar oluşturur. Ancak bu durumda çoklu mirasın faydalarını kaybediyoruz.


1
Paketin dışında kullanıcılar da kullanabilir YourPublicInterface.Internal. İç içe geçmiş arabirimler dahil bir arabirimdeki her şey, publicanahtar sözcüğün varlığına veya yokluğuna bakılmaksızın herkese açıktır .
Greg Roelofs

1

Bunun mantıklı olacağı tek senaryo, görünürlüğü aynı paketle sınırlandırmak istediğiniz zamandır. Ürününün diğer tüm kullanımları protectedgeçerli değildir. Özellikle, protectedyöntemler genellikle nesiller için daha düşük seviyeli uygulamaların bazı ayrıntılarına erişim sağlamak için kullanılır. Ancak, ortaya çıkarılacak daha düşük seviyeli bir uygulama olmadığından, bunu bir arayüzde beyan etmek bir anlam ifade etmiyor.

Ve hatta paket senaryosu bile arayüzlerin gerçekte ne olduğu değildir.

Muhtemelen istediğinizi elde etmek için, biri dahili kullanım için, diğeri genel API'de ifşa ettiğiniz iki arayüze ihtiyacınız var. (Muhtemelen dahili olanla, ancak kamusal olanı genişletmesi gerekmiyor.) Veya, diğerlerinin de belirttiği gibi, soyut bir üst sınıf.


Soyut bir üst sınıf, kendi paketinin dışındaki türler tarafından türetilmesini engelleyebilir. Paketin yazarına güvenen böyle bir üst sınıf türünün referansını alan biri, nesnenin iddia edildiği gibi davranacağından emin olabilir. Bir pakette, bazı ortak işlevleri açığa çıkarmak isteyen, ancak uygun bir hiyerarşiye uymayan birden çok sınıf varsa (örneğin, bir uygulama işlevleri X ve Y, bir Y ve Z ve bir X ve Z) açığa çıkarsa yararlı olacaktır. arayüzleri kullanan işlevsellik, yine de arayüz türleri tarafından atıfta bulunulan örneklerin "gerçek" olacağını vaat ediyor.
supercat

0

Korumalı yöntemlere her zaman alt sınıf tarafından erişilebilir, ancak alt sınıf temel sınıfı genişletirse.

Arayüz durumunda, alt sınıf asla arayüzü genişletmez. Arayüzü uygular.

Korumalı yöntemlere uygulama ile değil, genişletme yoluyla erişilebilir .


hangi anahtar kelime ne fark eder, önemli değil.
Alex78191

0

Arayüzler, yöntemleri dış dünyaya göstermek içindir . Dolayısıyla bu yöntemler doğası gereği halka açıktır. Bununla birlikte, aynı sınıf ailesi içinde soyutlamayı tanıtmak istiyorsanız , arayüzünüz ile uygulama sınıfı arasında başka bir soyutlama seviyesi, yani soyut bir sınıf oluşturmakla mümkündür. Aşağıda bir örnek gösterilmiştir.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}

2
Ancak arayüzlerde kimsenin görmeyeceği özel yöntemlere izin verilir.
Alex78191

Java, arabirimlerde varsayılan yöntemlere sahiptir, yani bir arabirim, soyut sınıfların çoklu kalıtımını atlamak için bir koltuk değnektir. O halde soyut sınıfların çoklu kalıtımına izin verilir. Varsayılan yöntemlerin çatışması bir sorun haline gelmedi.
Alex78191

Haklısın. Java 9'dan itibaren arabirimlerde özel yöntemlere izin verilmektedir. Bunlar soyut olamaz ve arayüz içinde, esas olarak diğer varsayılan veya statik yöntemlerle (kendileri statik ise) uygulanır ve kullanılır.
Stefanos Kargas

1
Bu cevap, sorulan soruyu basitçe görmezden geliyor: neden arayüzler korumalı yöntemlere sahip olamıyor? Korumalı yöntemler hala "yöntemleri dış dünyaya maruz bırakır" ve "bu yöntemlerin doğası gereği kamusaldır" iddiası tamamen yanlıştır. Halka açıklar çünkü dil bu şekilde tasarlandı, ancak arayüzlerde korumalı yöntemlere izin vermiş olabilir. OP basitçe nedenini soruyor.
skomisa
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.