Soyut bir sınıf başlatabilir miyiz?


573

Röportajımdan birinde, "Soyut bir sınıfı başlatabilir miyiz?"

Cevabım "Hayır. Yapamayız" idi. Ama görüşmeci bana "Yanlış, yapabiliriz" dedi.

Bu konuda biraz tartıştım. Sonra bunu evde kendim denememi söyledi.

abstract class my {
    public void mymethod() {
        System.out.print("Abstract");
    }
}

class poly {
    public static void main(String a[]) {
        my m = new my() {};
        m.mymethod();
    }
}

Burada, sınıfımın bir örneğini ve soyut sınıf çağırma yöntemini oluşturuyorum. Birisi bana bunu açıklayabilir mi? Röportajım sırasında gerçekten yanlış mıydım?


2
Sadece biraz ilgili olsa da, bir belki C ++ soyut sınıf örneğini edebilirsiniz: olmayan bir soyut sınıf türetmek eğer Bsoyut bir birinden A, inşaat bölümü sırasında bir Bçalışan oluşurlar: Örneğin, A'ın yapıcı, nesnenin zamanı tür aslında A. Ancak sadece geçici.
Vlad

8
@jWeavers: Verdiği örnek tamamen yanlış. Ondan "o zaman soyut sınıfın ne işe yaradığını" sormalıydın. Genişletiyorsanız, neden genişletilmiş sınıfın bir örneğini oluşturuyorsunuz? Hiçbir veri ile sonuçlanan tamamen yeni bir nesnedir ..
Lemon Juice

3
Veya görüşmeci, önerisine karşı ifadeniz hakkında ne kadar emin olduğunuzu kontrol etmek isteyebilir!
Sid

5
Sana yalan söyledi. Bu kodun ne yaptığını ve anonim alt sınıfların ne olduğunu açıklamak için başarısız olduğunuzda topu düşürdünüz. Muhtemelen zaten biliyordu ve bilip bilmediğinizi görmek istiyordu.
candied_orange

2
Bu bir sınav değil, bir iş görüşmesi değil mi? Peki ya Java ya da C ++ soyut sınıfların somutlaştırılmasına izin veriyorsa? Bunu yapmazsınız, çünkü bunu yapmak akıllıca bir şey değil. Objective-C'de soyut sınıflar sadece konvansiyonla soyuttur ve onları örneklemek bir hatadır.
gnasher729

Yanıtlar:


722

Burada, sınıfımın bir örneğini oluşturuyorum

Hayır, burada soyut sınıfınızın örneğini oluşturmuyorsunuz. Bunun yerine , soyut sınıfınızın anonim bir alt sınıfının bir örneğini oluşturuyorsunuz . Ve sonra soyut sınıf referansınızda şu yöntemi gösteren yöntemi çağırıyorsunuz: alt sınıf nesnesini .

Bu davranış, JLS - Bölüm # 15.9.1'de açıkça listelenmiştir : -

Sınıf örneği oluşturma ifadesi bir sınıf gövdesinde sona ererse, somutlaştırılan sınıf anonim bir sınıftır. Sonra:

  • T bir sınıfı belirtirse, T adlı sınıfın anonim doğrudan alt sınıfı bildirilir. T ile belirtilen sınıf son sınıfsa, derleme zamanı hatasıdır.
  • T bir arabirimi belirtirse, T adlı arabirimi uygulayan nesnenin anonim bir doğrudan alt sınıfı bildirilir.
  • Her iki durumda da, alt sınıfın gövdesi, sınıf örneği oluşturma ifadesinde verilen ClassBody öğesidir.
  • Gerçekleştirilen sınıf, anonim alt sınıftır.

Vurgu madeni.

Ayrıca, JLS - Bölüm # 12.5'te , Nesne Oluşturma Süreci hakkında bilgi edinebilirsiniz . Buradan bir ifade alıntılayacağım: -

Yeni bir sınıf örneği oluşturulduğunda, sınıf türünde bildirilen tüm örnek değişkenleri ve gizlenebilecek tüm örnek değişkenleri de dahil olmak üzere, sınıf türünün her üst sınıfında bildirilen tüm örnek değişkenleri için yer için bellek alanı ayrılır.

Sonuç olarak yeni oluşturulan nesneye yapılan bir başvuru döndürülmeden hemen önce, belirtilen kurucu aşağıdaki nesneyi kullanarak yeni nesneyi başlatmak üzere işlenir:

Tüm prosedürü sağladığım bağlantıdan okuyabilirsiniz.


Gerçekleştirilen sınıfın Anonim bir Alt Sınıf olduğunu pratik olarak görmek için her iki sınıfınızı da derlemeniz gerekir. Bu sınıfları iki farklı dosyaya koyduğunuzu varsayalım:

My.java:

abstract class My {
    public void myMethod() {
        System.out.print("Abstract");
    }
}

Poly.java:

class Poly extends My {
    public static void main(String a[]) {
        My m = new My() {};
        m.myMethod();
    }
}

Şimdi, her iki kaynak dosyanızı da derleyin:

javac My.java Poly.java

Şimdi kaynak kodu derlediğiniz dizinde aşağıdaki sınıf dosyalarını göreceksiniz:

My.class
Poly$1.class  // Class file corresponding to anonymous subclass
Poly.class

Şu sınıfa bakın - Poly$1.class. Aşağıdaki kodu kullanarak oluşturduğunuz anonim alt sınıfa karşılık gelen derleyici tarafından oluşturulan sınıf dosyasıdır:

new My() {};

Dolayısıyla, farklı bir sınıfın somutlaştırıldığı açıktır. Sadece bu derleme sadece derleyici tarafından derlendikten sonra bir isim verilir.

Genel olarak, sınıfınızdaki tüm anonim alt sınıflar şu şekilde adlandırılacaktır:

Poly$1.class, Poly$2.class, Poly$3.class, ... so on

Bu sayılar, bu anonim sınıfların çevreleyen sınıfta göründüğü sırayı belirtir.


172
@coders. Kesin cevap: - Soyut sınıfınızı örnekleyemezsiniz, ancak soyut sınıfınızın somut bir alt sınıfını örnekleyebilirsiniz.
Rohit Jain

16
Bir satırda şunları söyleyebilirsiniz: - Soyut bir sınıfı asla başlatamazsınız. Soyut bir sınıfın amacı budur.
Rahul Tripathi

66
Görüşme yapan kişinin cevabına sizinkinden daha fazla yatırım yapıldığı anlaşılıyor ...
Neil T.

7
Başka bir yoruma göre ( JLS referansı ile ), "Bir nesnenin kendi sınıfının ve sınıfının tüm üst sınıflarının bir örneği olduğu söylenir" - bu nedenle, burada teknik olarak soyut sınıfın bir örneğini yaratmıyor muyuz? yani soyut sınıfı somutlaştırmak?
arshajii

6
@ARS instance ofve ile olmak arasında bir fark olduğunu söyleyebilirim instantiating. Yalnızca bir sınıfı başlatırken, oluşturduğunuz nesne miras nedeniyle birden çok sınıfın örneği olabilir.
Simon Forsberg

89

Yukarıda anonim bir iç sınıf, my soyut sınıfın . Soyut sınıfın kendisini somutlaştırmakla kesinlikle eşdeğer değildir. OTOH, her alt sınıf örneği tüm süper sınıflarının ve arabirimlerinin bir örneğidir, bu nedenle soyut sınıfların çoğu gerçekten somut alt sınıflarından birini örnekleyerek somutlaştırılır.

Eğer görüşmeci "yanlış!" Bu örneği açıklamadan ve benzersiz bir karşı örnek olarak vermeden, bence neden bahsettiğini bilmiyor.


10
Açıkçası , soyut süper sınıf somutlaştırılmaz. Yapıcısı, örnek değişkenlerini başlatmak için çağrılır.
Algılama

4
Evet öyle: subclassInstance instanceof SuperClasstrue değerini döndürür, bu yüzden nesne üst sınıfın bir örneğidir, yani üst sınıf örneklenmiş demektir. Ama bu sadece anlamsal nitpick.
JB Nizet

5
Gerçekten semantik olabilir. Java, somutlamayı yeni anahtar kelime (hangi bir soyut sınıfla yapamayacağınız) aracılığıyla nesne oluşturma açısından tanımlar . Ancak elbette somut alt sınıf, onun ana hiyerarşisinin her üyesinin bir örneği olduğunu doğru bir şekilde rapor edecektir.
Algılama

11
JLS'nin 4.12.6. paragrafı şöyle der: "Bir nesnenin kendi sınıfının ve sınıfının tüm üst sınıflarının bir örneği olduğu söylenir."
JB Nizet

85

= my() {};anonim bir uygulama olduğu anlamına gelir, bir nesnenin basit bir somutlaştırması değil = my(); Soyut bir sınıfı asla başlatamazsınız.


30

Sadece yapabileceğiniz gözlemler:

  1. Neden polyuzanıyor my? Bu işe yaramaz ...
  2. Derlemenin sonucu nedir? Üç dosyaları: my.class,poly.class vepoly$1.class
  3. Eğer böyle bir soyut sınıfı başlatabilirsek, bir arayüz de başlatabiliriz ... tuhaf ...


Soyut bir sınıf başlatabilir miyiz?

Hayır, yapamayız. Yapabileceğimiz şey, anonim bir sınıf oluşturmak (üçüncü dosya) ve örneği başlatmak.


Süper sınıf örneklemeye ne dersiniz?

Soyut süper sınıf tarafımızdan değil, java tarafından somutlaştırılmıştır .

EDIT: Bunu test etmesini isteyin

public static final void main(final String[] args) {
    final my m1 = new my() {
    };
    final my m2 = new my() {
    };
    System.out.println(m1 == m2);

    System.out.println(m1.getClass().toString());
    System.out.println(m2.getClass().toString());

}

çıktı:

false
class my$1
class my$2

Gözlem 3 1: örneğin, yapabileceğimiz Serializable s = new Serializable() {};(oldukça yararsız olan) ve etiketli eğer kod verecekti üzerine class my$3(ya da her türlü sınıf ve numara kapatan)
eski durumuna Monica - notmaynard

18

Sadece tek bir satırda cevaplar verebilirsiniz

Hayır , Soyut Sınıf'ı asla örnekleyemezsiniz

Ancak görüşmeci hala aynı fikirde değil, ona söyleyebilirsin

tüm yapabileceğiniz bir Anonim Sınıf oluşturabilirsiniz.

Ve anonim sınıfa göre, sınıf aynı yerde / hatta ilan edildi ve somutlaştırıldı

Dolayısıyla, görüşmeci güven seviyenizi ve OOP'lar hakkında ne kadar bilginiz olduğunu kontrol etmek isteyebilir.


17

Teknik kısım diğer cevaplarda iyi ele alınmış ve esas olarak şu şekilde bitiyor:
"O yanlış, bir şey bilmiyor, ondan SO'ya katılmasını isteyin ve hepsini temizle :)"

Bunun bir stres sorusu olabileceği ve diğer birçok görüşmecinin sizin hakkınızda daha fazla bilgi sahibi olması ve zor ve olağandışı durumlara nasıl tepki verdiğiniz konusunda önemli bir araç olduğu gerçeğine değinmek istiyorum . Sana yanlış kodlar vererek muhtemelen geri dönüp dönmediğini görmek istedi. Buna benzer durumlarda yaşlılarınıza karşı ayağa kalkmaya güvenip güvenmediğinizi bilmek.

Not: Nedenini bilmiyorum ama görüşmecinin bu yazıyı okuduğunu hissediyorum.


13

Soyut sınıflar somutlaştırılamaz, ancak alt sınıflara ayrılabilirler. Bu Bağlantıya Bakın

En iyi örnek

Calender sınıfının getInstance () soyut bir yöntemi olmasına rağmen ,Calendar calc=Calendar.getInstance();

calc, "GregorianCalendar Takvimi genişletir" olarak sınıf GregorianCalendar sınıf örneğine başvuruyor "

Infact anonim iç tip , soyut sınıfın isimsiz bir alt sınıfı ve bunun bir örneğini oluşturmanıza izin verir .


11

Teknik Cevap

Soyut sınıflar örneklenemez - bu tanım ve tasarım gereğidir.

JLS, Bölüm 8. Sınıflar:

İsimlendirilmiş bir sınıf özet (§8.1.1.1) olarak ilan edilebilir ve eksik uygulandığında soyut olarak bildirilmelidir; böyle bir sınıf somutlaştırılamaz, ancak alt sınıflar tarafından genişletilebilir.

Classes.newInstance () için JSE 6 java doc'den:

InstantiationException - bu Sınıf bir soyut sınıfı, bir arabirimi, bir dizi sınıfını, ilkel bir türü veya void'i temsil ediyorsa; veya sınıfta herhangi bir sıfır yapıcısı yoksa; veya somutlaştırma başka bir nedenden dolayı başarısız olursa.

Elbette, soyut bir sınıfın somut bir alt sınıfını (anonim bir alt sınıf dahil) başlatabilir ve aynı zamanda bir soyut türe yönelik bir nesne referansının bir tür tahminini gerçekleştirebilirsiniz.

Bu Konuda Farklı Bir Açı - Takım Oyunu ve Sosyal İstihbarat:

Bu tür bir teknik yanlış anlama, karmaşık teknolojiler ve yasal özellikler ile uğraştığımızda gerçek dünyada sık sık meydana gelir.

"İnsan Becerileri" burada "Teknik Beceriler" den daha önemli olabilir. Rekabetçi ve agresif bir şekilde argüman tarafınızı kanıtlamaya çalışıyorsa, teorik olarak doğru olabilirsiniz, ancak savaşmak / zarar vermek "yüzüne" / düşman oluşturmaya değdiğinden daha fazla hasar verebilirsiniz. Farklılıklarınızı çözmede uzlaşmacı ve anlayışlı olun. Kim bilir - belki "her ikisi de haklısın" ama terimler için biraz farklı anlamlar üzerinde çalışıyorsun ??

Kim bilir - büyük olasılıkla olmasa da, görüşmeci sizi zorlu bir duruma sokmak ve duygusal ve sosyal olarak nasıl davrandığınızı görmek için kasıtlı olarak küçük bir çatışma / yanlış anlama başlatmıştır. İş arkadaşlarınızla zarif ve yapıcı olun, yaşlıların tavsiyelerini takip edin ve herhangi bir zorluğu / yanlış anlaşılmayı çözmek için e-posta veya telefon görüşmesi yoluyla görüşme sonrasında takip edin. Motive ve detay odaklı olduğunuzu gösterir.


7

Bu köklü bir gerçektir ki abstract classcan değil herkes cevap olarak başlatılamaz.

Program anonim sınıfı tanımladığında, derleyici aslında farklı adla yeni bir sınıf oluşturur ( anonim sınıf numarasının EnclosedClassName$nbulunduğu desene sahiptir n)

Bu Java sınıfını kodalıyorsanız kodu aşağıdaki gibi bulacaksınız:

sınıfım

abstract class my { 
    public void mymethod() 
    { 
        System.out.print("Abstract"); 
    }
} 

poly $ 1.class ("anonim sınıf" ın oluşturulan sınıfı)

class poly$1 extends my 
{
} 

ploly.cass

public class poly extends my
{
    public static void main(String[] a)
    {
        my m = new poly.1(); // instance of poly.1 class NOT the abstract my class

        m.mymethod();
    }
}

4

Hayır, soyut bir sınıfa anında ulaşamazsınız. Biz sadece anonim sınıfı başlatırız. Soyut sınıfta soyut yöntemleri beyan ederiz ve sadece somut yöntemleri belirleriz


4

Soyut Sınıflar Hakkında

  • Soyut bir sınıfın nesnesi oluşturulamıyor
  • Değişkenler oluşturabilir (veri türleri gibi davranabilir)
  • Bir çocuk ebeveynin en az bir soyut yöntemini geçersiz kılamazsa, çocuk da soyut olur
  • Soyut sınıflar çocuk sınıfları olmadan işe yaramaz

Soyut bir sınıfın amacı bir üs gibi davranmaktır. Miras hiyerarşisinde yukarı doğru soyut sınıflar göreceksiniz.


3


Şunu söyleyebilirsiniz: soyut bir sınıfı başlatamayız, ancak newanonim sınıf örneği oluşturmak için anahtar kelimeyi {}soyut sınıfın sonuna yalnızca uygulama gövdesi olarak ekleyerek kullanabiliriz .


3

Bir sınıfı genişletmek, sınıfı somutlaştırdığınız anlamına gelmez. Aslında, sizin durumunuzda alt sınıfın bir örneğini oluşturuyorsunuz.

Soyut sınıfların başlatılmasına izin vermediğinden eminim. Yani, hayır derdim: soyut bir sınıfı başlatamazsınız. Ancak, genişletebilir / devralın.

Soyut bir sınıfı doğrudan başlatamazsınız. Ancak dolaylı olarak sınıf örneğini (aslında orijinal soyut sınıfın örneğini değil) alamayacağınız anlamına gelmez. Yani soyut soyut sınıfı başlatamazsınız, ancak şunları yapabilirsiniz:

  1. Boş bir sınıf oluştur
  2. Soyut sınıftan miras alın
  3. Dervied sınıfını örnekleme

Böylece türetilmiş sınıf örneği aracılığıyla soyut bir sınıftaki tüm yöntemlere ve özelliklere erişebilirsiniz.


2

Soyut bir sınıfı başlatmak imkansızdır. Gerçekten yapabileceğiniz şey, soyut bir sınıfta bazı ortak yöntemler uygulamak ve diğerlerinin uygulanmamasına izin vermek (onları soyut olarak beyan etmek) ve somut inişçinin ihtiyaçlarına göre bunları uygulamasına izin vermektir. Sonra bu soyut sınıfın bir örneğini (aslında uygulayıcısı) döndüren bir fabrika yapabilirsiniz. Daha sonra hangi uygulayıcıyı seçeceğinize fabrikada karar verirsiniz. Bu fabrika tasarım deseni olarak bilinir:

   public abstract class AbstractGridManager {
        private LifecicleAlgorithmIntrface lifecicleAlgorithm;
        // ... more private fields

        //Method implemented in concrete Manager implementors 
        abstract public Grid initGrid();

        //Methods common to all implementors
        public Grid calculateNextLifecicle(Grid grid){
            return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
        }

        public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
            return lifecicleAlgorithm;
        }
        public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
            this.lifecicleAlgorithm = lifecicleAlgorithm;
        }
        // ... more common logic and getters-setters pairs
    }

Somut uygulayıcının yalnızca soyut olarak bildirilen yöntemleri uygulaması gerekir, ancak soyut olarak sınıflandırılmamış soyut bir sınıftaki bu sınıflarda uygulanan mantığa erişimi olacaktır:

public class FileInputGridManager extends AbstractGridManager {

private String filePath;

//Method implemented in concrete Manager implementors 
abstract public Grid initGrid();

public class FileInputGridManager extends AbstractGridManager {

    private String filePath;

    //Method implemented in concrete Manager implementors 
    abstract public Grid initGrid();

    public Grid initGrid(String filePath) {
        List<Cell> cells = new ArrayList<>();
        char[] chars;
        File file = new File(filePath); // for example foo.txt
        // ... more logic
        return grid;
    }
}

Sonunda fabrika şöyle görünür:

public class GridManagerFactory {
    public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
        AbstractGridManager manager = null;

        // input from the command line
        if(args.length == 2){
            CommandLineGridManager clManager = new CommandLineGridManager();
            clManager.setWidth(Integer.parseInt(args[0]));
            clManager.setHeight(Integer.parseInt(args[1]));
            // possibly more configuration logic
            ...
            manager = clManager;
        } 
        // input from the file
        else if(args.length == 1){
            FileInputGridManager fiManager = new FileInputGridManager();
            fiManager.setFilePath(args[0]);
            // possibly more method calls from abstract class
            ...
            manager = fiManager ;
        }
        //... more possible concrete implementors
        else{
            manager = new CommandLineGridManager();
        }
        manager.setLifecicleAlgorithm(lifecicleAlgorithm);
        return manager;
    }
}

AbstractGridManager alıcısı, onun üzerindeki yöntemleri çağırır ve sahip olduğu somut uygulamanın ne olduğunu bilmeden, beton inişinde (ve kısmen soyut sınıf yöntemlerinde) uygulanan mantığı alır. Bu aynı zamanda kontrol veya bağımlılık enjeksiyonunun ters çevrilmesi olarak da bilinir.


2

Hayır, soyut sınıfın nesnesini yaratamayız, ama soyut sınıfın referans değişkenini yaratırız. Referans değişken, türetilmiş sınıfların nesnelerini ifade etmek için kullanılır (Abstract sınıfının alt sınıfları)

İşte bu konsepti gösteren örnek

abstract class Figure { 

    double dim1; 

    double dim2; 

    Figure(double a, double b) { 

        dim1 = a; 

        dim2 = b; 

    } 

    // area is now an abstract method 

    abstract double area(); 

    }


    class Rectangle extends Figure { 
        Rectangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for rectangle 
    double area() { 
        System.out.println("Inside Area for Rectangle."); 
        return dim1 * dim2; 
    } 
}

class Triangle extends Figure { 
    Triangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for right triangle 
    double area() { 
        System.out.println("Inside Area for Triangle."); 
        return dim1 * dim2 / 2; 
    } 
}

class AbstractAreas { 
    public static void main(String args[]) { 
        // Figure f = new Figure(10, 10); // illegal now 
        Rectangle r = new Rectangle(9, 5); 
        Triangle t = new Triangle(10, 8); 
        Figure figref; // this is OK, no object is created 
        figref = r; 
        System.out.println("Area is " + figref.area()); 
        figref = t; 
        System.out.println("Area is " + figref.area()); 
    } 
}

Burada Şekil türünde bir nesne oluşturamayacağımızı görüyoruz, ancak Şekil türünde bir referans değişkeni oluşturabiliyoruz. Burada, Şekil Dikkeni türünde bir referans değişkeni oluşturduk ve Sınıf Dikdörtgeni ve Üçgeni nesnelerine başvurmak için Sınıf referans değişkeni kullanılır.


0

Aslında doğrudan soyut bir sınıfın nesnesini yaratamayız. Yarattığımız şey soyut bir çağrının referans değişkeni. Referans değişkeni, Abstract sınıfını miras alan sınıfın nesnesine, yani soyut sınıfın alt sınıfına başvurmak için kullanılı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.