Java'daki varsayılan anahtar kelimenin amacı nedir?


95

Java'daki bir arabirim bir sınıfa benzer, ancak bir arabirimin gövdesi yalnızca soyut yöntemler ve finalalanlar (sabitler) içerebilir .

Geçenlerde şuna benzeyen bir soru gördüm

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Arayüz tanımına göre sadece soyut yöntemlere izin verilir. Neden yukarıdaki kodu derlememe izin veriyor? Nedir defaultkelime?

Öte yandan, aşağıdaki kodu yazmaya çalışırken diyor ki modifier default not allowed here

default class MyClass{

}

onun yerine

class MyClass {

}

Biri bana defaultanahtar kelimenin amacını söyleyebilir mi? Sadece bir arayüz içinde mi izin verilir? default(Erişim değiştirici yok) ' dan farkı nedir?


4
arayüzlerdeki varsayılan yöntemler Java 8'e eklendi. Bu bir erişim değiştirici değil, varsayılan bir gerçeklemedir.
Eran

2
@Eran düşünmüyor musun, arayüz tanımını ihlal eden varsayılan yöntemin tanıtımı? : s
Ravi

2
Arayüz tanımını değiştirdi. Bu tanım artık güncel değil.
Louis Wasserman

2
Lambdaları desteklemek için tanıtıldılar. Neden gerekli olduklarının ayrıntıları Lambda Projesi için saman adam teklifinde yer almaktadır.
sprinter

Yanıtlar:


75

Java 8'de interfacebir uygulama sağlamaya izin veren yeni bir özelliktir . Java 8 JLS-13.5.6'da açıklanmıştır. (Kısmen) okuyan Arayüz Yöntemi Bildirimleri

Bir defaultyöntem eklemek veya bir yöntemi olarak abstractdeğiştirmek default, önceden var olan ikili dosyalar ile uyumluluğu bozmaz, ancak IncompatibleClassChangeErrorönceden var olan bir ikili programın yöntemi çağırmaya çalışmasına neden olabilir . Eleme tipi, eğer bu hata oluşur T, iki arayüz bir alt tipi olan, Ive Jböylelikle iki taraf Ive Jbir beyan defaultaynı imza ve sonuçla yöntemi ve ne Ide Jdiğer bir subinterface olduğunu.

JDK 8'deki Yenilikler (kısmen) diyor

Varsayılan yöntemler, kitaplıkların arabirimlerine yeni işlevlerin eklenmesini sağlar ve bu arabirimlerin eski sürümleri için yazılan kodla ikili uyumluluğu sağlar.


16
Görünüşe göre, şimdi arayüz ve soyut sınıf neredeyse aynı. :)
Ravi

16
@jWeaver arabirimleri hala yapıcılara, alanlara, özel yöntemlere veya equals / hashCode / toString uygulamalarına sahip olamaz.
Louis Wasserman

10
@Louis Wasserman: Java 9'da privateyöntemleri olabilir .
Holger

6
@Dan Pantry: privateyöntemler arayüzün bir parçası değildir, ancak defaultuygulamalar için yardımcı yöntemler olarak veya sabit başlatıcılar içinde hizmet edebilir . Arabirimler içinde lambda ifadeleri kullandığınızda, sentetik privateyöntemler üretildiğinden , bunların Java 8'de zaten var olduğunu unutmayın . Yani Java 9, bu özelliği sentetik olmayan, lambda dışı kullanımlar için de kullanmanıza izin verir…
Holger

14
@jWeaver Arabirimler ve sınıflar arasındaki fark, duruma karşı davranışa indirgenir . Arabirimler davranış taşıyabilir, ancak yalnızca sınıfların durumu olabilir. (Alanlar, yapıcılar ve equals / hashCode gibi yöntemler durum hakkındadır.)
Brian Goetz

26

Varsayılan yöntemler, öncelikle lambda ifadelerini desteklemek için Java 8'e eklenmiştir. Tasarımcılar (bana göre akıllıca bir şekilde) bir arayüzün anonim uygulamalarını oluşturmak için lambdas sözdizimi yapmaya karar verdiler. Ancak verilen lambdalar yalnızca tek bir yöntemi uygulayabilirler, bunlar oldukça ciddi bir kısıtlama olacak tek bir yöntemle arayüzlerle sınırlandırılacaktır. Bunun yerine, daha karmaşık arayüzlerin kullanılmasına izin vermek için varsayılan yöntemler eklenmiştir.

defaultLambdas nedeniyle ortaya atılan iddiayı ikna etmeye ihtiyacınız varsa , 2009 yılında Mark Reinhold tarafından Lambda Projesi'nin saman adam önerisinin lambdaları desteklemek için eklenmesi zorunlu bir özellik olarak 'Uzatma yöntemleri'nden bahsettiğini unutmayın.

İşte kavramı gösteren bir örnek:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

Çok yapmacık, farkındayım ama defaultlambdaları nasıl desteklediğini göstermeliyim . inverseÖntanımlı olduğundan , gerekirse bir uygulama sınıfı tarafından kolaylıkla geçersiz kılınabilir.


8
Bu gerçekten doğru değil. Lambdas en yakın neden olabilir, ancak gerçekten de devenin sırtını kıran samanlardı. Gerçek motivasyon, arayüz gelişimini sağlamaktı (mevcut arayüzlerin yeni davranışı desteklemek için uyumlu bir şekilde geliştirilmesine izin vermek); Lambdas bu ihtiyacı ön plana çıkaran faktör olabilir, ancak özellik bundan daha geneldir.
Brian Goetz

@BrianGoetz: IMHO, hem Java hem de .NET, başlangıçtan itibaren varsayılan yöntemler mevcut olsaydı, büyük ölçüde fayda sağlardı. Yalnızca arayüz üyeleri kullanılarak bir arayüzün herhangi bir uygulamasında bazı ortak işlemler gerçekleştirilebiliyorsa, ancak bazı uygulamaların bunları gerçekleştirmenin daha verimli bir yolu olması muhtemelse, arayüz bu işlemler için yöntemler tanımlamalı ve bunlar için varsayılan uygulamaları sağlamalıdır. Varsayılan uygulamaların belirlenememesi, arabirimlerin bu tür yöntemleri atlamasına yönelik baskıya neden olmuş ve daha sonra bunları eklemelerini imkansız hale getirmiştir.
supercat

@BrianGoetz Varsayılan yöntemlerin lambdaların ötesinde önemli bir değeri olduğunu kabul ediyorum. Ancak, onları dahil etme kararını yönlendiren daha geniş değere verebileceğiniz herhangi bir referansla ilgileniyorum. Benim okumam lambdaların birincil nedenin olduğudur (bu yüzden cevabımda 'öncelikle' kelimesini kullandım).
sprinter

2
Belki bu belge yardımcı olacaktır: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . Bölüm 10 açıkça şunu söylüyor: "Varsayılan yöntemlerin amacı (daha önce sanal genişletme yöntemleri veya savunma yöntemleri olarak adlandırılıyordu), arabirimlerin ilk yayınlandıktan sonra uyumlu bir şekilde geliştirilmesini sağlamaktır." Lambda dostu yöntemler daha sonra arayüz evriminin bir örneği olarak gösteriliyor .
Brian Goetz

2
@Kartik Yanlış soru soruyorsunuz! Sözdizimini "derleyicinin programı doğru şekilde ayrıştırması için gereken mutlak minimum değerin ne olduğuna" dayalı olarak seçmiyoruz; bunu, "programcının amacını okuyucular için neyin daha açık hale getireceğini" temel alarak seçiyoruz. Önce kullanıcılar için, ikincisi derleyiciler için tasarlıyoruz (ve kullanıcılar söz konusu olduğunda, önce okuma için, sonra da yazmak için tasarlıyoruz.)
Brian Goetz

16

Java 8'de varsayılan yöntemler adı verilen yeni bir kavram tanıtıldı. Varsayılan yöntemler, bazı varsayılan uygulamaları olan ve mevcut kodu bozmadan arabirimlerin geliştirilmesine yardımcı olan yöntemlerdir. Bir örneğe bakalım:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

ve çıktı:


Arabirimdeki DoSomeOtherWork uygulamasında bazı İş uygulamalarını yapın


16

Diğer cevaplarda gözden kaçan bir şey, açıklamalardaki rolüydü. Java 1.5'e kadar, defaultanahtar kelime , bir açıklama alanı için varsayılan bir değer sağlamanın bir yolu olarak ortaya çıktı .

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Arayüzlerde varsayılan bir yöntem tanımlanmasına izin vermek için Java 8'in tanıtılmasıyla kullanımı aşırı yüklendi .

Gözden kaçan bir şey daha var: Beyanın default class MyClass {}geçersiz olmasının nedeni , sınıfların ilan edilme biçimidir . Dilde, o anahtar kelimenin orada görünmesine izin veren bir hüküm yoktur. Yine de arayüz yöntemi bildirimleri için görünmektedir .


3

Yeni Java 8 özelliği ( Varsayılan Yöntemler ), bir arabirimin defaultanahtar sözcükle etiketlendiğinde bir uygulama sağlamasına izin verir .

Örneğin:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Arabirim Testi, arabirimin, arabirimi kullanan sınıflarda bu yöntemlerin uygulanmasına gerek kalmadan yöntemin varsayılan bir uygulamasını sağlamasına izin veren varsayılan anahtar sözcüğünü kullanır.

Geriye dönük uyumluluk: Arayüzünüzün yüzlerce sınıf tarafından uygulandığını ve bu arayüzü değiştirmenin, arayüzünüzü uygulayan diğer birçok sınıf için gerekli olmasa da, tüm kullanıcıları yeni eklenen yöntemi uygulamaya zorlayacağını hayal edin.

Gerçekler ve Kısıtlamalar:

1-Yalnızca bir arabirim içinde bildirilebilir, bir sınıf veya soyut sınıf içinde değil.

2-Bir gövde sağlamalıdır

3-Bir arayüzde kullanılan diğer normal yöntemler gibi genel veya soyut olduğu varsayılmaz.


3

Bir arayüzdeki varsayılan yöntemler, eski kodu bozmadan yeni işlevler eklememize izin verir.

Java 8'den önce, bir arayüze yeni bir yöntem eklenmişse, bu arayüzün tüm uygulama sınıfları, yeni işlevselliği kullanmasalar bile bu yeni yöntemi geçersiz kılmak zorunda kalıyordu.

Java 8 ile, defaultyöntem uygulamasından önce anahtar kelimeyi kullanarak yeni yöntem için varsayılan uygulamayı ekleyebiliriz .

Anonim sınıflarda veya işlevsel arayüzlerde bile, bazı kodların yeniden kullanılabilir olduğunu görürsek ve kodun her yerinde aynı mantığı tanımlamak istemiyorsak, bunların varsayılan uygulamalarını yazabilir ve yeniden kullanabiliriz.

Misal

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

2

Java ™ Öğreticilerinde çok iyi bir açıklama bulunur , açıklamanın bir kısmı aşağıdaki gibidir:

Otomobillerini çalıştırmak için hangi yöntemlerin kullanılabileceğini açıklayan endüstri standardı arayüzler yayınlayan bilgisayar kontrollü otomobil üreticilerini içeren bir örnek düşünün. Ya bu bilgisayar kontrollü araba üreticileri arabalarına uçuş gibi yeni işlevler eklerse? Bu üreticilerin, diğer şirketlerin (elektronik kılavuz araç üreticileri gibi) yazılımlarını uçan arabalara uyarlamasını sağlamak için yeni yöntemler belirlemesi gerekecektir. Bu otomobil üreticileri uçuşla ilgili bu yeni yöntemleri nerede ilan edecekler? Bunları orijinal arabirimlerine eklerlerse, bu arabirimleri uygulayan programcıların uygulamalarını yeniden yazmaları gerekir. Bunları statik yöntemler olarak eklerlerse, programcılar bunları temel yöntemler olarak değil, yardımcı yöntemler olarak görürler.

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


1

Varsayılan yöntemler, uygulamalarınızın arayüzlerine yeni işlevler eklemenizi sağlar. Çoklu mirasa sahip olmak için de kullanılabilir . Varsayılan yöntemlere ek olarak, arayüzlerde statik yöntemler tanımlayabilirsiniz. Bu, yardımcı yöntemleri düzenlemenizi kolaylaştırır

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.