1

したがって、以下の関数は、オブジェクトを受け取り、Carそれをオブジェクトに追加する関数であると想定されていCol<>ます。

void insertCar(List<? super Car> c, Car x) {
   c.add(x)
}

質問は、オブジェクト型の変数をn型の変数に追加することが機能するかどうかを尋ねました(つまり. )NissancList<Car>insertCar(c, n)

答えはイエスですが、理由はわかりません。Carを使用しているため、オブジェクトのサブタイプを追加することはできないと思いましたsuperCartype の型または のスーパータイプのみを取ることCar

私に理解できる人はいますか?

編集それは...

List<>それ自体が渡された他のサブタイプであった場合、日産を追加することはできませんか? たとえば、List<? super Car>実際にあった場合List<? super Ford>

以下に相反する回答があるようですが、これは試験のレビュー用に提供された質問であるため、提供された質問と回答が正しいことを確認してください。それについての私の理解は、私がよくわからないことです。

4

3 に答える 3

1

質問は、オブジェクト型の変数をn型の変数に追加することが機能するかどうかを尋ねました(つまり. )NissancList<Car>insertCar(c, n)

あなたの言葉をコード化すると、これがあなたが話していることだと思います:

public class GenericCheck {

    static void insertCar(List<? super Car> c, Car x) {

        c.add(x);
    }

    public static void main(String[] args) {

        List<Car> c = new ArrayList<>();
        Nissan n = new Nissan();
        insertCar(c, n);
    }
}

class Car {}

class Nissan extends Car {}

はい。これは問題ありませんが、実行する必要がある 3 つの型チェックがあります。

  1. の 1 番目の引数はList<Car>有効ですか? はい、サブタイプです。たとえば、こちらを参照してください。insertCarList<? super Car>
  2. の 2 番目の引数はNissan有効ですか? はい、サブタイプです。insertCarCar
  3. 呼び出しはc.add(x)有効ですか? はい、引数は で定義されているタイプまたはスーパータイプでxなければなりません。これは定義によるものです。CarCarList<? super Car> cCar x

では、なぜ混乱するのでしょうか。Nissan2 番目の引数に型を渡すため、ポイント 3 が型またはスーパータイプではない(サブタイプである)ため、ポイント 3 が壊れると考えているためです。何が起こるかというと、それが にアップキャストされ、これが実行可能な引数になります。xCarCarNissanCar

呼び出しが有効かどうかを知るには、 (メソッドの引数リストで) andc.add(x)の定義を確認するだけでよいことに注意してください。これにより、メソッドが有効な引数で呼び出される限り、その呼び出しは有効になります。このチェックは、 を呼び出すときの (2 つの) タイプ チェックとは関係ありません。これらは、上記で実行した 3 つのチェックです。cxc.add(x)insertCar

編集: では、なぜうまくいかinsertCar(List<? super Nissan> c, Car x)ないのですか?

型消去のため。コンパイル中に、コンパイラはすべての型パラメーターを消去し、それぞれを最初の境界に置き換えます (こちらを参照)。あなたが得るのは へのリクエストList<Nissan>ですadd(Car)。しかし、これはCarのサブタイプではないため、コンパイルできませんNissan

の最初のケースではList<? super Car>、型消去は結果として有効にList<Car>なりadd(Car)ます。

私が思うに、あなたの混乱を最も解消するのは、ジェネリックがコンパイル時のみのチェックを提供するという認識です。上記のコードブロックでほのめかしたように

static void insertCar(List<? super Car /* or Nissan */> c, Car x) {

    c.add(x);
}

実行時にメソッドが呼び出される引数に関係なく、コンパイルする必要があります。これは、1 番目のメソッド引数のジェネリックが、2 番目の引数に渡す型とはまったく関係がないこと、insertCar(..., Car)またはinsertCar(..., Nissan)のコンパイル可能性に影響を与えないことを意味しc.add(x)ます。指定された引数はメソッドの引数の型に変換 (アップキャスト) されますがCar、これはメソッドの内容とは無関係です。

于 2015-12-15T23:38:32.463 に答える
0

サブタイプ オブジェクトには、Car オブジェクトの少なくともすべての属性とメソッドに加えて、通常は独自のメソッドがさらに含まれます。Nissan オブジェクトが Car 変数に割り当てられている場合、Car 変数のすべてのメソッドを呼び出すことができます。逆に、Car インスタンスを Nissan オブジェクトに割り当てることはできません。Nissan オブジェクトには Car インスタンスよりも多くのメソッドがある可能性があるためです。

于 2015-12-15T23:21:27.133 に答える
0

答えはイエスですが、理由はわかりません。スーパーを使用しているため、オブジェクト Car のサブタイプを追加することはできないと思いました。タイプ Car のタイプまたは Car の任意のスーパータイプのみを取ること。

すべてのスーパー クラス参照は、そのインスタンスまたはその子クラス インスタンスのオブジェクトを保持できるため、これは完全に合法です。

于 2015-12-15T23:10:09.490 に答える