抽象クラスをインスタンス化できますか?


573

あるインタビューで、「抽象クラスをインスタンス化できるかどうか」と尋ねられました。

私の返事は「いいえ、できません」でした。しかし、面接官は私に「間違った、私たちはできる」と言った。

私はこれについて少し議論しました。それから彼は私にこれを自分で家で試すように言った。

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

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

ここでは、クラスのインスタンスを作成し、抽象クラスのメソッドを呼び出しています。誰か私にこれを説明してもらえますか?面接中に私は本当に間違っていましたか?


2
わずかに関連していますが、おそらくC ++で抽象クラスをインスタンス化できます。インスタンスの構築一部である、実行中のコンストラクタで構成される抽象クラスBから非抽象クラスを派生させる場合、オブジェクトの実行時の型は実際にはです。ただし、一時的なものです。ABAA
Vlad

8
@jWeavers:彼が与えた例は完全に間違っています。あなたは彼に「それでは抽象クラスの使い方は何ですか」と尋ねるべきだった。それを拡張する場合、拡張クラスのインスタンスを作成するのはなぜですか?それはあなたがいないデータで終わる完全に新しいオブジェクト、..です
レモンジュース

3
または、面接担当者が、彼の提案に対して自分の発言について自信を持っているかどうかを確認したいと考えているかもしれません。
シド

5
彼はあなたに嘘をついた。これは、このコードが行うことではなく、匿名サブクラスが何であるかを説明するのに失敗したときに、ボールを落としました。彼はおそらくそれをすでに知っていて、あなたが知っているかどうかを見たかったのでしょう。
candied_orange 2015

2
これはクイズ番組ではなく、就職の面接でしたね。では、JavaまたはC ++が抽象クラスのインスタンス化を許可している場合はどうでしょうか?それは賢いことではないので、あなたはそれをしないでしょう。Objective-Cでは、抽象クラスは慣例によってのみ抽象であり、それらをインスタンス化することはバグです。
gnasher729 2015

回答:


722

ここでは、クラスのインスタンスを作成しています

いいえ、ここでは抽象クラスのインスタンスを作成していません。むしろ、抽象クラスの無名サブクラスのインスタンスを作成しています。そして、サブクラスオブジェクトを指す抽象クラス参照でメソッドを呼び出しています

この動作はJLSに明確にリストされています-セクション#15.9.1:-

クラスインスタンス作成式がクラス本体で終了する場合、インスタンス化されるクラスは匿名クラスです。次に:

  • Tがクラスを表す場合、Tによって指定されたクラスの匿名の直接サブクラスが宣言されます。Tで示されるクラスが最終クラスである場合は、コンパイル時エラーです。
  • Tがインターフェースを表す場合、Tによって指定されたインターフェースを実装するObjectの匿名の直接サブクラスが宣言されます。
  • どちらの場合でも、サブクラスの本体は、クラスインスタンス作成式で指定されたClassBodyです。
  • インスタンス化されるクラスは、無名のサブクラスです。

強調鉱山。

また、JLS-セクション#12.5では、オブジェクト作成プロセスについて読むことができます。。その中の1つのステートメントをここで引用します。-

新しいクラスインスタンスが作成されるたびに、クラス型で宣言されたすべてのインスタンス変数と、クラス型の各スーパークラスで宣言されたすべてのインスタンス変数(非表示になっている可能性があるすべてのインスタンス変数を含む)のためのスペースがメモリ空間に割り当てられます。

新しく作成されたオブジェクトへの参照が結果として返される直前に、次の手順を使用して、示されたコンストラクターが処理され、新しいオブジェクトが初期化されます。

私が提供したリンクで完全な手順について読むことができます。


インスタンス化されているクラスがAnonymous SubClassであることを実際に確認するには、両方のクラスをコンパイルするだけです。これらのクラスを2つの異なるファイルに配置するとします。

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();
    }
}

次に、両方のソースファイルをコンパイルします。

javac My.java Poly.java

ソースコードをコンパイルしたディレクトリに、次のクラスファイルが表示されます。

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

そのクラスを参照してください- Poly$1.class。これは、以下のコードを使用してインスタンス化した無名サブクラスに対応するコンパイラーによって作成されたクラスファイルです。

new My() {};

したがって、インスタンス化されている別のクラスがあることは明らかです。それだけです。そのクラスには、コンパイラーによるコンパイル後にのみ名前が付けられます。

一般に、クラス内のすべての匿名サブクラスには、次のように名前が付けられます。

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

これらの番号は、それらの匿名クラスが外側のクラスに現れる順序を示します。


172
@coders。正確な答えは次のとおりです。-抽象クラスをインスタンス化することはできませんが、抽象クラスの具象サブクラスをインスタンス化することはできます。
Rohit Jain

16
1行で次のように言うことができます。-抽象クラスをインスタンス化することはできません。それが抽象クラスの目的です。
Rahul Tripathi

66
インタビュアーがあなたの答えよりも彼の答えにより多く投資されたようです...
Neil T.

7
別のコメントJLS参照を使用)によると、「オブジェクトはそのクラスのインスタンスおよびそのクラスのすべてのスーパークラスのインスタンスであると言われています」-したがって、実際に技術的に抽象クラスのインスタンスをここで作成していませんか?つまり、抽象クラスをインスタンス化しますか?
arshajii

6
私がいる間に違いがあることを言うだろう@ARS instance ofとはinstantiating。作成するオブジェクトは継承により複数のクラスのインスタンスになる可能性がありますが、インスタンス化するクラスは1つだけです。
Simon Forsberg

89

上記は、my抽象クラスのサブクラスである匿名の内部クラスをインスタンス化します。これは、抽象クラス自体をインスタンス化することと厳密には同等ではありません。OTOH、すべてのサブクラスインスタンスは、そのすべてのスーパークラスとインターフェイスのインスタンスです。そのため、ほとんどの抽象クラスは、具体的なサブクラスの1つをインスタンス化することによって実際にインスタンス化されます。

インタビュアーが「間違った!」説明せずに、この例をユニークな反例として示しましたが、彼は自分が何を話しているのかわからないと思います。


10
厳密に言えば、抽象スーパークラスはインスタンス化されません。そのコンストラクタは、インスタンス変数を初期化するために呼び出されます。
知覚

4
はいsubclassInstance instanceof SuperClass、そうです。trueを返すため、オブジェクトはスーパークラスのインスタンスです。つまり、スーパークラスはインスタンス化されています。しかし、それは単なる意味論的なつまらないことです。
JB Nizet

5
確かにセマンティクスかもしれません。Javaは、新しいキーワードを使用してオブジェクトを作成することでインスタンス化を定義します(抽象クラ​​スではできません)。しかしもちろん、具象サブクラスは、その親階層のすべてのメンバーのインスタンスであることを正しく報告します。
知覚

11
JLSの4.12.6項は、「オブジェクトは、そのクラスのインスタンスおよびそのクラスのすべてのスーパークラスのインスタンスであると言われています。」と述べています。
JB Nizet

85

= my() {};オブジェクトの単純なインスタンス化ではなく、匿名の実装があることを意味します= my()。抽象クラスをインスタンス化することはできません。


30

あなたができる観察だけ:

  1. なぜpoly拡張するのmyですか?これは役に立たない...
  2. コンパイルの結果は何ですか?3つのファイル:my.classpoly.classおよびpoly$1.class
  3. そのような抽象クラスをインスタンス化できれば、インターフェースもインスタンス化できます...奇妙です...


抽象クラスをインスタンス化できますか?

いいえ、できません。私たちにできることは、匿名クラス(3番目のファイル)を作成してインスタンス化することです。


スーパークラスのインスタンス化はどうですか?

抽象スーパークラスは、私たちではなく、Javaによってインスタンス化されます。

編集:これをテストするように彼に依頼してください

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());

}

出力は次のとおりです。

false
class my$1
class my$2

観察3のための1:例えば、我々は行うことができますSerializable s = new Serializable() {};(かなり無用である)と、あなたのコードにタグ付けされた場合は与えるだろうclass my$3(または何囲むクラスと番号)
復活モニカ- notmaynard

18

たった1行で答えることができます

いいえ、抽象クラスをインスタンス化することはできません

しかし、インタビュアーはまだ同意していないので、あなたは彼/彼女に言うことができます

できることは、匿名クラスを作成することだけです。

そして、匿名クラスによると、クラスは同じ場所/行で宣言およびインスタンス化されます

そのため、インタビュアーが信頼水準とOOPについてどれだけ知っているかを確認することに関心を持つ可能性があります。


17

技術的な部分は他の回答で十分にカバーされており、主に次のように終わります

これはストレス質問であり、多くの面接担当者があなたについて、そして困難で異常な状況にどのように反応するかを知るための重要なツールであるという事実(他の回答で言及されています)に触れたいと思います。間違ったコードを与えることにより、彼はおそらくあなたが議論したかどうかを確認したかったのでしょう。これに似た状況で、先輩に立ち向かう自信があるかどうかを知ること。

PS:理由はわかりませんが、インタビュアーがこの投稿を読んだと感じています。


13

抽象クラスはインスタンス化できませんが、サブクラス化できます。 このリンクを見る

最良の例は

カレンダークラス)(抽象メソッドのgetInstanceを持っていますが、あなたが言うとき、Calendar calc=Calendar.getInstance();

calcは、クラスGregorianCalendarのクラスインスタンスを「GregorianCalendar extends Calendarとして参照しています

InfactはAnnonymousのインナータイプは、 あなたが抽象クラスのノーブランドのサブクラスを作成することを可能にし、このインスタンスを。


11

技術的な回答

抽象クラスはインスタンス化できません-これは定義と設計によるものです。

JLSの第8章から。クラス:

名前付きクラスは、abstract(§8.1.1.1)と宣言することができ、実装が不完全な場合は、abstractと宣言する必要があります。このようなクラスはインスタンス化できませんが、サブクラスによって拡張できます。

Classes.newInstance()のJSE 6 java docから:

InstantiationException-このClassが抽象クラス、インターフェース、配列クラス、プリミティブ型、またはvoidを表す場合。または、クラスにnullコンストラクタがない場合。または、インスタンス化が他の何らかの理由で失敗した場合。

もちろん、抽象クラス(無名サブクラスを含む)の具象サブクラスをインスタンス化し、抽象型へのオブジェクト参照の型キャストを実行することもできます。

これについての別の角度-チームプレイとソーシャルインテリジェンス:

この種の技術的な誤解は、複雑なテクノロジーや法的仕様を扱うときに現実の世界で頻繁に発生します。

ここでは、「技術スキル」よりも「人材スキル」の方が重要です。競争的にそして積極的にあなたの主張の側面を証明しようとするなら、あなたは理論的には正しいかもしれませんが、戦いをする/「顔」にダメージを与える/敵を作成することで、それよりも多くのダメージを与える可能性もあります。違いを解決するには、和解し、理解してください。誰が知っている-多分あなたは「どちらも正しい」が、用語のわずかに異なる意味に取り組んでいますか?

誰が知っているか-可能性は低いですが、面接担当者が意図的に小さな衝突/誤解を招いて、困難な状況に陥り、感情的および社会的にどのように振る舞うかを確認することは可能です。同僚に親切で建設的になり、先輩からのアドバイスに従い、面接後にメールや電話で問題や誤解を解決します。あなたがやる気と細部指向であることを示しています。


7

それはabstract classできない確立された事実です誰もが答えるようにインスタンス化。

プログラムが匿名クラスを定義すると、コンパイラーは実際に異なる名前で新しいクラスを作成します(パターンEnclosedClassName$nn匿名クラスの数である)を

したがって、このJavaクラスを逆コンパイルすると、次のようなコードが見つかります。

私のクラス

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

poly $ 1.class(「匿名クラス」の生成されたクラス)

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

いいえ、抽象クラスをインスタンス化することはできません。匿名クラスのみをインスタンス化します。抽象クラスでは、抽象メソッドを宣言し、具象メソッドのみを定義します。


4

抽象クラスについて

  • 抽象クラスのオブジェクトを作成できません
  • 変数を作成できる(データ型のように動作できる)
  • 子が親の少なくとも1つの抽象メソッドをオーバーライドできない場合、子も抽象になります
  • 抽象クラスは子クラスなしでは役に立たない

抽象クラスの目的は、ベースのように動作することです。継承階層では、上位に向かって抽象クラスが表示されます。


3

言うことができます:
抽象クラスをインスタンス化することはできませんが、newキーワードを使用{}して、抽象クラスの最後に実装本体として追加するだけで、匿名クラスインスタンスを作成できます。


3

クラスを拡張しても、クラスをインスタンス化しているわけではありません。実際、あなたのケースでは、サブクラスのインスタンスを作成しています。

抽象クラスは開始を許可しないと私はかなり確信しています。したがって、私はノーと言います。抽象クラスをインスタンス化することはできません。しかし、あなたはそれを拡張/継承することができます。

抽象クラスを直接インスタンス化することはできません。ただし、クラスのインスタンス(元の抽象クラスのインスタンスではない)を間接的に取得できないという意味ではありません。つまり、元の抽象クラスをインスタンス化することはできませんが、次のことはできます。

  1. 空のクラスを作成する
  2. 抽象クラスから継承する
  3. 派生クラスをインスタンス化する

したがって、派生クラスインスタンスを介して、抽象クラスのすべてのメソッドとプロパティにアクセスできます。


2

抽象クラスをインスタンス化することは不可能です。あなたが本当にできることは、いくつかの一般的なメソッドを抽象クラスに実装し、他のメソッドを実装せずに(それらを抽象として宣言)、具体的な子孫にそれらのニーズに応じてそれらを実装させます。次に、この抽象クラス(実際にはその実装者)のインスタンスを返すファクトリを作成できます。次に、ファクトリで、どの実装者を選択するかを決定します。これは、ファクトリデザインパターンと呼ばれます。

   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
    }

具象実装者は、abstractとして宣言されたメソッドを実装する必要があるだけですが、abstractとして宣言されていない、abstractクラスのそれらのクラスに実装されたロジックにアクセスできます。

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;
    }
}

最後に、ファクトリは次のようになります。

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のレシーバーは、メソッドを呼び出して、具体的な実装が何であるかを知らなくても、具体的な子孫(および部分的に抽象クラスメソッド)に実装されたロジックを取得します。これは、制御の反転または依存性注入とも呼ばれます。


2

いいえ、抽象クラスのオブジェクトは作成できませんが、抽象クラスの参照変数を作成します。参照変数は、派生クラス(抽象クラ​​スのサブクラス)のオブジェクトを参照するために使用されます

この概念を説明する例を次に示します

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()); 
    } 
}

ここでは、Figure型のオブジェクトは作成できませんが、Figure型の参照変数は作成できます。ここでは、Figure型の参照変数を作成し、Figureクラス参照変数を使用して、クラスRectangleおよびTriangleのオブジェクトを参照しています。


0

実際には、抽象クラスのオブジェクトを直接作成することはできません。作成するのは、抽象呼び出しの参照変数です。参照変数は、抽象クラスを継承するクラスのオブジェクト、つまり抽象クラスのサブクラスを参照するために使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.