9

次のようなクラス階層があるとします。

class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;

2つのオブジェクトを比較する関数があります

public <T extends Vehicle> generateDiff(T original, T copy)

コンパイル時に、上記のメソッドは 2 つのオブジェクトがVehicleであることを保証しますが、2 つのオブジェクトの型が同じであることは確認できません。

generateDiff(new Car(), new Car()); //OK
generateDiff(new Plane(), new Plane()); //OK
generateDiff(new Car(), new Plane()); //WRONG

Generics を使用してコンパイル時にこれを実現できますか?

Ps: 現在、Class2 つのオブジェクトの が同じでない場合に例外をスローするように実装しました。しかし、私はこれに満足していません。

前もって感謝します。

4

7 に答える 7

8

はい、できます(種類)!

タイプTは引数から推測されますが、タイプを指定できます。

MyClass.<Car>generateDiff(new Car(), new Plane()); // generates a compile error

メソッドを入力しない場合、型Tは使用される範囲を満たす最も狭いクラスであると推測されます。したがって、パラメーターCarPlane、で機能する最も狭い型はVehicle、であるため、これらの2行は同等です。

generateDiff(new Car(), new Plane()); // type is inferred as Vehicle
MyClass.<Vehicle>generateDiff(new Car(), new Plane());

上記のコードは、generateDiff()が静的メソッドであることを前提としています。インスタンスメソッドの場合は、クラスを入力して、そのタイプをメソッドで使用できます。

于 2012-06-19T04:52:33.837 に答える
6

深く理解すると、少し抽象的になります。関数のクラスタイプも指定する必要があります(以下を参照)。このような動作を強制したい場合は、比較したいタイプを受け入れる別のメソッドを作成することをお勧めします。ともかく:

public <C extends Vehicle> void generateDiff(Class<C> type, C original, C copy);

そして、あなたはそれをそのように使うことができます:

generateDiff(Plane.class, new Plane(), new Plane()); // OK
generateDiff(Car.class, new Car(), new Car()); // OK
generateDiff(Plane.class, new Plane(), new Car()); // ERROR
generateDiff(Vehicle.class, new Plane(), new Car()); // OK

しかし、正気の人がこれをやりたいと思う理由はわかりません!:)

于 2012-06-19T05:00:36.223 に答える
3

厳密に言えば、あなたの質問に対する答えは「いいえ、不可能です」です。

ただし、回避策があります。<T extends Vehicle> VehicleDiffer<T> compare(T vehicleA)methodをVehicleDiffer<T>持つメソッドを作成しますReturnType with(T vehicleB)。これで、次の呼び出しを実行できます。

compare(new Car()).with(new Car()); // okay
compare(new Plane()).with(new Plane()); // okay

以下は失敗します。

compare(new Car()).with(new Plane()); // with(Car) can't be called with argument type Plane
于 2012-06-19T06:20:04.280 に答える
3

私の意見では、Vehicle を引数として受け入れることができるメソッドは、CAR と PLANE を受け入れることができます。コンパイラは、どのような種類のオブジェクトが来るか (CAR、BUS、PLANE の可能性がある) を知らないため、2 つのパラメーターがまったく同じ型であることを保証できません。誰かが CAR を拡張して FORD を作成したら? どちらのオブジェクトもタイプ CAR です。

これを保証する唯一の方法は、実行時にカスタム ロジックを使用することです。

于 2012-06-19T04:46:47.633 に答える
1

いいえ、これはジェネリックの有無にかかわらず達成できません。基本的に、ポリモーフィズムの規則に違反するようにコンパイラーに指示できるかどうかを尋ねています。

以下のようにジェネリックスなしでメソッドを明示的に定義した場合でも、を拡張するクラスのペアを受け入れますVehicle

void generateDiff(Vehicle maybePlane, Vehicle maybeCar) { ...

例外的なシナリオが1つありますが、お勧めしません。final拡張するクラスオブジェクト(または拡張されていないクラス)に対してメソッドを呼び出す場合はVehicle、メソッドをオーバーライドして、各パラメーターのそのクラスのシグネチャに一致させることができます。ただし、それぞれを明示的に定義する必要があります。

class Vehicle;
final class Car extends Vehicle;
final class Plane extends Vehicle;

void generateDiff(Car car1, Car car2) { ...
void generateDiff(Plane plane1, Plane plane2) { ...

generateDiff(new Car(), new Car()); // OK
generateDiff(new Plane(), new Plane()); // OK
generateDiff(new Car(), new Plane()); // No matching method
于 2012-06-19T04:54:50.857 に答える
1

Genericsを使用してコンパイル時にこれを達成できますか?

タイプは実行時に設定されるため、いいえ。無効なタイプが関数に送信された場合は、イントロスペクションを使用して例外をスローできます。その場合は、デザインに欠陥がある可能性がありますが、それは私の意見です。 。

instanceof演算子は基になるタイプをチェックするので、例外を発生させるか、より適切なことを行うことができます。

public <T extends Vehicle> generateDiff(T original, T copy)

if else異なるタイプを比較している可能性があるため、単一の関数を使用するべきではありません。適切なタイプのオブジェクトと適切に比較できるように、各クラスに対応して関数を実装する方がかなりの量が必要になるためです。私はかなりの量の仮定を取っていますが、それは間違っているかもしれません。

于 2012-06-19T04:55:21.513 に答える
0

いいえ、それは不可能です!

これは私がすることです:

class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;

class DiffGenerator {
  public Diff generateDiff(Car original, Car copy) {
    return generateDiff(original, copy)
  }

  public Diff generateDiff(Plane original, Plane copy) {
    return generateDiff(original, copy)
  }

  private Diff generateDiff(Vehicle original, Vehicle copy) {
    return generatedDiff;
  }

}

private メソッドに気付きましたか?private Diff generateDiff(Vehicle original, Vehicle copy)

于 2012-06-19T05:03:43.997 に答える