Java の「抽象クラス」とは何ですか?
ベストアンサー1
抽象クラスはインスタンス化できないクラスです。抽象クラスは、インスタンス化できる継承サブクラスを作成することによって使用されます。抽象クラスは、継承サブクラスに対していくつかの処理を実行します。
- 継承サブクラスで使用できるメソッドを定義します。
- 継承サブクラスが実装する必要がある抽象メソッドを定義します。
- サブクラスを他のすべてのサブクラスと交換できるようにする共通インターフェースを提供します。
次に例を示します。
abstract public class AbstractClass
{
abstract public void abstractMethod();
public void implementedMethod() { System.out.print("implementedMethod()"); }
final public void finalMethod() { System.out.print("finalMethod()"); }
}
「abstractMethod()」にはメソッド本体がないことに注意してください。このため、次の操作は実行できません。
public class ImplementingClass extends AbstractClass
{
// ERROR!
}
を実装するメソッドはありませんabstractMethod()
。そのため、 のようなものを取得したときに JVM が何をすべきかを知る方法はありませんnew ImplementingClass().abstractMethod()
。
正しいのはこれですImplementingClass
。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
}
implementedMethod()
または を定義する必要がないことに注意してくださいfinalMethod()
。これらは によってすでに定義されていますAbstractClass
。
ここにもう一つ正しいものがありますImplementingClass
。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
}
この場合は、 を上書きしましたimplementedMethod()
。
ただし、キーワードのせいでfinal
、以下は不可能です。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
public void finalMethod() { System.out.print("ERROR!"); }
}
finalMethod()
のの実装はAbstractClass
の最終実装としてマークされているため、これを実行することはできませんfinalMethod()
。他の実装は許可されません。
抽象クラスを 2 回実装することもできます。
public class ImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("abstractMethod()"); }
public void implementedMethod() { System.out.print("Overridden!"); }
}
// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
public void abstractMethod() { System.out.print("second abstractMethod()"); }
}
ここで、どこかに別のメソッドを記述することができます。
public tryItOut()
{
ImplementingClass a = new ImplementingClass();
AbstractClass b = new ImplementingClass();
a.abstractMethod(); // prints "abstractMethod()"
a.implementedMethod(); // prints "Overridden!" <-- same
a.finalMethod(); // prints "finalMethod()"
b.abstractMethod(); // prints "abstractMethod()"
b.implementedMethod(); // prints "Overridden!" <-- same
b.finalMethod(); // prints "finalMethod()"
SecondImplementingClass c = new SecondImplementingClass();
AbstractClass d = new SecondImplementingClass();
c.abstractMethod(); // prints "second abstractMethod()"
c.implementedMethod(); // prints "implementedMethod()"
c.finalMethod(); // prints "finalMethod()"
d.abstractMethod(); // prints "second abstractMethod()"
d.implementedMethod(); // prints "implementedMethod()"
d.finalMethod(); // prints "finalMethod()"
}
b
型を宣言したにもかかわらずAbstractClass
、 と表示されていることに注意してください"Overriden!"
。これは、インスタンス化したオブジェクトが実際には でありImplementingClass
、implementedMethod()
当然オーバーライドされているためです。(これはポリモーフィズムと呼ばれることがあります。)
特定のサブクラスに固有のメンバーにアクセスする場合は、まずそのサブクラスにキャストする必要があります。
// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();
最後に、次のことはできません。
public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
... // implementation
}
一度に拡張できるクラスは 1 つだけです。複数のクラスを拡張する必要がある場合は、インターフェイスにする必要があります。次のようにします。
public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
... // implementation
}
インターフェースの例を次に示します。
interface InterfaceA
{
void interfaceMethod();
}
これは基本的に以下と同じです:
abstract public class InterfaceA
{
abstract public void interfaceMethod();
}
唯一の違いは、2 番目の方法では、それが実際にインターフェースであることをコンパイラに知らせないことです。これは、他のインターフェースではなく、自分のインターフェースだけを実装させたい場合に便利です。ただし、初心者の一般的な経験則として、抽象クラスに抽象メソッドしかない場合は、おそらくそれをインターフェースにする必要があります。
以下は違法です:
interface InterfaceB
{
void interfaceMethod() { System.out.print("ERROR!"); }
}
インターフェイスにメソッドを実装することはできません。つまり、2 つの異なるインターフェイスを実装した場合、それらのインターフェイス内の異なるメソッドは衝突しません。インターフェイス内のすべてのメソッドは抽象であるため、メソッドを実装する必要があります。また、メソッドは継承ツリー内の唯一の実装であるため、コンパイラはメソッドを使用する必要があることを認識します。