Bir Interface ve Abstract sınıfı arasındaki farkı nasıl açıklamalıydım?


469

Röportajlarımdan birinde, bir Arayüz ve Soyut sınıf arasındaki farkı açıklamam istendi .

İşte cevabım:

Bir Java arayüzünün yöntemleri dolaylı olarak soyuttur ve uygulamaları olamaz. Java soyut sınıfında, varsayılan davranışı uygulayan örnek yöntemler bulunabilir.

Java arayüzünde bildirilen değişkenler varsayılan olarak son şeklindedir. Soyut bir sınıf, son olmayan değişkenler içerebilir.

Java arabiriminin üyeleri varsayılan olarak herkese açıktır. Bir Java soyut sınıfı, özel, korumalı vb.Gibi sınıf üyelerinin olağan lezzetlerine sahip olabilir.

Bir Java arayüzü “implements” anahtar sözcüğü kullanılarak uygulanmalıdır; Bir Java soyut sınıfı, "extends" anahtar kelimesi kullanılarak genişletilmelidir.

Bir arabirim yalnızca başka bir Java arabirimini genişletebilir, soyut bir sınıf başka bir Java sınıfını genişletebilir ve birden çok Java arabirimi uygulayabilir.

Bir Java sınıfı birden çok arabirim uygulayabilir, ancak yalnızca bir soyut sınıfı genişletebilir.

Ancak görüşmeci memnun değildi ve bana bu açıklamanın " kitap bilgisi " ni temsil ettiğini söyledi .

Benden daha pratik bir yanıt istedi , pratik örnekleri kullanarak bir arayüz üzerinden soyut bir sınıfı ne zaman seçeceğimi açıkladı .

Nerede hata yaptım?


32
Belki cevabınız anlamadığınız bir şeyi söylüyorsunuz? Bu sadece anlatım stilini daha çok kendi kelimelerinize benzeyen şekilde değiştirmeniz gerekebilir.
Kirill Kobelev

19
(Oldukça doğru) teknik farklılıkların bir listesi ile cevap verdiniz. Muhabir büyük olasılıkla daha kavramsal bir cevap arıyordu (örneğin, bir arayüz ile soyut bir sınıf arasında hangi temeli seçecekti).
Ted Hopp

15
Soyut bir sınıfın inşasını başlatamasanız bile soyut sınıfların kurucuları olduğunu söylemeyi unuttunuz. çocuk sınıfları tarafından kullanılır. Arayüzler bir "ab" iken bir sözleşme (yöntemler listesi) tanımladıkları için "nasıl" değil "nasıl" olduğunu belirtir. sınıf aynı zamanda "nasıl" olduğunu da belirtebilir. İnt kullanma. birden çok kalıtım taklit edebilirsiniz (bir sınıf birden fazla int uygulayabilir, ancak yalnızca bir sınıfı genişletebilir). İnt kullanma. dif için bir taban türüne sahip olabilirsiniz. aileler: El ilanı f = yeni Düzlem (); El ilanı f2 = yeni Kuş (); Kuş ve Uçak aynı aileye karşılık gelmez, ancak her ikisi de uçabilir (el ilanlarıdır).
Francisco Goldenstein

7
Java8 arayüzlerinden itibaren yöntemler içerebilir .. OO kavramının ötesinde bu "farklılıklar" her gün değişebilir.
halka taşıyıcı

15
Cevabınızla ilgili herhangi bir sorunum yok ve görüşmecinin 'kitap bilgisi'nde küçümseyecek bir işi olmadığını düşünüyorum. Görüşmeciler her zaman sordukları soruların doğru cevaplarını bilmezler ve bazı görüşmeler yalnızca sizi orada çalışmamanız konusunda uyarır.
Lorne Marquis

Yanıtlar:


513

Önce size bir örnek vereceğim:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

Uygulamanızda 3 veritabanı olduğunu varsayalım. Daha sonra, bu veritabanı için her uygulamanın yukarıdaki 2 yöntemi tanımlaması gerekir:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

Ama ya encryptPassword()veritabanına bağımlı değilse ve her sınıf için aynı ise? O zaman yukarıdakiler iyi bir yaklaşım olmazdı.

Bunun yerine, bu yaklaşımı düşünün:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

Şimdi her alt sınıfta, yalnızca bir yöntem uygulamamız gerekiyor - veritabanına bağımlı yöntem.


97
Bunun gerçekten farkı açıkladığından emin değilim ... güzel bir teknik olduğundan eminim. Ayrıca Java 8'in sonunda C ++ 'ın doğru olduğunu ve çoklu kalıtımın yapılabileceğini ve bir kullanıma sahip olabileceğini ve ayrıca arayüzlerin sadece işlev imzalarını tanımlamakla kalmayıp varsayılan uygulamaları da sağlayabildiğini de belirtmek gerekir. Bu nedenle, bir arayüz kullanmak tercih edilir.
thecoshman

1
@thecoshman Soruna yanıttaki gibi yaklaştığımda (bir yöntem uygulanmış ve diğer soyut ile soyut sınıf) veya varsayılan yöntem uygulamalı bir arabirim tanımlasam ne fark ederdi? Temel olarak, söylemeye çalıştığım şey, 'bir arabirim kullanmak tercih edilir' yazdığınızı ve sorum şu - neden?
Neutrino

1
Yani, sanırım o zaman arayüzlerde, tanımlanmış olanın uygulanmasının aslında arayüzü uygulayan sınıfa bağlı olduğunu, soyut bir sınıftaki şeylerin ise sınıfı genişleten sınıfların "çekirdeği" olduğunu söylemek doğru olur; yani değişmez.
orrymr

4
@Neutrino Her biri işlevler için varsayılan uygulamalar sunan birden çok arabirim uygulamanıza izin veren Java'ya rağmen, yine de yalnızca tek bir sınıfı genişletebilirsiniz. Bu nedenle, bir arayüz kullanmak, diğer arayüzlerle birlikte kullanmak isteyenler için daha fazla esneklik sağlayabilir.
thecoshman

3
@HiradNikoo Geç yorum için özür dilerim, ama ben sadece bu konu üzerinde tökezledi. Ayrıca, sınıf mirasını IS-A ilişkisi olarak kabul edebilirsiniz, oysa arabirimler "belirli bir işlevselliğe sahiptir" anlamına gelir.
Alexander Jank

206

Bu dünyada hiçbir şey mükemmel değildir. Daha pratik bir yaklaşım beklemiş olabilirler.

Ancak açıklamanızdan sonra bu satırları biraz farklı bir yaklaşımla ekleyebilirsiniz.

  1. Arayüzler, yazılım geliştirmedeki çeşitli ekipler arasında ortak bir anlayış belgesi olarak çalışan kurallardır (kurallar, görmezden gelemeyeceğiniz veya kurallar gibi dayatılamayacağınız bir uygulama vermelisiniz).

  2. Arabirimler ne yapılacağı fikrini verir ama nasıl yapılacağını değil. Dolayısıyla uygulama, verilen kuralları (yöntemlerin imzası verilen araçlar) izleyerek geliştiriciye tamamen bağlıdır.

  3. Soyut sınıflar soyut bildirimler, somut uygulamalar veya her ikisini içerebilir.

  4. Soyut bildirimler uyulması gereken kurallar gibidir ve somut uygulamalar yönergeler gibidir (olduğu gibi kullanabilir veya kendi uygulamanızı geçersiz kılarak ve uygulayarak yok sayabilirsiniz).

  5. Ayrıca, aynı imzalı hangi yöntemlerin farklı bağlamdaki davranışı değiştirebileceği, farklı bağlamlarda buna göre uygulanacak kurallar olarak arayüz bildirimleri olarak sunulmaktadır.

Düzenleme: Java 8, arabirimdeki varsayılan ve statik yöntemleri tanımlamayı kolaylaştırır.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

Artık bir sınıf SomeInterface uygulayacaksa, varsayılan arabirim yöntemleri için uygulama sağlamak zorunlu değildir.

Aşağıdaki yöntemlerle başka bir arayüzümüz varsa:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java, derleyicinin hangi üst sınıf yönteminin kullanılacağına karar veremediği “Elmas Sorunu” ile sonuçlandığı için birden çok sınıfın genişletilmesine izin vermez . Varsayılan yöntemlerle, elmas problemi arabirimler için de ortaya çıkacaktır. Çünkü eğer bir sınıf her ikisini de

SomeInterfaceOne and SomeInterfaceTwo

ve ortak varsayılan yöntemi uygulamazsa, derleyici hangisini seçeceğine karar veremez. Bu sorunu önlemek için, java 8'de farklı arayüzlerin ortak varsayılan yöntemlerini uygulamak zorunludur. Herhangi bir sınıf yukarıdaki arabirimlerin her ikisini de uyguluyorsa, defaultMethod () yöntemi için uygulama sağlamalıdır, aksi takdirde derleyici derleme zamanı hatası verir.


11
+1, bu karışıklığı önlemek için gerçekten iyi bir cevap. Ama hiçbir bağlantı görmedim ve neden bu değerli satırları alıntıladığınızı bilmiyorum. Mümkünse puan verin :).
Suresh Atta

Arabirimleri kullanarak ve farklı ailelerin sınıfları için bir taban türüne sahip olmak üzere arabirimleri kullanarak çoklu kalıtım öykünmesi hakkındaki yorumumu okuyun. Görüşmecinin görüşülen kişiden bu tür cevapları duymak istediğini düşünüyorum.
Francisco Goldenstein

Yorumunuz ayrıca iyi bir arayüz kullanımına işaret ediyor. Her gün çalışırken neler hissettiğimi yazdım. Bu kelimeler profesyonel veya doğru olmayabilir. Ama günlük kodlamamda soyut sınıflar ve arayüzlerle yakından çalıştıktan sonra öğrendim.
Shailesh Saxena

4. Somut uygulamalar da varsayılan uygulamaya sahip kurallardır.
Luten

@Luten: Bildiğim kadarıyla, bir kuralı herhangi bir sorun yaşamadan engelleyebilir / görmezden gelebilirseniz, bu kural değil, bir kılavuz olmalıdır. Yanlışım varsa lütfen düzelt.
Shailesh Saxena

168

Kullanım ve uygulamadaki pratik farklılıkların iyi bir özetini yaptınız, ancak anlamdaki fark hakkında hiçbir şey söylemediniz.

Bir arabirim bir uygulama sınıfı olacak bir davranış açıklamasıdır. Uygulayıcı sınıf, üzerinde kullanılabilecek bu yöntemlere sahip olmasını sağlar. Temelde sınıfın yapmak zorunda olduğu bir sözleşme ya da sözdür.

Bir soyut sınıf defalarca oluşturulacak gerekmez payı davranışı farklı alt sınıfları için bir temel oluşturur. Alt sınıflar davranışı tamamlamalı ve önceden tanımlanmış davranışı geçersiz kılma seçeneğine sahip olmalıdır ( finalveya olarak tanımlanmadığı sürece private).

java.utilArayüzde halihazırda uygulayan Listbenzeri arayüzler ve soyut sınıflar içeren pakette iyi örnekler bulacaksınız AbstractList. Resmi belgeler açıklanır AbstractListaşağıdaki gibidir:

Bu sınıf, "rasgele erişim" veri deposu (dizi gibi) tarafından desteklenen bu arabirimi uygulamak için gereken çabayı en aza indirmek amacıyla Liste arabiriminin iskeletsel bir uygulamasını sağlar.


16
Cevap bu olmalı. Bir ayrıntı listesi değil, sadece Java'da değil, genel olarak bir arayüz ile soyut bir sınıf arasındaki farkı yaratan temel kavram.
edc65

1
Bu gerçekten iyi. Tabii ki diğer cevaplar da iyi. Ancak bu size abstractanahtar kelime hakkında önemli bir bilgi verir, yani bir derleyici bunu gördüğünde , aşağıdaki bilgilerin eksik olduğunu ve uygulanmaya ihtiyacı olduğunu bilir . Arayüzler her zaman eksiktir, ancak soyut sınıflar soyuttur çünkü incomplete (abstract)yöntemlere sahip olmak zorundaydılar .
Rakib

85

Bir arayüz tekil değişkenler (genel statik final) ve genel soyut yöntemlerden oluşur. Normalde ne yapacağımızı bildiğimiz ancak nasıl yapacağımızı bilmediğimizde gerçek zamanlı olarak bir arayüz kullanmayı tercih ederiz .

Bu kavram örneklerle daha iyi anlaşılabilir:

Bir Ödeme sınıfı düşünün. Ödeme PayPal, kredi kartı vb.Gibi birçok şekilde yapılabilir. Bu nedenle normalde Ödeme makePayment()yöntemini içeren bir arayüz olarak alırız ve CreditCard ve PayPal iki uygulama sınıfıdır.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

Yukarıdaki örnekte CreditCard ve PayPal iki uygulama sınıfı / stratejisidir. Bir Arabirim ayrıca Java'da soyut bir sınıf tarafından gerçekleştirilemeyen çoklu kalıtım kavramına da izin verir.

Ne yapacağımızı bildiğimiz bazı özellikler ve nasıl performans göstereceğimizi bildiğimiz diğer özellikler olduğunda soyut bir sınıf seçiyoruz .

Aşağıdaki örneği düşünün:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

Gelecekte belirli bir soyut sınıfa yöntemler (somut / soyut) eklersek, uygulama sınıfının kodunu değiştirmesi gerekmez. Ancak, gelecekte bir arabirime yöntemler eklersek, bu arabirimi uygulayan tüm sınıflara uygulamalar eklemeliyiz, aksi takdirde derleme zamanı hataları oluşur.

Başka farklılıklar da var, ancak bunlar mülakatçınızın beklediği şey olabilir. Umarım bu yardımcı oldu.


1
Eh, bu yanıtın markaları çok anlamda ve biz arasında seçim toprak kadar zaman, örneğin oldukça açıktır interfaceve abstract class.
MAC

"ne yapmalı ama nasıl yapılacağını bilmiyorum" şeklinde bir yöntem tanımladığımız için "void makePayment ();", sınıftaki yöntemin uygulamalarını tanımlarken "void makePayment ();"
Abdel-Raouf

45

Abstact sınıfı ve arayüz arasındaki fark

  1. Java 8'de arabirimlere karşı soyut sınıflar
  2. Kavramsal Fark:

Java 8'de Arabirim Varsayılan Yöntemleri

  1. Varsayılan Yöntem nedir?
  2. ForEach yöntemi derleme hatası Varsayılan Yöntem kullanılarak çözüldü
  3. Varsayılan Yöntem ve Çoklu Kalıtım Belirsizlik Sorunları
  4. Java arayüzü varsayılan yöntemleri hakkında önemli noktalar:

Java Arayüzü Statik Yöntemi

  1. Java Arayüzü Statik Yöntem, kod örneği, statik yöntem vs varsayılan yöntem
  2. Java arayüzü statik yöntemi hakkında önemli noktalar:

Java İşlevsel Arabirimleri



Java 8'de arabirimlere karşı soyut sınıflar

Java 8 arabirim değişiklikleri, arabirimlerde statik yöntemleri ve varsayılan yöntemleri içerir. Java 8'den önce, arayüzlerde yalnızca yöntem bildirimleri alabilirdik. Ancak Java 8'den, arayüzlerde varsayılan yöntemlere ve statik yöntemlere sahip olabiliriz.

Varsayılan Yöntemi uygulamaya koyduktan sonra arayüzler ve soyut sınıflar aynı görünüyor. Bununla birlikte, Java 8'de hala farklı bir kavramdır.

Soyut sınıf yapıcıyı tanımlayabilir. Daha yapılandırılmıştır ve kendileriyle ilişkili bir duruma sahip olabilirler. Aksine, varsayılan yöntem yalnızca belirli bir uygulamanın durumuna başvurmadan yalnızca diğer arabirim yöntemlerini çağırmak açısından uygulanabilir. Bu nedenle, hem farklı amaçlar için kullanın hem de ikisi arasında seçim yapmak senaryo bağlamına bağlıdır.

Kavramsal Fark:

Soyut sınıflar arayüzlerin iskeletsel (yani kısmi) uygulamaları için geçerlidir, ancak eşleşen bir arayüz olmadan mevcut olmamalıdır.

Yani soyut sınıflar, düşük görünürlük, arayüzlerin iskelet uygulamaları olarak etkili bir şekilde azaltıldığında, varsayılan yöntemler de bunu ortadan kaldırabilir mi? Kesinlikle: Hayır! Arabirimlerin uygulanması neredeyse her zaman varsayılan yöntemlerin eksik olduğu sınıf oluşturma araçlarının bir kısmını veya tamamını gerektirir. Ve eğer bazı arayüzler yapmazsa, açıkça sapıklığa yol açmaması gereken özel bir durumdur.

Java 8'de Arabirim Varsayılan Yöntemleri

Java 8 , geliştiricinin bu Arabirimin mevcut uygulamasını bozmadan Arayüzlere yeni yöntemler eklemesine izin veren “ Varsayılan Yöntem ” veya (Defender yöntemleri) yeni özelliğini sunar. Somut bir Sınıfın bu yöntem için bir uygulama sağlayamadığı durumlarda varsayılan olarak kullanılacak Arayüz tanımlama uygulamasına izin verme esnekliği sağlar.

Nasıl çalıştığını anlamak için küçük bir örnek düşünelim:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

Aşağıdaki Sınıf Java JDK 8'de başarıyla derlenecek,

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

OldInterfaceImpl örneği oluşturursanız:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

Varsayılan Yöntem:

Varsayılan yöntemler hiçbir zaman nihai değildir, senkronize edilemez ve Object'in yöntemlerini geçersiz kılamaz. Her zaman halka açıktır, bu da kısa ve tekrar kullanılabilir yöntemler yazma yeteneğini ciddi şekilde sınırlar.

Varsayılan yöntemler, bir uygulama içerdiğinden, uygulama Sınıflarını etkilemeden bir Arabirime sağlanabilir. Uygulama ile tanımlanan bir Arabirime eklenen her yöntem uygulayıcı Sınıftan etkilenmez. Bir uygulayıcı Sınıf, Arayüz tarafından sağlanan varsayılan uygulamayı geçersiz kılabilir.

Varsayılan yöntemler, bu Arayüzlerin eski uygulamalarını bozmadan mevcut Arayüzlere yeni işlevsellik eklenmesini sağlar.

Varsayılan yöntem içeren bir arabirimi genişlettiğimizde, aşağıdakileri gerçekleştirebiliriz,

  1. Varsayılan yöntemi geçersiz kılmaz ve varsayılan yöntemi devralır.
  2. Alt sınıfta geçersiz kıldığımız diğer yöntemlere benzer varsayılan yöntemi geçersiz kıl.
  3. Varsayılan yöntemi, alt sınıfı geçersiz kılmaya zorlayan soyut olarak yeniden tanımlayın.

ForEach yöntemi derleme hatası Varsayılan Yöntem kullanılarak çözüldü

Java 8 için, JDK koleksiyonları genişletildi ve forEach yöntemi tüm koleksiyona eklendi (lambdalarla birlikte çalışır). Geleneksel yöntemle kod aşağıdaki gibi görünür,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

Bu sonuç derleme hataları ile uygulayan her Sınıf bu nedenle, mevcut uygulamanın değiştirilmemesi için gerekli bir uygulama ile varsayılan bir yöntem eklendi.

Varsayılan yöntemle Yinelenebilir Arabirim aşağıdadır,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Aynı mekanizma, uygulama Sınıflarını bozmadan JDK Arabirimine Akış eklemek için kullanılmıştır .


Varsayılan Yöntem ve Çoklu Kalıtım Belirsizlik Sorunları

Java sınıfı birden çok arabirim uygulayabildiğinden ve her arabirim aynı yöntem imzasıyla varsayılan yöntemi tanımlayabildiğinden, devralınan yöntemler birbiriyle çakışabilir.

Aşağıdaki örneği ele alalım,

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

Yukarıdaki kod aşağıdaki hatayla derlenemez,

java: class Impl, InterfaceA ve InterfaceB türlerinden defaultMethod () için alakasız varsayılanları devralır

Bu sınıfı düzeltmek için varsayılan yöntem uygulamasını sağlamamız gerekir:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

Ayrıca, kendi uygulamamız yerine süper bir arayüz tarafından sağlanan varsayılan uygulamayı çağırmak istiyorsak, bunu aşağıdaki gibi yapabiliriz,

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

Yeni yöntemimizin bir parçası olarak herhangi bir varsayılan uygulamayı veya her ikisini birden seçebiliriz.

Java arayüzü varsayılan yöntemleri hakkında önemli noktalar:

  1. Java arayüzü varsayılan yöntemleri, uygulama sınıflarını kırma korkusu olmadan arayüzleri genişletmemize yardımcı olacaktır.
  2. Java arabirimi varsayılan yöntemleri, arabirimler ve soyut sınıflar arasındaki farkları kapatmıştır.
  3. Java 8 arabirimi varsayılan yöntemleri, tüm Collections sınıf yöntemi arabirimlerin kendisinde sağlanabilir gibi yardımcı program sınıflarından kaçınmamıza yardımcı olacaktır.
  4. Java arabirimi varsayılan yöntemleri, temel uygulama sınıflarını kaldırmamıza yardımcı olacaktır, varsayılan uygulamayı sağlayabiliriz ve uygulama sınıfları hangisini geçersiz kılacağını seçebilir.
  5. Arabirimlerde varsayılan yöntemleri tanıtmanın başlıca nedenlerinden biri, Java 8'de Koleksiyon API'sını lambda ifadelerini desteklemek için geliştirmektir.
  6. Hiyerarşideki herhangi bir sınıfın aynı imzalı bir yöntemi varsa, varsayılan yöntemler ilgisiz hale gelir. Varsayılan yöntem java.lang.Object içindeki bir yöntemi geçersiz kılamaz. Akıl yürütme çok basittir, çünkü Object tüm java sınıfları için temel sınıftır. Bu nedenle, arabirimlerde varsayılan yöntemler olarak tanımlanmış Object sınıfı yöntemlerimiz olsa bile, yararsız olacaktır çünkü Object sınıfı yöntemi her zaman kullanılacaktır. Bu nedenle karışıklığı önlemek için, Object sınıfı yöntemlerini geçersiz kılan varsayılan yöntemlere sahip olamayız.
  7. Java arabirimi varsayılan yöntemlerine Defender Yöntemleri veya Sanal genişletme yöntemleri de denir.

Kaynak Bağlantısı:

  1. Varsayılan yöntemlerle arabirim - Java 8'de Abstract sınıfı
  2. JDK 8 döneminde arabirime karşı soyut sınıf
  3. Sanal genişletme yöntemleri ile arayüz gelişimi

Java Arayüzü Statik Yöntemi

Java Arayüzü Statik Yöntem, kod örneği, statik yöntem vs varsayılan yöntem

Java arabirimi statik yöntemi, uygulama sınıflarında bunları geçersiz kılamamamız dışında varsayılan yönteme benzer. Bu özellik, uygulama sınıflarında yetersiz uygulama durumunda istenmeyen sonuçlardan kaçınmamıza yardımcı olur. Basit bir örnekle buna bakalım.

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Şimdi kötü uygulama ile isNull () yöntemine sahip bir uygulama sınıfı görelim.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

İsNull (String str) öğesinin basit bir sınıf yöntemi olduğunu, arayüz yöntemini geçersiz kılmadığını unutmayın. Örneğin, isNull () yöntemine @Override ek açıklaması eklersek, derleyici hatasına neden olur.

Şimdi uygulamayı çalıştıracağımız zaman, aşağıdaki çıktıyı alıyoruz.

Arayüz Boş Kontrol

Boş Kontrol Et

Arabirim yöntemini statikten varsayılana yaparsak, aşağıdaki çıktıyı alırız.

Boş Kontrol Et

MyData Yazdır ::

Boş Kontrol Et

Java arabirimi statik yöntemi yalnızca arabirim yöntemleri tarafından görülebilir; isData (MyDataImpl) sınıfından isNull () yöntemini kaldırırsak, MyDataImpl nesnesi için kullanamayız. Ancak, diğer statik yöntemler gibi, sınıf adını kullanarak arabirim statik yöntemlerini kullanabiliriz. Örneğin, geçerli bir ifade şöyle olacaktır:

boolean result = MyData.isNull("abc");

Java arayüzü statik yöntemi hakkında önemli noktalar:

  1. Java arabirimi statik yöntemi arabirimin bir parçasıdır, uygulama sınıfı nesneleri için kullanamayız.
  2. Java arabirimi statik yöntemleri, null denetim, koleksiyon sıralama gibi yardımcı yöntem yöntemleri sağlamak için iyidir.
  3. Java arabirimi statik yöntemi, uygulama sınıflarının bunları geçersiz kılmasına izin vermeyerek güvenlik sağlamamıza yardımcı olur.
  4. Nesne sınıfı yöntemleri için arabirim statik yöntemini tanımlayamıyoruz, derleyici hatasını “Bu statik yöntem örnek yöntemini Object'ten gizleyemiyor” olarak alacağız. Bunun nedeni, Java'da izin verilmemesidir, çünkü Object tüm sınıflar için temel sınıftır ve bir sınıf düzeyinde statik yönteme ve aynı imzalı başka bir örnek yönteme sahip olamayız.
  5. Koleksiyonlar gibi yardımcı program sınıflarını kaldırmak ve tüm statik yöntemlerini bulmak ve kullanmak kolay olan ilgili arayüze taşımak için java arayüzü statik yöntemlerini kullanabiliriz.

Java İşlevsel Arabirimleri

Gönderiyi sonuçlandırmadan önce, Fonksiyonel arayüzlere kısa bir giriş yapmak istiyorum. Tam olarak bir soyut yönteme sahip bir arayüz Fonksiyonel Arayüz olarak bilinir.

Bir @FunctionalInterfacearabirimi İşlevsel Arabirim olarak işaretlemek için yeni bir ek açıklama eklendi . @FunctionalInterfaceek açıklama, fonksiyonel arayüzlere soyut yöntemlerin yanlışlıkla eklenmesini önlemek için bir olanaktır. Kullanmak isteğe bağlıdır, ancak iyi bir uygulamadır.

Fonksiyonel arayüzler uzun zamandır beklenen ve Java 8'in çok aranan bir özelliğidir, çünkü onları örneklemek için lambda ifadelerini kullanmamızı sağlar. Lambda ifadeleri ve yöntem referansları için hedef türleri sağlamak üzere bir grup fonksiyonel arayüzlü java.util.function adlı yeni bir paket eklenmiştir. Gelecekteki yazılarda fonksiyonel arayüzlere ve lambda ifadelerine bakacağız.

Kaynak Konumu:

  1. Java 8 Arayüz Değişiklikleri - statik yöntem, varsayılan yöntem

8
Bu tür güncellenmiş cevapları tam olarak arıyorum. Hızlı yanıt için teşekkürler.
Ravindra babu

41

İlk ifadeniz hariç tüm ifadeleriniz geçerlidir (Java 8 sürümünden sonra):

Bir Java arabiriminin yöntemleri dolaylı olarak soyuttur ve uygulamaları olamaz

Dokümantasyon sayfasından :

Arabirim, yalnızca sabitleri, yöntem imzalarını, varsayılan yöntemleri, statik yöntemleri ve iç içe türleri içerebilen, sınıfa benzer bir başvuru türüdür

Yöntem gövdeleri yalnızca varsayılan yöntemler ve statik yöntemler için vardır.

Varsayılan yöntemler:

Bir arabirimin varsayılan yöntemleri olabilir , ancak soyut sınıflardaki soyut yöntemlerden farklıdır.

Varsayılan yöntemler, kitaplıklarınızın arabirimlerine yeni işlevler eklemenizi ve bu arabirimlerin eski sürümleri için yazılan kodla ikili uyumluluk sağlamanızı sağlar.

Varsayılan bir yöntem içeren bir arabirimi genişlettiğinizde, aşağıdakileri yapabilirsiniz:

  1. Genişletilmiş arabiriminizin varsayılan yöntemi devralmasını sağlayan varsayılan yöntemden hiç bahsetmiyorum.
  2. Bunu yapan varsayılan yöntemi yeniden belirtin abstract.
  3. Geçersiz kılan varsayılan yöntemi yeniden tanımlayın.

Statik Yöntemler:

Varsayılan yöntemlere ek olarak, arabirimlerde statik yöntemler tanımlayabilirsiniz. (Statik yöntem, herhangi bir nesne yerine tanımlandığı sınıfla ilişkilendirilmiş bir yöntemdir. Sınıfın her örneği statik yöntemlerini paylaşır.)

Bu, kitaplıklarınızda yardımcı yöntemler düzenlemenizi kolaylaştırır;

Sahip interfaceolma staticve defaultyöntemlerle ilgili dokümantasyon sayfasından örnek kod .

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Bir arabirim mi yoksa soyut sınıf mı kullanılacağını seçmek için aşağıdaki yönergeleri kullanın.

Arayüz:

  1. Bir sözleşme tanımlamak için (tercihen vatansız - Yani değişken yok)
  2. İlişkisiz sınıfları bağlamak için bir yeteneği vardır.
  3. Genel sabit değişkenleri beyan etmek ( değişmez durum )

Soyut sınıf:

  1. Kodu yakından ilişkili birkaç sınıf arasında paylaşın. Bir ilişki kurar .

  2. Ortak devletleri ilgili sınıflar arasında paylaşma (devlet somut sınıflarda değiştirilebilir)

İlgili Mesajlar:

Arayüz ve Soyut Sınıf (genel OO)

Uygulama vs uzar: Ne zaman kullanılır? Fark ne?

Bu örnekleri inceleyerek şunu anlayabilirsiniz:

İlişkisiz sınıflar arabirim aracılığıyla yeteneklere sahip olabilir, ancak ilgili sınıflar temel sınıfların genişletilmesi yoluyla davranışı değiştirir.


Ne demek "vatansız sözleşme" demek? Arayüzler hakkında madde 1
Maksim Dmitriev

1
Değişken durumun olmaması. Arabirim sabitleri olabileceğinden, veriler soyut sınıflardan farklı olarak değiştirilebilir
Ravindra babu

1
Yukarıdaki açıklamada düzeltme. Arayüzde, veri soyut sınıftan farklı olarak değiştirilemez
Ravindra babu

2
bu en iyi cevap. Sadece Java8'i ele almakla kalmaz, aynı zamanda hangi belirli durumlarda birini kullanacağınızı da açıklar.
Shuklaswag

statelessArayüz kavramı güzel bir hit. Arayüz herhangi bir duruma sahip olamaz (Arayüz sabitleri olabilir ancak nihai / statiktir, bu nedenle değişmezdir).
Kaihua

22

Açıklamanız iyi görünüyor, ama hepsini bir ders kitabından okuyormuşsunuz gibi görünebilir mi? : - /

Daha fazla rahatsız olduğum şey, örneğiniz ne kadar sağlamdı? Soyut ve arayüzler arasındaki hemen hemen tüm farkları dahil etmeye zahmet ettiniz mi?

Şahsen, bu bağlantıyı öneririm: http://mindprod.com/jgloss/interfacevsabstract.html#TABLE

kapsamlı bir farklılık listesi için ..

Umarım size ve diğer tüm okuyuculara gelecekteki görüşmelerinde yardımcı olur


1
bağlantı paylaşılıyor gerçekten harika
Premraj

Java arayüzlerinde varsayılan uygulamayı, varsayılan anahtar kelimeyi
Ogen

21

Birçok genç geliştirici, arayüzleri, soyut ve somut sınıfları aynı şeyin küçük varyasyonları olarak düşünme hatasını yapar ve bunlardan birini sadece teknik gerekçelerle seçer: Birden fazla mirasa ihtiyacım var mı? Ortak yöntemler koymak için bir yere ihtiyacım var mı? Sadece somut bir sınıftan başka bir şeyle uğraşmam gerekir mi? Bu yanlış ve bu sorularda gizli ana sorun: "Ben" . Kendiniz için kod yazdığınızda, kendi başınıza, kodunuz üzerinde veya kodunuzla çalışan diğer mevcut veya gelecekteki geliştiricileri nadiren düşünürsünüz.

Arayüzler ve soyut sınıflar, görünüşe göre teknik açıdan benzer olsalar da, tamamen farklı anlamlara ve amaçlara sahiptirler.

özet

  1. Bir arayüz , bazı uygulamaların sizin için yerine getireceği bir sözleşmeyi tanımlar .

  2. Soyut bir sınıf varsayılan bir davranış sağlar o senin uygulama yeniden kullanabilirsiniz.

Yukarıdaki bu iki nokta, görüşme yaparken aradığım şeydir ve yeterince kompakt bir özettir. Daha fazla bilgi için okumaya devam edin.

Alternatif özet

  1. Arayüz genel API'leri tanımlamak içindir
  2. Soyut bir sınıf, dahili kullanım ve SPI'ları tanımlamak içindir

Örnek olarak

Başka bir deyişle: Somut bir sınıf, asıl işi çok özel bir şekilde yapar. Örneğin, bir kullanıcı ArrayList, nesnelerin listesini hızlı rasgele erişim, yineleme ve yerinde değişiklikler sunan, ancak eklemelerde, silmelerde ve hatta bazen eklemelerde korkunç bir şekilde saklamak için bitişik bir bellek alanı kullanır; bu arada, birLinkedListbunun yerine hızlı yineleme, yerinde değişiklikler ve ekleme / silme / ekleme sunan ancak rasgele erişimde korkunç olan bir nesne listesini saklamak için çift bağlantılı düğümler kullanır. Bu iki tür liste farklı kullanım durumları için optimize edilmiştir ve bunları nasıl kullanacağınız çok önemlidir. Performansı, yoğun bir şekilde etkileşimde bulunduğunuz bir listeden çıkarmaya çalıştığınızda ve liste türünü seçmek size kaldığında, hangisini somutlaştırdığınızı dikkatlice seçmelisiniz.

Öte yandan, bir listenin üst düzey kullanıcıları listenin gerçekte nasıl uygulandığını gerçekten umursamazlar ve bu ayrıntılardan izole edilmelidirler. Java'nın Listarayüzü açığa vurmadığını, ancak şu anda Listgerçekte olan somut bir sınıfı olduğunu hayal edelim LinkedList. Tüm Java geliştiricileri kodlarını uygulama ayrıntılarına uyacak şekilde uyarlamışlardı: rastgele erişimden kaçının, erişimi hızlandırmak için bir önbellek ekleyin veya yalnızca ArrayListkendileriyle yeniden uygulayın, ancak Listyalnızca gerçekte çalışan diğer tüm kodlarla uyumsuz olurdu . Bu korkunç olurdu ... Ama şimdi Java ustalarının aslında bağlantılı bir listenin çoğu gerçek kullanım durumu için korkunç olduğunu fark ettiklerini ve sadece bir dizi listesine geçmeye karar verdiklerini hayal edinListkullanılabilir sınıf. Bu, dünyadaki her Java programının performansını etkiler ve insanlar bu programdan memnun olmazlar. Ve asıl suçlu, uygulama detaylarının mevcut olması ve geliştiricilerin bu detayların güvenebilecekleri kalıcı bir sözleşme olduğunu varsaymalarıydı. Bu nedenle uygulama ayrıntılarını gizlemek ve yalnızca soyut bir sözleşme tanımlamak önemlidir. Bu bir arayüzün amacıdır: bir programın ne tür bir girişi kabul ettiğini ve ne tür bir çıktı beklendiğini tanımlayın, programcıları gelecekteki herhangi bir güncellemeyle değişebilecek iç detaylara uyacak şekilde kodlarını değiştirmeye teşvik edecek tüm cesaretleri ortaya çıkarmadan .

Soyut bir sınıf, arayüzler ve somut sınıflar arasında ortadadır. Uygulamaların ortak veya sıkıcı kodları paylaşmasına yardımcı olması gerekiyor. Örneğin, yinelemede olduğu gibi tekrarlanan ve karşılaştırıldığı gibi, tekrar boyutuna göre boyut 0 AbstractCollectioniçin temel uygulamalar sağlar . Bu, uygulamaların aralarında ayrım yapan önemli parçalara odaklanmasını sağlar: Verilerin gerçekte nasıl depolanacağı ve alınacağı.isEmptycontainsaddAlladd

Başka bir bakış açısı: API'ler ve SPI'lar

Arabirimler, kodun farklı bölümleri arasındaki düşük bütünlüklü ağ geçitleridir . Bir şey dahili olarak değiştiğinde her kütüphane kullanıcısını bozmadan kütüphanelerin var olmasına ve gelişmesine izin verir. Buna Uygulama Programlama Sınıfları değil, Uygulama Programlama Arayüzü denir . Daha küçük ölçekte, farklı modülleri iyi belgelenmiş arabirimlerle ayırarak birden fazla geliştiricinin büyük ölçekli projelerde başarılı bir şekilde işbirliği yapmasına izin verir.

Soyut sınıflar, bir arabirim uygulanırken, bazı düzeyde uygulama ayrıntılarını varsayarak , yüksek uyum sağlayan yardımcılardır . Alternatif olarak, soyut sınıflar SPI'leri, Servis Sağlayıcı Arayüzlerini tanımlamak için kullanılır.

Bir API ve bir SPI arasındaki fark anlaşılır, ancak önemlidir: bir API için odak noktası onu kimin kullandığına ve bir SPI için odak noktası onu kimin uyguladığına odaklanır .

Bir API'ya yöntem eklemek kolaydır, API'nin mevcut tüm kullanıcıları derlemeye devam eder. Her hizmet sağlayıcı (somut uygulama) yeni yöntemleri uygulamak zorunda kalacağından, bir SPI'ya yöntem eklemek zordur. Bir SPI tanımlamak için arabirimler kullanılıyorsa, SPI sözleşmesi her değiştiğinde bir sağlayıcı yeni bir sürüm yayınlamak zorundadır. Bunun yerine soyut sınıflar kullanılırsa, yeni yöntemler ya mevcut soyut yöntemler açısından tanımlanabilir ya da throw not implemented exceptionen azından bir hizmet uygulamasının eski bir sürümünün hala derlenip çalışmasına izin verecek boş saplamalar olarak tanımlanabilir .

Java 8 ve varsayılan yöntemler hakkında bir not

Java 8, arabirimler ve soyut sınıflar arasındaki çizgiyi daha da bulanıklaştıran arabirimler için varsayılan yöntemler sunmasına rağmen, bu, uygulamaların kodu yeniden kullanabilmesi için değil, hem API hem de SPI olarak hizmet veren arabirimleri değiştirmeyi kolaylaştırmak için (veya soyut sınıflar yerine SPI'leri tanımlamak için yanlış kullanılır).

"Kitap bilgisi"

Bu genellikle okulda ve bir dili hakkında en teknoloji kitaplarında kullanılan yaklaşımdır çünkü OP'ın yanıtında sağlanan teknik detaylar "kitap bilgi" olarak kabul edilir: Ne bir şeydir, değil nasıl özellikle büyük ölçekli uygulamalarda, uygulamada kullanmak .

İşte bir benzetme: Sorunun şuydu:

Balo gecesi, araba veya otel odası için kiralamak daha iyi ne olabilir?

Teknik cevap şöyle geliyor:

Eh, bir arabada daha erken yapabilirsiniz, ancak bir otel odasında daha rahat yapabilirsiniz. Öte yandan, otel odası sadece tek bir yerde, arabada daha fazla yerde yapabilirsiniz, örneğin, güzel bir manzara için manzara noktasına gidebilir veya bir tiyatroya gidebilirsiniz, veya başka birçok yerde, hatta birden fazla yerde. Ayrıca, otel odasında duş vardır.

Bu doğru, ancak tamamen farklı iki şey olduklarını tamamen kaçırıyor ve her ikisi de aynı anda farklı amaçlar için kullanılabilir ve "bunu yapmak" yönü iki seçenekten herhangi biri için en önemli şey değildir . Cevap perspektiften yoksundur, gerçek "gerçekleri" doğru bir şekilde sunarken, olgunlaşmamış bir düşünme şekli gösterir.


Şunu mu demek istediniz: "low-coupling"?
user2418306

@ user2418306 Hayır, uyum, yakın eşanlamlı olmalarına rağmen her iki terim de işe yarayacak olsa da, birleştirmeyi içeren daha genel bir terimdir.
Sergiu Dumitriu

9

Aşağıdaki şekilde düşünmeye ne dersiniz:

  • Bir sınıf ile soyut bir sınıf arasındaki ilişki "is-a" türündedir.
  • Sınıf ve arabirim arasındaki ilişki "has-a" türündedir.

Yani soyut bir sınıf Memeliler, bir alt sınıf İnsan ve bir Sürüş Sürüş varsa, o zaman diyebilirsiniz

  • her insan bir memelidir
  • her İnsanın bir Sürüşü vardır (davranış)

Benim önerim, kitap bilgi cümlesinin her ikisi arasındaki anlamsal farkı duymak istediğini göstermesidir (burada başkalarının önerdiği gibi).


9

Bir arabirim, sözleşmeyi uygulayan sınıfın yöntemleri uygulamayı vaat ettiği bir "sözleşme" dir. Sınıf yerine arayüz yazmak zorunda olduğum bir örnek, bir oyunu 2D'den 3D'ye yükselttiğim zamandı. Oyunun 2D ve 3D sürümü arasında sınıfları paylaşmak için bir arayüz oluşturmak zorunda kaldım.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

Daha sonra oyunun hangi sürümünü yüklediğini bilmeyen bir nesneden bu yöntemleri çağırabilirken, ortama dayalı yöntemleri uygulayabilirim.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Tipik olarak, oyun dünyasında, dünya oyunda yöntemler gerçekleştiren soyut bir sınıf olabilir:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

6

Soyut sınıflar somut soyutlama değildir bcz somut koleksiyonu (uygulanan yöntemler) ve uygulanmayan yöntemler. Ancak Arayüzler saf soyutlamadır bcz somut yöntemler değil sadece uygulanmayan yöntemler vardır.

Neden Soyut dersler?

  1. Kullanıcı tüm nesneler için ortak işlevsellik yazmak istiyorsa.
  2. Soyut sınıflar, son kullanıcıyı etkilemeden daha fazla işlevsellik eklemek için gelecekte yeniden uygulama için en iyi seçimdir.

Neden Arayüzler?

  1. Kullanıcı nesneler üzerinde farklı işlevler olacak farklı işlevler yazmak isterse.
  2. Arayüzler, arayüz yayınlandıktan sonra gereksinimlerin değiştirilmesi gerekmediği takdirde en iyi seçimdir.

5

Bir arayüz , bir tür etkiye sahip olması için kamuya açık olarak belgelenmiş bir dizi gen gibidir: Bir DNA testi bana bunları alıp almadığımı söyler - ve eğer yaparsam, bir "taşıyıcı" olduğumu açıkça söyleyebilirim "ve davranışlarımın veya durumumun bir kısmı onlara uyacaktır. (Ama elbette, bu kapsamın dışında özellikler sağlayan birçok genim olabilir.)

Bir soyut sınıf bir ölü atası gibidir Tek cinsiyetli türlere O hayata edilemez ancak yaşayan (yani: (*) olmayan soyut ) soyundan INHERITS onun tüm genler.

(*) Bu metaforu genişletmek için, türün tüm üyelerinin aynı yaşta yaşadığını varsayalım. Bu, ölü bir ataların tüm atalarının da ölü olması gerektiği anlamına gelir - ve aynı şekilde, yaşayan bir ataların tüm torunları hayatta olmalıdır.


4

İş için röportajlar yapıyorum ve cevabınıza olumsuz olarak bakacağım (üzgünüm ama çok dürüstüm). Farkı okuduğunuz ve bir cevabı revize ettiğiniz gibi görünüyor, ancak belki de pratikte hiç kullanmadınız.

Neden her birini kullanacağınıza dair iyi bir açıklama, farkın kesin bir açıklamasına sahip olmaktan çok daha iyi olabilir. İşverenler ultimatley, programcıların bir röportajda gösterilmesi zor olabilecek, kendilerini bilmeyen şeyler yapmalarını ister. Verdiğiniz cevap, teknik veya belgelere dayalı bir işe başvurmak, ancak geliştiricilerin rolü için değilse iyi olur.

Gelecekte röportajlarda bol şans.

Ayrıca bu soruya verdiğim cevap, sağladığınız teknik materyalden çok röportaj tekniği ile ilgili. Belki de bu konuda okumayı düşünün. https://workplace.stackexchange.com/ bu tür şeyler için mükemmel bir yer olabilir.


1
Bana nasıl cevap verdiğini söyleyebilir misin? Belki bana yardımcı olabilir.
code_fish

size cevap vermenize yardımcı olmaktan çok daha az şey sunar, temel olarak her birini ne zaman kullanacağınıza dair pratik bir örnek verin ve her birinin neden farklı görevlere uygun olduğunu açıklayın.
Adrian

4

Birden fazla devralmada Elmas Sorunu'ndan kaçınmak için Java'daki Arabirim'i seçersiniz .

Tüm yöntemlerinizin müşteriniz tarafından uygulanmasını istiyorsanız arayüze gidersiniz. Tüm uygulamayı soyut olarak tasarladığınız anlamına gelir.

Ortak olanı zaten biliyorsanız soyut sınıfı seçersiniz. Örneğin soyut bir sınıf alın Car. Daha yüksek düzeyde ortak araç yöntemlerini uygularsınız calculateRPM(). Bu yaygın bir yöntemdir ve müşterinin
calculateMaxSpeed()vb. Gibi kendi davranışlarını uygulamasına izin verirsiniz . Muhtemelen günlük işinizde karşılaştığınız birkaç gerçek zamanlı örnek vererek açıklarsınız.



3

Gözlemlediğim temel fark, soyut sınıfın bize zaten uygulanan bazı ortak davranışlar sağlaması ve alt sınıfların sadece bunlara karşılık gelen belirli işlevleri uygulaması gerektiğiydi. burada bir arayüz gelince sadece hangi görevlerin yapılması gerektiğini belirleyecek ve arayüz tarafından hiçbir uygulama yapılmayacaktır. Kendisiyle uygulamalı sınıflar arasındaki sözleşmeyi belirlediğini söyleyebilirim.


3

Ben bile aynı soruya birden fazla röportajda rastladım ve inanın bana zamanınızı mülakatçıyı ikna etmenin sefil hale getiriyor. Yukarıdaki tüm cevapları içsel alırsam, OO'yu daha ikna edici ve en iyi şekilde kullanmak için bir anahtar nokta daha eklemem gerekir.

Eğer edilmez kurallarda herhangi bir değişiklik planlama Eğer içinde değiştirmek mümkün olmayacak şekilde, arayüz için gidip bunu yaparsanız, sizin için gitmek gerekir, uzun bir gelecek için, izlenecek alt sınıf için, diğer tüm alt sınıflardaki değişiklikler, oysa, işlevselliği yeniden kullanmak, bazı kurallar belirlemek ve değişiklik için açık hale getirmek istiyorsanız, Abstract sınıfına gidin.

Bu şekilde düşünün, sarf malzemesi hizmeti kullandınız ya da dünyaya bir kod verdiniz ve bir şeyi değiştirme, güvenlik kontrolünü varsayalım. Eclipse içindeki tüm okuma işaretlerini bulmak, tüm uygulama kapalı. Bu tür kabusları önlemek için Arayüzler Üzerindeki Özet'i kullanın

Bunun Mülakatçıyı bir ölçüde ikna edebileceğini düşünüyorum ... İleride Mutlu Görüşmeler.


2

Davranışı yakından ilişkili 2 sınıf arasında paylaşmaya çalıştığımda, ortak davranışı tutan ve her iki sınıfa da ebeveyn olarak hizmet eden soyut bir sınıf oluşturuyorum.

Bir tür tanımlamak çalıştığımda, nesnemdeki bir kullanıcının güvenilir bir şekilde çağırabileceği yöntemlerin bir listesi, sonra bir arayüz oluşturuyorum.

Örneğin, asla 1 somut alt sınıfla soyut bir sınıf yaratmam, çünkü soyut sınıflar davranışları paylaşmakla ilgilidir. Ancak tek bir uygulama ile çok iyi bir arayüz oluşturabilirim. Kodumun kullanıcısı tek bir uygulama olduğunu bilemez. Aslında, gelecekteki bir sürümde, hepsi arayüzü oluşturduğumda bile var olmayan bazı yeni soyut sınıfların alt sınıfları olan birkaç uygulama olabilir.

Bu biraz fazla kitap gibi görünüyordu (ben hatırladım herhangi bir yere koymak asla görmemiş olsa da). Eğer görüşmeci (ya da OP) bu konudaki kişisel deneyimimi gerçekten daha fazla isteseydi, bir arayüzün fıkraları ile hazır olmalıydım ve bunun tersi de doğrudur.

Bir şey daha. Java 8 artık arayüze ve soyut sınıflar arasındaki çizgiyi daha da bulanıklaştırarak varsayılan kodu bir arayüze koymanıza izin veriyor. Ama gördüğüm kadarıyla, bu özellik Java çekirdek kütüphanelerinin yapımcıları tarafından bile aşırı kullanıldı. İkili uyumsuzluk yaratmadan bir arayüzün genişletilmesini mümkün kılmak için bu özellik eklenmiştir. Ancak, bir arabirim tanımlayarak yepyeni bir Tip yapıyorsanız, arabirim SADECE bir arabirim olmalıdır. Ortak kod sağlamak istiyorsanız, elbette bir yardımcı sınıf (soyut veya somut) yapın. Değiştirmek isteyebileceğiniz işlevsellik ile arabiriminizi baştan beri karıştırmayın.


2

Arayüz ve soyut sınıf arasındaki temel fark, arayüz çoklu mirası destekliyor ancak soyut sınıfı desteklemiyor.

Soyut sınıfta arayüz gibi tüm soyut yöntemleri de sağlayabilirsiniz.

neden soyut sınıf gereklidir?

Bazı senaryolarda, kullanıcı isteği işlenirken soyut sınıf hangi kullanıcının niyetini bilmez. Bu senaryoda, sınıfta bir soyut yöntem tanımlayacağız ve bu sınıfı kimin genişlettiğini kullanıcıya soracağız, lütfen soyut yöntemde niyetinizi belirtin. Bu durumda soyut sınıflar çok faydalıdır

Neden arayüz gerekli?

Diyelim ki o alanda tecrübem olmayan bir işim var. Örneğin, bir bina veya baraj inşa etmek istiyorsanız, o zaman bu senaryoda ne yapacaksınız?

  1. gereksinimlerinizin neler olduğunu belirleyecek ve bu gereksinimlerle sözleşme yapacaksınız.
  2. Ardından projenizi inşa etmek için İhaleleri arayın
  3. Projeyi kim inşa etti, bu da ihtiyaçlarınızı karşılamalı. Ancak inşaat mantığı bir satıcıdan diğer satıcıya farklıdır.

Burada nasıl inşa ettikleri mantığı ile uğraşmıyorum. Son nesne benim gereklerimi karşıladı ya da karşılamadı, bu sadece benim kilit nokta.

Burada arayüz ve yapıcılar olarak adlandırılan gereksinimlerinize uygulayıcı denir.


2

Birkaç kelimeyle, bu şekilde cevap verirdim:

  • sınıf hiyerarşisi yoluyla miras bir devlet mirası anlamına gelir ;
  • arayüzler yoluyla kalıtım , davranış kalıtım anlamına gelir ;

Soyut sınıflar bu iki durum arasında bir şey olarak ele alınabilir (bazı durumları tanıtır, ancak aynı zamanda bir davranış tanımlamanızı zorunlu kılar), tamamen soyut bir sınıf bir arabirimdir (bu, sınıfların daha ileri bir gelişmesidir. sözdiziminin farkında olduğum kadarıyla).

Elbette, Java 8'den başlayarak işler biraz değişti, ancak fikir hala aynı.

Bir derleyici ekibiyle röportaj yapmıyorsanız, tipik bir Java röportajı için bu oldukça yeterli.


1

Anladığım kadarıyla, son değişkenlerden ve uygulama içermeyen yöntemlerden oluşan bir Arayüz, bir sınıf tarafından birbiriyle ilişkili bir grup yöntem veya yöntem elde etmek için uygulanır. Öte yandan, nihai olmayan değişkenleri ve uygulamaları olan yöntemleri içerebilen soyut bir sınıf genellikle bir rehber olarak veya ilgili veya benzer sınıfların miras aldığı bir üst sınıf olarak kullanılır. Başka bir deyişle, bir soyut sınıf, tüm alt sınıfları tarafından paylaşılan tüm yöntemleri / değişkenleri içerir.


1

Soyut sınıfta, yöntemlerin varsayılan uygulamasını yazabilirsiniz! Ancak Arayüzde yapamazsınız. Temel olarak, arayüzde, arayüzü uygulayan sınıf tarafından uygulanması gereken saf sanal yöntemler vardır.


1

Evet, yanıtlarınız teknik olarak doğruydu, ancak yanlış yaptığınız yerlere onları göstermemek, diğerini seçmenin olumsuz ve olumsuz yönlerini anlıyorsunuz. Ayrıca, muhtemelen kod tabanlarının gelecekte yükseltmelerle uyumluluğu konusunda endişe duyuyorlardı. Bu tür bir yanıt yardımcı olabilir (söylediklerinize ek olarak):

"Bir Arabirim Sınıfı üzerinden bir Özet Sınıf seçmek, kodun geleceğini ne projelendireceğimize bağlıdır.

Soyut sınıflar daha iyi ileri uyumluluk sağlar, çünkü mevcut kodunuzu kırmadan bir Soyut Sınıfa gelecekteki davranışları eklemeye devam edebilirsiniz -> bu bir Arayüz Sınıfıyla mümkün değildir.

Öte yandan, Arayüz Sınıfları Soyut Sınıflardan daha esnektir. Bunun nedeni birden fazla arabirim uygulayabilmeleridir . Şey, Java'nın birden fazla mirasa sahip olmamasıdır, bu nedenle soyut sınıfları kullanmak, başka bir sınıf hiyerarşi yapısını kullanmanıza izin vermez ...

Sonuçta, iyi bir genel kural şöyledir: Kod tabanınızda mevcut / varsayılan uygulamalar olmadığında Arayüz Sınıfları kullanmayı tercih edin. Ayrıca, gelecekte sınıfınızı güncelleyeceğinizi biliyorsanız uyumluluğu korumak için Soyut Sınıflar'ı kullanın. "

Bir sonraki röportajda iyi şanslar!


1

İkisi arasındaki farkı göstermek için pratik senaryo kullanarak cevap vermeye çalışacağım.

Arabirimler sıfır yük ile gelir, yani hiçbir durum korunmamalıdır ve bu nedenle bir sözleşmeyi (yetenek) bir sınıfla ilişkilendirmek için daha iyi bir seçimdir.

Örneğin, bazı eylemi gerçekleştiren bir Görev sınıfım var, şimdi ayrı bir iş parçacığında bir görev yürütmek için gerçekten iş parçacığı sınıfını genişletmek zorunda değilim daha iyi bir seçim Görev uygulamak Runnable arabirimi (yani onun run () yöntemini uygulamak yapmaktır ) ve ardından bu Görev sınıfının nesnesini bir Thread örneğine geçirin ve start () yöntemini çağırın.

Şimdi Runnable'ın soyut bir sınıf olup olmadığını sorabilirsiniz?

Teknik olarak bu mümkün oldu ama kötü bir seçim nedeni olurdu tasarım akıllıca:

  • Runnable'ın kendisiyle ilişkilendirilmiş bir durumu yoktur ve ne de run () yöntemi için herhangi bir varsayılan uygulamayı 'sunar'
  • Görev onu genişletmek zorunda kalacaktı, böylece başka bir sınıfı genişletemedi
  • Görevin Runnable sınıfına uzmanlık olarak sunacak hiçbir şeyi yoktur, tek gereken run () yöntemini geçersiz kılmaktır

Başka bir deyişle, Görev sınıfı, bir iş parçacığı haline getirecek Thread sınıfını genişleten Runnable arabirim ayetleri uygulayarak elde ettiği bir iş parçacığında çalıştırılabilme özelliğine ihtiyaç duyuyordu.

Sadece bir kabiliyet (sözleşme) tanımlamak için arayüz koymak, iskelet (ortak / kısmi) uygulamasını tanımlamak için soyut bir sınıf kullanın.

Feragatname: aptal örnek aşağıdaki gibidir, yargılamamaya çalışın :-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

Şimdi size GodLike olma seçeneği sunuldu, ancak yalnızca Forgiver olmayı (yani GodLike değil) seçebilir ve şunları yapabilirsiniz:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Veya GodLike olmayı seçebilir ve şunları yapabilirsiniz:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

Java 8 arabirimli PS de statik (varsayılan) (geçersiz kılınabilir uygulama) yöntemlerine sahip olabilir ve böylece fark s / b arabirimi ve soyut sınıf daha da daraltılır.


1

Hemen hemen her şey pratik uygulamasına ilişkin sadece bir noktayı daha eklemek .. zaten burada ele alınacak gibi görünüyor abstractsınıfın:

abstractanahtar kelime ayrıca bir sınıfın somutlaştırılmasını önlemek için de kullanılır. Eğer somutlaştırılmak istemediğiniz somut bir sınıfınız varsa - yapın abstract.


1

hmm şimdi insanlar aç pratik yaklaşım, oldukça haklısın ama görüşmecinin çoğu mevcut gereksinimlerine göre görünüyor ve pratik bir yaklaşım istiyor.

cevabınızı bitirdikten sonra örneğe atlamalısınız:

Öz:

örneğin, tüm çalışanlar için ortak olan bazı parametarları olan maaş fonksiyonumuz var. kısmi olarak tanımlanmış yöntem gövdesi ile CTC adında soyut bir sınıfa sahip olabiliriz ve her tür çalışan tarafından genişletilir ve ekstra beefitelerine göre kurtarılır. Ortak işlev için.

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

Arayüz

java arabirimi, bunu genişletmeden interfcae işlevselliğine izin verir ve uygulamanızda tanıtmak istediğiniz işlevsellik imzasının uygulanması ile net olmanız gerekir. sizi tanımlamaya zorlar. Farklı işlevler için.

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

soyut bir sınıf olarak tanımlanmış methgos tarafından soyut sınıfla da böyle zorlanmış bir aktiviteye sahip olabilirsiniz, şimdi bu soyut fonksiyonu geçersiz kılana kadar soyut sınıfı anımsatan bir sınıfı genişletir.


1

Anladığım ve nasıl yaklaştığımdan,

Arabirim bir şartname / sözleşme gibidir, bir arabirim sınıfı uygulayan herhangi bir sınıf, soyut sınıfta tanımlanan tüm yöntemleri uygulamak zorundadır (varsayılan yöntemler hariç (Java 8'de tanıtılır))

Sınıfın bazı yöntemleri ve bazı yöntemler için gerekli olan uygulamayı bildiğimde bir sınıf özeti tanımlarken yine de uygulamanın ne olacağını bilmiyorum (fonksiyon imzasını biliyor olabiliriz, ancak uygulamayı değil). Bunu daha sonra gelişimin bu yöntemlerin nasıl uygulanacağını bildiğimde yapacağım, bu soyut sınıfı genişletip bu yöntemleri uygulayabileceğim.

Not: Yöntem statik veya varsayılan olmadığı sürece, arabirim yöntemlerinde işlev gövdesine sahip olamazsınız.


0

Görüşmecinin ulaşmaya çalıştığı şeyin muhtemelen arayüz ve uygulama arasındaki fark olduğuna inanıyorum.

Bir Java modülünü değil, daha genel anlamda "arayüzünü" içeren arabirim, temel olarak, arabirimi kullanan istemci koduyla yapılan sözleşmedir.

Kod modülünün uygulanması, modülün çalışmasını sağlayan dahili koddur. Genellikle belirli bir arabirimi birden fazla farklı şekilde uygulayabilir ve hatta değişikliğin farkında bile olsa istemci kodu olmadan uygulamayı değiştirebilirsiniz.

Bir Java arabirimi, herhangi bir uygulama belirtmeden, sınıfın sınıfı kullanan istemci kodu yararına nasıl davrandığını tanımlamak için yalnızca yukarıdaki genel anlamda bir arabirim olarak kullanılmalıdır. Bu nedenle, arabirim, istemci kodu tarafından çağrılması beklenen yöntemler için yöntem imzaları - adlar, dönüş türleri ve bağımsız değişken listeleri - içerir ve ilke olarak bu yöntemin ne yaptığını açıklayan her yöntem için bol miktarda Javadoc olmalıdır. Bir arabirimi kullanmanın en zorlayıcı nedeni, arabirimin birden çok farklı uygulamasını kullanmayı planlıyorsanız, belki de dağıtım yapılandırmasına bağlı olarak bir uygulama seçmenizdir.

Bir Java soyut sınıfı, aksine, birincil bir arabirim belirtmek yerine sınıfın kısmi bir uygulamasını sağlar. Birden fazla sınıfın kodu paylaştığı ancak alt sınıfların da uygulamanın bir kısmını sağlaması beklendiğinde kullanılmalıdır. Bu, paylaşılan kodun yalnızca bir yerde - soyut sınıf - görünmesine izin verirken, uygulamanın bazı bölümlerinin soyut sınıfta bulunmadığını ve alt sınıflar tarafından sağlanması beklenmektedir.


0

cevabınız doğru, ancak görüşmeci Java'nın detaylarına göre değil, yazılım mühendisliği perspektifine göre farklılaşmanızı istiyor.

Basit kelimeler:

Bir Arayüz bir dükkanın arayüzü gibidir, üzerinde gösterilen her şey dükkanda bulunmalıdır, bu yüzden Arayüzdeki herhangi bir yöntem beton sınıfında uygulanmalıdır. Şimdi ya bazı sınıflar bazı kesin yöntemleri paylaşıyorsa ve diğerlerinde değişiyorsa. Arayüzün iki şey içeren bir dükkanla ilgili olduğunu varsayalım ve iki mağazamızın her ikisi de spor malzemeleri içerdiğini, ancak birinin ekstra kıyafetleri olduğunu ve diğerinin ayakkabılarının ekstra olduğunu varsayalım. Yaptığınız şey, Sport için Sports yöntemini uygulayan ve diğer yöntemi uygulanmamış bırakan soyut bir sınıf yapmaktır. Buradaki soyut sınıf, bu dükkanın kendi başına var olmadığı anlamına gelir, ancak diğer sınıfların / dükkanların temelidir. Bu şekilde kodu düzenlersiniz, kodu çoğaltma hatalarından kaçınırsınız, kodu birleştirirsiniz ve başka bir sınıf tarafından yeniden kullanılabilirliği sağlarsınız.

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.