104

私は非常に単純な質問をしていますが、これには少し混乱しています。

クラスがあるとしますParent

public class Parent {

    int name;
}

そして別のクラスを持っていますChild:

public class Child extends Parent{

    int salary;
}

そして最後に私の Main.java クラス

public class Main {

    public static void main(String[] args)
    {
        Parent parent = new Child();
        parent.name= "abcd";
    }
}

次のような子オブジェクトを作成すると

Child child = new Child():

その後、childオブジェクトは両方のname and salary変数にアクセスできます。

私の質問は:

Parent parent = new Child();

name親クラスの変数のみにアクセスできます。では、この行の正確な用途は何ですか??

 Parent parent = new Child();

また、動的ポリモーフィズムを使用している場合、これを行った後に子クラスの変数にアクセスできないのはなぜですか

Parent parent = new Child();
4

11 に答える 11

69

まず、用語の明確化: Childtype の変数にオブジェクトを代入していますParent。のサブタイプであるParentオブジェクトへの参照です。ParentChild

これは、より複雑な例でのみ役立ちます。getEmployeeDetailsクラス Parent に以下を追加するとします。

public String getEmployeeDetails() {
    return "Name: " + name;
}

そのメソッドをオーバーライドして、Child詳細を提供できます。

@Override
public String getEmployeeDetails() {
    return "Name: " + name + " Salary: " + salary;
}

Parentこれで、オブジェクトが であるかであるかに関係なく、利用可能な詳細を取得する 1 行のコードを記述できますChild

parent.getEmployeeDetails();

次のコード:

Parent parent = new Parent();
parent.name = 1;
Child child = new Child();
child.name = 2;
child.salary = 2000;
Parent[] employees = new Parent[] { parent, child };
for (Parent employee : employees) {
    employee.getEmployeeDetails();
}

出力は次のようになります。

Name: 1
Name: 2 Salary: 2000

を として使用しChildましたParentChildクラスに固有の特別な動作がありましたが、呼び出したときに違いを無視して、どのように とが似ているgetEmployeeDetails()かに焦点を当てることができました。これをサブタイプ多型と呼びます。ParentChild

あなたの更新された質問は、オブジェクトが参照に格納されているChild.salaryときにアクセスできない理由を尋ねます。答えは、「ポリモーフィズム」と「静的型付け」の交差点です。Java はコンパイル時に静的に型付けされるため、コンパイラから一定の保証が得られますが、代わりにルールに従うことを余儀なくされます。そうしないと、コードがコンパイルされません。ここで、関連する保証は、サブタイプ (例: ) のすべてのインスタンスがそのスーパータイプ (例: ) のインスタンスとして使用できるということです。たとえば、型の変数に割り当てることができる null 以外のオブジェクトにアクセスするか、メソッドまたはフィールドが定義されていることが保証されます。ChildParentChildParentemployee.getEmployeeDetailsemployee.nameemployeeParent. この保証を行うために、コンパイラは、Parentアクセスできるものを決定するときに、静的な型 (基本的には変数参照の型) のみを考慮します。そのため、オブジェクトの実行時型で定義されているメンバーにはアクセスできませんChild

Child本当に a を aとして使用したい場合、Parentこれは簡単な制限であり、コードはParentおよびそのすべてのサブタイプで使用できます。それが受け入れられない場合は、参照の型を作成しますChild

于 2012-08-28T12:59:42.387 に答える
16

共通の親インターフェイスを介してすべてのサブクラスにアクセスできます。これは、すべてのサブクラスで利用可能な共通操作を実行するのに役立ちます。より良い例が必要です:

public class Shape
{
  private int x, y;
  public void draw();
}

public class Rectangle extends Shape
{ 
  public void draw();
  public void doRectangleAction();
}

あなたが持っている場合:

List<Shape> myShapes = new ArrayList<Shape>();

リスト内のすべての項目を Shape として参照できます。それが Rectangle であるか、Circle などの他のタイプであるかを心配する必要はありません。それらをすべて同じように扱うことができます。それらすべてを描くことができます。Shape が実際に四角形であるかどうかがわからないため、doRectangleAction を呼び出すことはできません。

これは、オブジェクトを一般的な方法で処理するか、具体的に処理するかのトレードです。

本当に、OOP についてもっと読む必要があると思います。良い本が役立つはずです: http://www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945

于 2012-08-28T12:57:30.020 に答える
12

親タイプをサブクラスに割り当てると、親クラスの共通機能を使用することに同意したことになります。

これにより、さまざまなサブクラスの実装から自由に抽象化できます。その結果、親機能が制限されます。

ただし、このタイプの割り当てはアップキャストと呼ばれます。

Parent parent = new Child();  

反対はダウンキャストです。

Child child = (Child)parent;

したがって、のインスタンスを作成しChildてダウンキャストすると、Parentその type attribute を使用できますname。のインスタンスを作成するParentと、前のケースと同じことができますが、salaryにそのような属性がないため使用できませんParentsalaryにダウンキャストする場合のみ使用できる前のケースに戻りChildます。

詳しい説明あり

于 2012-08-28T12:55:57.903 に答える
8

それは簡単です。

Parent parent = new Child();

この場合、オブジェクトのタイプは ですParent。AntParentには 1 つのプロパティしかありません。ですname

Child child = new Child();

この場合、オブジェクトのタイプは ですChild。AntChildには 2 つのプロパティがあります。nameと ですsalary

実際には、宣言の直後に非 final フィールドを初期化する必要はありません。通常、これは実行時に行われます。これは、必要な実装が正確にわからないことが多いためです。たとえばTransport、先頭にクラスを持つクラス階層があるとします。そして 3 つのサブクラス: CarHelicopterおよびBoat. Tourそして、 field を持つ別のクラスがありますTransport。あれは:

class Tour {
   Transport transport;
}  

ユーザーが旅行を予約しておらず、特定の交通手段を選択していない限り、このフィールドを初期化することはできません。最初です。

go()次に、これらすべてのクラスにメソッドが必要であるが、実装が異なると仮定します。スーパークラスでデフォルトで基本的な実装を定義しTransport、各サブクラスで固有の実装を定義できます。この初期化により、特定の実装を気にせずTransport tran; tran = new Car();にメソッドを呼び出して結果を取得できます。tran.go()特定のサブクラスからオーバーライドされたメソッドを呼び出します。

さらに、スーパークラスのインスタンスが使用されている場所ならどこでもサブクラスのインスタンスを使用できます。たとえば、交通手段をレンタルする機会を提供したいとします。ポリモーフィズムを使用しない場合は、ケースごとに多くのメソッドを作成する必要があります:rentCar(Car car)などrentBoat(Boat boat)。同時に、多態性により、1 つの普遍的なメソッドを作成できますrent(Transport transport)。の任意のサブクラスのオブジェクトを渡すことができますTransport。さらに、時間の経過とともにロジックが増加し、階層内に別のクラスを作成する必要がある場合は? ポリモーフィズムを使用する場合、何も変更する必要はありません。クラスを拡張Transportして、新しいクラスをメソッドに渡すだけです。

public class Airplane extends Transport {
    //implementation
}

rent(new Airplane())。そしてnew Airplane().go()2番目のケース。

于 2012-08-28T13:03:57.463 に答える
2

この状況は、複数の実装がある場合に発生します。説明させてください。いくつかのソートアルゴリズムがあり、実行時に実装するものを選択したい、または実装を追加する機能を他の人に与えたいとします。この問題を解決するには、通常、抽象クラス (親) を作成し、別の実装 (子) を使用します。あなたが書く場合:

Child c = new Child();

実装を Child クラスにバインドすると、それを変更できなくなります。それ以外の場合は、次を使用します。

Parent p = new Child();

Child が Parent を継承している限り、コードを変更せずに後で変更できます。

インターフェイスを使用して同じことを行うことができます。親はもはやクラスではなく、Java インターフェイスです。

一般に、このアプローチは、複数の DB 依存実装が必要な DAO パターンで使用できます。FactoryPatter または AbstractFactory Pattern を見ることができます。これがあなたを助けることを願っています。

于 2012-08-28T12:57:44.507 に答える
1

Parent クラスのインスタンスの配列と、Parent を拡張する子クラス Child1、Child2、Child3 のセットが必要だとします。より一般的な親クラスの実装のみに関心があり、子クラスによって導入されたより具体的なものには関心がない場合があります。

于 2012-08-28T12:57:41.620 に答える
-3

親を Parent として宣言すると、Java は Parent クラスのメソッドと属性のみを提供します。

Child child = new Child();

動作するはずです。または

Parent child = new Child();
((Child)child).salary = 1;
于 2012-08-28T12:51:58.957 に答える