web-dev-qa-db-ja.com

IDEがとても賢い場合、なぜ「clone()」をキャストする必要があるのですか?

私のIDE(NetBeans)型は、コードの入力中にCollectionsをチェックします。しかし、返されたObject.clone()のオブジェクトをキャストする必要があるのはなぜですか?何の問題もありません。

キャストせずにObject.clone()の返されたオブジェクトを型チェックすることはできませんか? genericsフレームワークにより、IDEはtype入力中に「=」マークの右側にあるオブジェクト参照をキャストせずにキャストすると、取得できません。

補遺
私の使用例は、プライベートCalendarフィールドpubdateがあったことだけでした。私は書くつもりでした:

_Calendar getPubdate() {
    return pubdate;
}
_

しかし、呼び出し元が私のpubdateを変更するリスクがあるため、コピーを返しました。

_Calendar getPubdate() {
    return (Calendar) pubdate.clone();
}
_

次に、なぜpubdate.clone()をキャストする必要があるのか​​疑問に思いました。メソッドのシグネチャには、型があります。 NetBeansはそれを理解できるはずです。そして、NetBeansは、Collectionsに関して同様のことをしているようです。

13
konishiki

Object.clone()の返されたオブジェクトをキャストする必要があるのはなぜですか?

Objectを返すためです。

genericsフレームワークにより、IDEはtype入力中に「=」マークの右側にあるオブジェクト参照をキャストせずにキャストすると、取得できません。

Object.cloneは一般的ではありません。

cloneが設計されたときにジェネリックが存在していた場合、それはおそらく次のようになります(F限定多相性を使用)。

interface Cloneable<T extends Cloneable<T>> {
  T clone();
}

JavaにMyType機能があった場合、次のようになります。

interface Cloneable {
  this clone();
}

しかし、ジェネリックはObject.cloneは設計されており、JavaにはMyTypeがないため、タイプセーフでないバージョンのObject.cloneは私たちと一緒に作業する必要があるものです。

53
Jörg W Mittag

これはIDEの機能ではなく、言語定義の機能です。

IDEは、プログラミング言語をより効率的に使用するのに役立ちます。それはその言語のセマンティクスを変更しません。つまり、エディタヘルパーは、どちらが必要かが明らかな場合に自動的にキャストを挿入する可能性があります。しかし、それは単に言語の規則を破って、コンパイルできないコードが有効であると偽ることはできません。

編集 IDEが独自のコンパイラをバンドルできることは事実であり、実際には多くの人がそれを正確に実行します。たとえば、部分解析ツリーへのより多くの内部情報を含むより良いエラー報告のために。ただし、この内部コンパイラに公式SDKとは異なる言語セマンティクスを実装させることは非常に悪いアイデアです。開発段階では、本番環境にインストールすると、不可解に失敗し始める可能性があります。定義上、デバッグできない問題が発生します。

26
Kilian Foth

これは、Object.cloneメソッドの型シグネチャが原因です。型シグネチャは、メソッドがObject型のオブジェクトを返すことを示しています。

protected Object clone() throws CloneNotSupportedException

コレクションは、いわゆるジェネリック型を使用して、キャストのタイプを自動的に置き換えます。

したがって、このコードがある場合:

List<Integer> ints = Arrays.asList(1,2,3);
int x = ints.get(0);`

コンパイラーが舞台裏でキャストを追加するため、コードは実際には次のようになります。

List ints = Arrays.asList(1,2,3);
int x = (Integer)ints.get(0);
3
Miro

完全を期すため、Java 5、 共変の戻り値の型が許可されています なので、次のように書くことができます:

public MyObject implements Cloneable {
  @Override
  public MyObject clone() {
    try {
      return (MyObject)super.clone();
    } catch (CloneNotSupportedException e) {
      throw new AssertionError();
    }
  }
}

これにより、次のコードは有効です。

MyObject original = new MyObject();
MyObject clone = original.clone();
0