おそらく以前に尋ねられた質問ですが、いつものように、一般的な単語に言及すると、型消去を説明する千の答えが得られます。私はずっと前にその段階を経験し、ジェネリックとその使用について多くのことを知っていますが、この状況はもう少し微妙なものです。
スプレッドシート内のデータのセルを表すコンテナがあります。これは、実際には2つの形式でデータを格納します。表示用の文字列としてだけでなく、データに応じて(オブジェクトとして格納される)別の形式でもあります。セルは、型間で変換するトランスフォーマーも保持し、型の有効性チェックも行います(たとえば、IntegerTransformerは、文字列が有効な整数であるかどうかをチェックし、格納する整数を返すかどうか、またはその逆を行います)。
セルオブジェクトを新しいタイプで再構築せずにフォーマットを変更できるようにしたいので(たとえば、セカンダリフォーマットを整数の代わりにfloatに変更したり、生の文字列に変更したり)、セル自体はタイプされません。以前の試みではジェネリック型を使用していましたが、一度定義すると型を変更できず、コーディングが非常に大きくなり、多くの反射が発生しました。
問題は、タイプされた方法でセルからデータを取得するにはどうすればよいですか?実験してみたところ、制約が定義されていなくても、ジェネリック型の使用はメソッドで実行できることがわかりました。
public class Cell {
private String stringVal;
private Object valVal;
private Transformer<?> trans;
private Class<?> valClass;
public String getStringVal(){
return stringVal;
}
public boolean setStringVal(){
//this not only set the value, but checks it with the transformer that it meets constraints and updates valVal too
}
public <T> T getValVal(){
return (T) valVal;
//This works, but I don't understand why
}
}
私を先延ばしにするビットは次のとおりです:それは?何もキャストすることはできません。何かに一致するように制約するタイプTの入力はありません。実際、実際にはどこにも何も言いません。Objectのreturnタイプを持つことは、どこでもキャストの複雑さを与えるだけです。
私のテストでは、Double値を設定し、Doubleを(オブジェクトとして)格納しました。Doubleを実行すると、testdou = testCell.getValVal(); キャストの警告がチェックされていなくても、すぐに機能しました。ただし、String teststr = testCell.getValVal()を実行すると、ClassCastExceptionが発生しました。本当に驚くことではありません。
私がこれについて見る2つの見解があります:
1つ:未定義のキャストを使用することは、キャストが戻った後、メソッドの外側ではなく、メソッドの内側にキャストを配置するための単なる方法にすぎないようです。ユーザーの観点からは非常に優れていますが、メソッドのユーザーは適切な呼び出しの使用について心配する必要があります。これは、実行時まで複雑な警告とチェックを非表示にするだけですが、機能しているようです。
2番目の見方は次のとおりです。私はこのコードが好きではありません。それはきれいではなく、私が通常書いていることに誇りを持っているようなコード品質ではありません。コードは、機能するだけでなく、正しくなければなりません。エラーをキャッチして処理し、予想する必要があります。期待するユーザーが自分だけであっても、インターフェイスは絶対確実である必要があります。私は常に、厄介なものよりも柔軟で汎用的で再利用可能な手法を好みます。問題は次のとおりです。これを行う通常の方法はありますか?これは、キャストせずに必要なものを返す、型なしのすべてを受け入れるArrayListを実現するための卑劣な方法ですか?または私がここで欠けているものがあります。このコードを信用してはいけないということです。
おそらく私が意図したよりも哲学的な質問ですが、それが私が求めていることだと思います。
編集:さらなるテスト。
次の2つの興味深いスニペットを試しました。
public <T> T getTypedElem() {
T output = (T) this.typedElem;
System.out.println(output.getClass());
return output;
}
public <T> T getTypedElem() {
T output = null;
try {
output = (T) this.typedElem;
System.out.println(output.getClass());
} catch (ClassCastException e) {
System.out.println("class cast caught");
return null;
}
return output;
}
typedElemにdoubleを割り当てて文字列に入れようとすると、キャストではなくリターンで例外が発生し、2番目のスニペットは保護されません。getClassからの出力はjava.lang.Doubleであり、typedElemから動的に推測されていることを示していますが、コンパイラレベルの型チェックは邪魔にならないように強制されています。
討論のメモとして:valClassを取得するための関数もあります。これは、実行時に割り当て可能性チェックを実行できることを意味します。
Edit2:結果
オプションについて考えた後、2つのソリューションを使用しました。1つは軽量ソリューションですが、関数に@depreciatedとして注釈を付け、もう1つは、キャストしようとするクラスを渡すソリューションです。このように、状況に応じて選択できます。