Bir arabirim uygulayan soyut bir sınıf neden arabirimin yöntemlerinden birinin bildirimini / uygulamasını kaçırabilir?


123

Bir arabirimi uygulamak için soyut bir sınıf kullandığınızda Java'da ilginç bir şey olur: arabirimin yöntemlerinden bazıları tamamen eksik olabilir (yani ne soyut bir bildirim ne de gerçek bir uygulama mevcut değildir), ancak derleyici şikayet etmez.

Örneğin, arayüz verildiğinde:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

aşağıdaki soyut sınıf neşeyle bir uyarı veya hata olmadan derlenir:

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

Nedenini açıklayabilir misin?


2
Soyut bir sınıfın nesnesi yaratılamaz. Bu nedenle, soyut bir sınıf için bir uygulama sağlanmadığı sürece, nesneler IAnything için yaratılamaz. Yani bu derleyici için kesinlikle iyidir. Derleyici, IAnything'i uygulayan soyut olmayan herhangi bir sınıfın, IAnything'den bildirilen tüm yöntemleri uygulaması gerektiğini bekler. Ve nesneler yaratabilmek için AbstractThing'in genişletilmesi ve uygulanması gerektiğinden, eğer bu uygulama AbstractThing tarafından bırakılan IAnything yöntemlerini uygulamazsa, derleyici bir hata verecektir.
VanagaS

Kendi "AbstractThing" i buna benzer bir senaryoda genişleten somut bir sınıfım vardı ve arayüzdeki yöntemlerden birini uygulamamış olsam da açıklanamaz bir şekilde derleniyordu. Şimdi beklediğim şeyi yapıyor, ancak daha önce neyin başarılı olmasına neden olduğunu anlayamıyorum. :wDosyalardan birini yapmadığımı sanıyorum .
Braden Best

benzer bir sorunun cevabını görebilirsiniz stackoverflow.com/questions/8026580/…
Do Nhu Vy

Yanıtlar:


156

Bunun nedeni, eğer bir sınıf soyutsa, o zaman tanım gereği onun alt sınıflarını yaratmanız gerekir. Soyut sınıfın dışarıda bıraktığı herhangi bir arabirim yöntemini uygulamak için alt sınıflar (derleyici tarafından) gerekecektir.

Örnek kodunuzun ardından AbstractThing, m2yöntemi uygulamadan alt sınıfını oluşturmayı deneyin ve derleyicinin size hangi hataları verdiğini görün. Sizi bu yöntemi uygulamaya zorlayacaktır.


1
Derleyicinin arayüzleri eksik uygulayan soyut sınıflarla ilgili uyarılar atması gerektiğini düşünüyorum, çünkü o zaman bir alt sınıfta neye ihtiyacınız olduğunu görmek için 1 yerine 2 sınıf tanımına bakmanız gerekiyor. Yine de bu bir dil / derleyici sınırlamasıdır.
workmad3

3
Tipik olarak çok sayıda soyut sınıf olabileceğinden ve 'yanlış' uyarılar kısa süre sonra sizi ezip 'gerçek' uyarıları kaçırmanıza neden olacağı için bu iyi bir fikir olmaz. Düşünürseniz, 'soyut' anahtar sözcüğü, derleyiciye o sınıf için uyarıları bastırmasını söylemek için özellikle oradadır.
belugabob

4
@workmad - bir arayüz metotları alt kümesi için ortak uygulamalarınız varsa, onu ayrı bir temel sınıfa ayırmak daha mantıklıdır (DRY, tek
basamaklı

4
Soyut bir sınıfa boş yöntem uygulamaları koymanızı istemek tehlikeli olabilir . Bunu yaparsanız, alt sınıfların uygulayıcıları, derleyici onlara bir sorun olduğunu söylemeden bu davranışı devralır.
Bill the Lizard

8
Sanırım workmad'in önerdiği şey, soyut sınıfta yöntemleri bir yöntem gövdesi olmadan tanımlamanız ve onları soyut olarak işaretlemenizdir. Bana kötü bir fikir gibi gelmedi.
Dónal

33

Mükemmel derecede iyi.
Soyut sınıfları başlatamazsınız .. ancak soyut sınıflar m1 () ve m3 () için ortak uygulamaları barındırmak için kullanılabilir.
Yani eğer m2 () uygulaması her uygulama için farklıdır ama m1 ve m3 değildir. Sadece farklı m2 uygulamasıyla farklı somut IAnything uygulamaları oluşturabilir ve DRY ilkesini onurlandıran AbstractThing'den türetebilirsiniz. Arayüzün tamamen soyut bir sınıf için uygulanıp uygulanmadığını doğrulamak beyhudedir ..

Güncelleme : İlginç bir şekilde, C # 'ın bunu bir derleme hatası olarak zorladığını görüyorum. Bu senaryoda, yöntem imzalarını kopyalamak ve soyut temel sınıfta bunların önüne 'abstract public' eklemek zorundasınız .. (her gün yeni bir şey :)


7

Bu iyi. Yukarıdakileri anlamak için önce soyut sınıfların doğasını anlamalısınız. Bu bakımdan arayüzlere benzerler. Oracle'ın burada söylediği şey bu .

Soyut sınıflar arayüzlere benzer. Bunları örnekleyemezsiniz ve bunlar, bir uygulama ile veya olmadan bildirilen bir yöntem karışımını içerebilir.

Bu nedenle, bir arayüz başka bir arayüzü genişlettiğinde ne olacağını düşünmelisiniz. Örneğin ...

//Filename: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

... gördüğünüz gibi, bu da mükemmel bir şekilde derleniyor. Bunun nedeni, tıpkı soyut bir sınıf gibi, bir arayüzün somutlaştırılamamasıdır. Bu nedenle, yöntemlerden açıkça "ebeveyninden" bahsetmek gerekli değildir. Ancak, TÜM ana yöntem imzaları örtük olarak genişletme arabiriminin veya soyut sınıfın uygulanmasının bir parçası haline gelir. Dolayısıyla, uygun bir sınıf (somutlaştırılabilen) yukarıdakileri genişlettiğinde, her bir soyut yöntemin uygulanmasını sağlamak GEREKECEKTİR.

Umarım bu yardımcı olur ... ve Allahu 'alam!


Bu ilginç bir bakış açısı. Bu bana "soyut sınıfların" gerçekten "somut arayüzler" olduğunu düşündürüyor, yani bazı soyut metotlara sahip sınıflardan ziyade bazı somut metotlarla arayüzler.
Giulio Piancastelli

... ikisinden de biraz. Ama kesin olan bir şey var ki, somutlaştırılamazlar.
Minnettar

4

Arabirim, yönteminin uygulanmasına sahip olmayan, ancak yalnızca bildirimi olan bir sınıf anlamına gelir.
Öte yandan, soyut sınıf, bazı yöntemlerin uygulanmasının yanı sıra yalnızca bildirimle bazı yöntemlerin uygulanmasına sahip olabilen, uygulama yapılmayan bir sınıftır.
Soyut bir sınıfa bir arabirim uyguladığımızda, bu soyut sınıfın arabirimin tüm yöntemlerini miras aldığı anlamına gelir. Soyut sınıfta tüm yöntemi uygulamak önemli olmadığından, soyut sınıfa (kalıtım yoluyla da) geldiği için soyut sınıf, burada uygulama yapmadan bazı yöntemi arayüzde bırakabilir. Ancak, bu soyut sınıf bir somut sınıf tarafından miras alınacağı zaman, soyut sınıfta tüm bu uygulanmamış yöntemi orada uygulamak zorundadır.


4

Arayüz göz önüne alındığında:

public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}

Java aslında bunu şu şekilde görüyor:

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}

Böylece abstract, abstractsınıfların başka bir abstractsınıfı genişletmesi durumunda yapacağınız gibi, bu yöntemlerin bazılarını (veya tümünü) uygulanmadan bırakabilirsiniz .

Ne zaman implementbir interfacebütün o kural interfaceyöntemleri türetilmiş uygulanması gereken classtek somut uygulanır class(değil yani, uygulama abstractkendisi).

Eğer gerçekten bir oluşturmayı planlıyorsanız abstract classbunun out, o zaman ettik söyleyen bir kural yoktur implementhepsi interface(böyle bir durumda o türetilmiş açıklamak zorunlu olduğuna dikkat yöntemlerinin classolarak abstract)


javap IAnything.classİkinci kod parçacığını oluşturmak için kullanma .
sharhp

3

Soyut Bir Sınıf Bir Arayüz Uyguladığında

Arabirimler bölümünde, bir arabirim uygulayan bir sınıfın arabirimin tüm yöntemlerini uygulaması gerektiği belirtildi. Bununla birlikte, sınıfın soyut olarak bildirilmesi koşuluyla, arabirimin tüm yöntemlerini uygulamayan bir sınıf tanımlamak mümkündür. Örneğin,

abstract class X implements Y {   
    // implements all but one method of Y
}

class XX extends X {   
    // implements the remaining method in Y 
} 

Bu durumda, X sınıfı soyut olmalıdır çünkü Y'yi tam olarak uygulamaz, ancak XX sınıfı aslında Y'yi uygular.

Referans: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


1

Yöntemleri uygulamak için soyut sınıflar gerekli değildir. Dolayısıyla, bir arayüz uygulamasına rağmen, arayüzün soyut yöntemleri soyut kalabilir. Somut bir sınıfta bir arabirim uygulamaya çalışırsanız (yani soyut değil) ve soyut yöntemleri uygulamazsanız, derleyici size şunu söyleyecektir: Ya soyut yöntemleri uygulayın ya da sınıfı soyut olarak bildirin.

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.