未チェックのキャスト警告に対処するにはどうすればよいですか?


611

Eclipseから次のような警告が出されます。

型の安全性:ObjectからHashMapへの未チェックのキャスト

これは、Objectを返すAPIの制御からの呼び出しによるものです。

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}

理論的には少なくとも潜在的なコードの問題を示しているため、できればEclipseの警告は避けたいと思います。しかし、私はこれを取り除く良い方法をまだ見つけていません。メソッドに含まれる1行だけを抽出し@SuppressWarnings("unchecked")てそのメソッドに追加することで、警告を無視するコードブロックの影響を制限できます。より良いオプションはありますか?Eclipseでこれらの警告をオフにしたくありません。

コードにたどり着く前は、それはより単純でしたが、それでも警告を引き起こしました。

HashMap getItems(javax.servlet.http.HttpSession session) {
  HashMap theHash = (HashMap)session.getAttribute("attributeKey");
  return theHash;
}

あなたがハッシュを使用しようとしたときに警告が出るだろう他の場所に問題がありました:

HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap.  References to generic type HashMap<K,V> should be parameterized.

そのようなHttpSessionを使用している場合は、Brian Goetzの件に関する記事を確認してください
。ibm.com/ developerworks / library / j-jtp09238.html

未チェックのキャストが避けられない場合は、良いアイデアは、論理的に(のような、それの型を表すことを何かを持つ夫婦、それをしっかりとあるenumのかさえインスタンスをClass<T>)、あなたはそれを一瞥することができますので、知っている、それは安全です。
フィリップグイン

4
関連/
重複


追加したいのですが、問題のコードを含むメソッドレベルでのみ@SuppressWarnings( "unchecked")を追加できました。そのため、私はこれを行わなければならないルーチンにコードを分割しました。問題の境界線のすぐ上でこれを実行できるといつも思っていました。
JGFMK

回答:


557

もちろん、明白な答えは、チェックされていないキャストを行うことではありません。

どうしても必要な場合は、少なくとも@SuppressWarningsアノテーションのスコープを制限してください。そのJavadocによると、ローカル変数を使用できます。この方法では、メソッド全体に影響することさえありません。

例:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

Mapジェネリックパラメータが本当に必要かどうかを判断する方法はありません<String, String>。パラメータを事前に知っておく必要があります(またはを取得するとわかりますClassCastException)。コンパイラーが安全かどうかを知ることができないため、コードが警告を生成するのはこのためです。


112
+1は、ローカル変数で実行できることを示します。Eclipseはそれをメソッド全体に追加することのみを提供しています...
thSoft

17
Eclipse 3.7(Indigo)は、チェックされていないローカル変数の追加をサポートしています。
sweetfa

78
警告は、キャストが安全であることをコンパイラーが知らないためだけではありません。たとえばString s = (String) new Object() ;、コンパイラがキャストが安全であることを認識していなくても、警告は出されません。警告は、コンパイラ(a)がキャストが安全であることを認識していないこと、および(b)キャストの時点で完全な実行時チェックを生成しないためです。であることの確認はありますが、であることの確認はHashmapありませんHashMap<String,String>
セオドアノーベル2013

9
悲しいことに、キャストと警告が割り当てに関するものであるとしても、注釈は変数宣言でなければなりません...したがって、宣言と割り当てが異なる場所にある場合(たとえば、「try」ブロックの外側と内側) 、Eclipseが2つの警告を生成するようになりました。元の未チェックのキャストと、新しい「不要な注釈」の診断です。
Ti Strga 2013

6
実際のキャストとは異なる行の異なるスコープにある可能性があるローカル変数宣言を伴う必要がある注釈の回避策は、同じ行でキャストを実行するために、キャストのスコープ内にローカル変数を作成することです宣言として。次に、この変数を別のスコープにある実際の変数に割り当てます。これは、アノテーションもここでは適用できないため、インスタンス変数へのキャストの警告を抑制するためにも使用した方法です。
ジェフロックハート、2015年

168

残念ながら、ここには素晴らしいオプションはありません。これらすべての目標は、タイプセーフを維持することです。「Java Generics」は、汎用化されていないレガシーライブラリを処理するためのソリューションを提供します。特に、セクション8.2で「空ループ技術」と呼ばれるものがあります。基本的に、安全でないキャストを行い、警告を抑制します。次に、次のようにマップをループします。

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

予期しないタイプが検出された場合、ランタイムを取得しますClassCastExceptionが、少なくとも問題の原因の近くで発生します。


6
複数の理由により、skipphoppyによって提供されるものよりもはるかに優れた答えです。1)このコードははるかに短いです。2)このコードは実際にClassCastExceptionをスローします。3)このコードはソースマップの完全なコピーを行いません。4)ループは、アサートで使用される別のメソッドに簡単にラップできます。これにより、製品コードのパフォーマンスヒットを簡単に取り除くことができます。
Stijn de Witt 2014

6
JavaコンパイラーまたはJITコンパイラーが、このコードの結果が使用されていないと判断し、コンパイルしないことによって「最適化」する可能性はありませんか?
RenniePet 2014

1
例外をスローする可能性がある場合、実際にはデッドコードではありません。今日使われているJITコンパイラーについて、どれもこれを台無しにしないことを保証するほど十分には知りませんが、私はそれらがそうであるはずがないと言ってかなり自信があります。
GrandOpener 2016年

3
同じマップがまだ使用されているため、これはまだタイプセーフを保証しません。最初はMap <Object、Object>として定義されていた可能性がありますが、たまたま文字列と数値が含まれ、その後ブール値が追加された場合、このコードのユーザーは混乱し、かなり追跡が困難になります。タイプセーフを保証する唯一の方法は、要求されたタイプを含む新しいマップにそれをコピーすることです。
user2219808 2018

112

ワオ; 自分の疑問に対する答えがわかったと思います。それだけの価値があるかわかりません!:)

問題は、キャストがチェックされていないことです。ですから、自分で確認する必要があります。パラメータ化された型の情報は実行時に利用できず、コンパイル時に消去されているため、instanceofを使用してパラメータ化された型をチェックすることはできません。

ただし、instanceofを使用して、ハッシュ内のすべてのアイテムに対してチェックを実行できます。これにより、タイプセーフな新しいハッシュを構築できます。そして、あなたは警告を引き起こしません。

mmyersとEsko Luontolaのおかげで、ここで最初に書いたコードをパラメーター化したので、どこかでユーティリティクラスにラップして、パラメーター化されたHashMapに使用できます。理解を深めたい、ジェネリックにあまり詳しくない場合は、この回答の編集履歴を確認することをお勧めします。

public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

これは大変な作業であり、ごくわずかな報酬しか得られないかもしれません...使用するかどうかはわかりません。人々が価値があると思うかどうかについてのコメントをいただければ幸いです。また、改善の提案をいただければ幸いです。AssertionErrorsをスローする以外に、もっと良い方法はありますか?私が投げることができるより良いものはありますか?チェック例外にする必要がありますか?


68
これは混乱を招きますが、ClassCastExceptionsをAssertionErrorsに交換するだけで済んだと思います。
ダスティンゲッツ2011年

59
おい、それは間違いなくそれの価値はありません!戻ってきて、その混乱を含むコードを修正しなければならない貧しい樹液を想像してみてください。私は警告を抑制するのは好きではありませんが、それはここではそれほど悪いことではないと思います。
クレイグB

69
それは単に醜く、混乱し、混乱しているだけではありません(1つの大量のコメントを避けられない場合は、メンテナンスプログラマーがそれを通り抜けることができます)。コレクション内のすべての要素を反復処理すると、キャストがO(1)からO(n)操作に変わります。これは決して予想されないことであり、恐ろしい謎の減速に簡単に変わる可能性があります。
DanはFirelightによっていじくります

22
@DanNeelyあなたは正しいです。一般に、誰もこれを行うべきではありません。
skiphoppy

4
コメント...メソッドのシグネチャは間違っています。これは、いまいましいことを「キャスト」しないため、既存のマップを新しいマップにコピーするだけです。また、マップを受け入れるようにリファクタリングされ、HashMap自体に依存しない可能性があります(つまり、内部型がHashMapの場合でも、Mapを取得してメソッドシグネチャでMapを返します)。新しいマップへのキャストやストレージを実際に行う必要はありません。アサーションエラーをスローしない場合、現在のところ、指定されたマップには適切な型が含まれています。ジェネリック型を使用して新しいマップを作成しても、それをそのままにして何でも置くことができるため、無意味です。
MetroidFan2002 2014年

51

Eclipse設定で、Java->コンパイラ->エラー/警告->ジェネリック型に移動し、 Ignore unavoidable generic type problemsチェックボックスをオンにします。

これは質問の意図、つまり

Eclipseの警告を避けたい...

精神ではない場合。


1
ああ、このおかげで:)で「uses unchecked or unsafe operations.」エラーが発生してjavacいましたが、追加する@SuppressWarnings("unchecked")とEclipseが不満になり、抑制は不要だと主張しました。 このボックスのチェックを外すjavacと、Eclipseと同じ動作になります。これが私が望んでいたことです。コードで警告を明示的に抑制することは、Eclipse内のあらゆる場所で警告を抑制するよりもはるかに明確です。
dimo414 2015

26

次のようなユーティリティクラスを作成し、それを使用して未チェックの警告を抑制できます。

public class Objects {

    /**
     * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }
}

次のように使用できます。

import static Objects.uncheckedCast;
...

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
      return uncheckedCast(session.getAttribute("attributeKey"));
}

これに関するいくつかの議論はここにあります:http : //cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html


18
反対投票ではありませんが、ラッパーは警告を抑制するだけでは何も追加しません。
ダスティンゲッツ2011年

3
このソリューションは貴重なコード行を無駄にしないため、+ 1。
ティノ2014

1
@ErikE多すぎます。すべての無駄なラインにスペースを与えるためのはるかに高価な大きくて高解像度のモニター、すべての大きなモニターを置くための大きなデスク、大きなデスクを置くための大きな部屋、そして洞察に満ちた上司..
Tino

1
@ErikE Scrollbars、for vi冗談ですか?
Tino

21

これは難しいですが、私の現在の考えは次のとおりです。

APIがObjectを返す場合は、何もすることができません。何があっても、オブジェクトを盲目的にキャストすることになります。JavaにClassCastExceptionsをスローさせるか、各要素を自分でチェックしてAssertionsやIllegalArgumentExceptionsなどをスローすることができますが、これらのランタイムチェックはすべて同等です。実行時に何をするかに関係なく、コンパイル時のチェックされてないキャストを抑制する必要があります。

APIが何を返すべきかを "知っている"ので、通常はAPIが機能すると仮定して構わないので、ブラインドキャストを行い、JVMにランタイムチェックを実行させたいと思います。ジェネリックが必要な場合は、キャストの上のどこでもジェネリックを使用してください。まだシングルブラインドキャストがあるため、実際には何も購入していませんが、少なくともそこからジェネリックを使用して、JVMがコードの他の部分でブラインドキャストを回避できるようにすることができます。

この特定のケースでは、おそらくSetAttributeの呼び出しを確認し、タイプが入力されていることを確認できるため、途中で同じタイプにブラインドキャストするだけでは不道徳ではありません。SetAttributeを参照するコメントを追加し、それで完了します。


16

以下は、他の回答で言及されている2つの戦略を採用することにより、「チェックされていないキャスト」警告を回避する短い例です

  1. 関心のあるタイプのクラスを実行時にパラメーターとして渡します(Class<T> inputElementClazz)。それからあなたは使うことができます:inputElementClazz.cast(anyObject);

  2. コレクションの型キャストには、ワイルドカードを使用しますか?ジェネリック型Tの代わりに、レガシーコード(Collection<?> unknownTypeCollection)からどのようなオブジェクトが予期されるかを実際に知らないことを認めます。結局のところ、これは「チェックされていないキャスト」警告が私たちに伝えたいことです:が確実に得られるわけではないCollection<T>ので、行うべき正直なことはを使用することCollection<?>です。どうしても必要な場合は、既知のタイプのコレクションを構築できます(Collection<T> knownTypeCollection)。

以下の例でインターフェースされているレガシーコードは、StructuredViewerに属性「input」を持っています(StructuredViewerはツリーまたはテーブルウィジェットで、「input」はその背後のデータモデルです)。この「入力」は、あらゆる種類のJavaコレクションです。

public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
    IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
    // legacy code returns an Object from getFirstElement,
    // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
    T firstElement = inputElementClazz.cast(selection.getFirstElement());

    // legacy code returns an object from getInput, so we deal with it as a Collection<?>
    Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();

    // for some operations we do not even need a collection with known types
    unknownTypeCollection.remove(firstElement);

    // nothing prevents us from building a Collection of a known type, should we really need one
    Collection<T> knownTypeCollection = new ArrayList<T>();
    for (Object object : unknownTypeCollection) {
        T aT = inputElementClazz.cast(object);
        knownTypeCollection.add(aT);
        System.out.println(aT.getClass());
    }

    structuredViewer.refresh();
}

当然のことながら、間違ったデータ型のレガシーコードを使用すると(たとえば、Javaコレクションではなく、StructuredViewerの「入力」として配列を設定した場合)、上記のコードはランタイムエラーを発生させる可能性があります。

メソッドを呼び出す例:

dragFinishedStrategy.dragFinished(viewer, Product.class);

13

HTTPセッションの世界では、APIはそのように記述されているため(キャストとリターンのみ)、キャストを実際に回避することはできません。 Object)。

少しの作業で、チェックされていないキャストを簡単に回避できます。これはClassCastException、エラーが発生した場合にそこに権利を与える従来のキャストに変わることを意味します)。チェックされていない例外CCEは、キャストのポイントではなく、後でいつでもに変わる可能性があります(これが、別の警告である理由です)。

HashMapを専用クラスに置き換えます。

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Attributes extends AbstractMap<String, String> {
    final Map<String, String> content = new HashMap<String, String>();

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
        return content.entrySet();
    }

    @Override
    public Set<String> keySet() {
        return content.keySet();
    }

    @Override
    public Collection<String> values() {
        return content.values();
    }

    @Override
    public String put(final String key, final String value) {
        return content.put(key, value);
    }
}

次に、代わりにそのクラスにキャストするとMap<String,String>、コードを記述した正確な場所ですべてがチェックされます。ClassCastExceptions後で予期しないことはありません。


これは本当に役立つ答えです。
GPrathap 2015年

10

Android Studioで検査を無効にする場合は、次を使用できます。

//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();

2
これはIntelliJ IDEでも動作します
neXus

8

この特定のケースでは、MapをHttpSessionに直接格納するのではなく、代わりに自分のクラスのインスタンスにMap(クラスの実装の詳細)を格納します。次に、マップ内の要素が正しいタイプであることを確認できます。

しかし、とにかくマップのコンテンツが正しいタイプであることを確認したい場合は、次のようなコードを使用できます。

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.put("b", 2);
    Object obj = map;

    Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
    Map<String, String> error = safeCastMap(obj, String.class, String.class);
}

@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
    checkMap(map);
    checkMapContents(keyType, valueType, (Map<?, ?>) map);
    return (Map<K, V>) map;
}

private static void checkMap(Object map) {
    checkType(Map.class, map);
}

private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
    for (Map.Entry<?, ?> entry : map.entrySet()) {
        checkType(keyType, entry.getKey());
        checkType(valueType, entry.getValue());
    }
}

private static <K> void checkType(Class<K> expectedType, Object obj) {
    if (!expectedType.isInstance(obj)) {
        throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
    }
}

1
驚くばかり; 私はそれを私の答えと組み合わせてそれをパラメーター化し、警告を完全に抑制する必要をなくすことができると思います!
skiphoppy

1
+1は、実行時チェックで安全に行うためのおそらく最良のレシピ(理解と保守が容易)
Tino

8

Esko Luontolaによる上記の回答のObjects.Uncheckedユーティリティ関数は、プログラムの混乱を避けるための優れた方法です。

メソッド全体でSuppressWarningsを使用したくない場合、Javaはそれをローカルに置くことを強制します。メンバーのキャストが必要な場合は、次のようなコードにつながる可能性があります。

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

ユーティリティを使用する方がずっとクリーンで、何をしているのかはまだ明らかです。

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

注: 時々警告は本当にあなたが次のような何か間違ったことをしていることを意味することを追加することが重要だと思います:

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

コンパイラーが言っているのは、このキャストは実行時にチェックされないため、汎用コンテナーのデータにアクセスしようとするまで実行時エラーは発生しないということです。


5

警告の抑制は解決策ではありません。1つのステートメントで2レベルのキャストを行うべきではありません。

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

1
彼の5歳の質問?あなたはそれだけの仕事をする必要がありますか?Javaの型が消去されているとすると、2番目のハッシュマップは実行時に最初のハッシュマップと同じになるはずです。エントリを繰り返し処理し、それらがすべて文字列のインスタンスであることを確認した場合は、より効率的でコピーを回避できると思います。または、TBH、使用しているサーブレットJARのソースを検査し、それが文字列のみを配置することを確認します。
Rup

1
今日まで、この警告はプロジェクトで見られます。彼の問題はタイプの検証ではなく、キャストされていないマップへの「配置」によって引き起こされた警告でした。
abbas

2

あなたのコードを投稿すれば簡単に推測できますが、あなたは次のように何かをしたかもしれません

HashMap<String, Object> test = new HashMap();

あなたがする必要があるときに警告を生成します

HashMap<String, Object> test = new HashMap<String, Object>();

見る価値があるかもしれません

Javaプログラミング言語のジェネリックス

何をする必要があるかをよく知らない場合。


1
残念ながら、それは簡単な状況ではありません。コードを追加しました。
skiphoppy

1
私は少し違う問題の答えを探してここに来ました:そしてあなたは私が必要とするものを正確に私に言った!ありがとう!
staticsan

2

私は質問を誤解している可能性があります(例といくつかの周囲の行がいいでしょう)が、なぜ適切なインターフェース(およびJava5 +)を常に使用しないのですか?あなたがのHashMap代わりににキャストしたいと思う理由は何もありませんMap<KeyType,ValueType>。実際に、私は想像することはできません任意のに変数の型を設定する理由HashMapの代わりにMap

そして、なぜソースはObject何ですか?レガシーコレクションのパラメータータイプですか?その場合は、ジェネリックスを使用して、必要なタイプを指定します。


2
この場合、マップに切り替えても何も変わらないと確信していますが、プログラミングのヒントに感謝します。オブジェクトのソースは、私が制御できない(コードが追加された)APIです。
skiphoppy

2

GenericsをサポートしていないAPIを使用する必要がある場合は、できるだけ少ない行数のラッパールーチンでそれらの呼び出しを分離しようとします。次に、SuppressWarningsアノテーションを使用し、同時にタイプセーフキャストも追加します。

これは、物事をできるだけきれいに保つための個人的な好みにすぎません。


2

これを使用してください。新しいHashMapを作成するよりもはるかに高速です。既に作成されている場合は、各要素がその型に対してチェックされるため、安全です。

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

key.isAssignableFrom(e.getKey().getClass())次のように記述できますkey.isInstance(e.getKey())
user102008

1

キャストする前にタイプチェックしてください。

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  

そして、質問する人にとっては、タイプがわからないオブジェクトを受け取るのはよくあることです。多くの従来の「SOA」実装は、常に信頼すべきではないさまざまなオブジェクトを通過させます。(恐怖!)

編集ポスターの更新に一致するようにサンプルコードを1回変更しました。いくつかのコメントの後に、instanceofがジェネリックでうまく機能しないことがわかりました。ただし、外部オブジェクトを検証するためにチェックを変更すると、コマンドラインコンパイラでうまく機能するようです。現在掲載されている修正例。


8
残念ながら、ジェネリックはそれを不可能にします。これは単なるHashMapではなく、型情報を備えたHashMapです。そして、その情報を削除した場合は、警告を別の場所に送信します。
skiphoppy

1

コンピュータサイエンスのほとんどすべての問題は、間接レベル*などを追加することで解決できます。

したがって、aよりも高レベルの非ジェネリックオブジェクトを導入しますMap。コンテキストがないと、それは非常に説得力があるようには見えませんが、とにかく:

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*多すぎるレベルの間接参照を除きます。


1
引用は故デービッド・ウィーラー教授に起因している。 en.wikipedia.org/wiki/…–
Stephen C

1

これは、equals()操作をオーバーライドするときにこれを処理する1つの方法です。

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

これはJava 8で動作するようです(でコンパイルされていても-Xlint:unchecked


0

session.getAttribute()によって返されるタイプがHashMapであることが確実な場合は、その正確なタイプに型キャストすることはできませんが、一般的なHashMapのチェックのみに依存できます。

HashMap<?,?> getItems(javax.servlet.http.HttpSession session) {  
    HashMap<?,?> theHash = (HashMap<?,?>)session.getAttribute("attributeKey");
    return theHash;
} 

するとEclipseは警告を驚かしますが、もちろんこれは実行時エラーにつながり、デバッグが困難になる可能性があります。私はこのアプローチを、操作に重要なコンテキストではなく使用しています。


0

2つの方法があります。1つはタグを完全に回避する方法、もう1つはいたずらですが便利なユーティリティメソッドを使用する方法です。
問題は事前に生成されたコレクションです...
経験則は次のとおりです。「オブジェクトを一度に1つずつキャストする」-汎用化された世界でrawクラスを使用しようとするときにこれが意味するのは、このMap <?、?>内にあり(実際、JVMはそれがMapでもないことに気付くかもしれません!)、それを考えると、キャストできないことは明らかです。Map <String、?> map2がある場合、HashSet <String> keys =(HashSet <String>)map2.keySet()は警告を出しませんが、これはコンパイラーに対する「信仰の行為」であるためです(それはTreeSetになるかもしれません)...しかし、それは信仰の単一の行為にすぎません。

私の最初の方法のように反復することは「退屈」で「時間がかかる」という異議へのPS、答えは「何の痛みもない」:一般化されたコレクションはMap.Entry <String、String> sを含み、何も含まれないことが保証されますそうしないと。この保証の代金を支払う必要があります。ジェネリック医薬品を体系的に使用する場合、この支払いは美しく、マシンタイムではなくコーディングコンプライアンスの形をとります。
ある学校では、警告ではなく、チェックされていないキャストエラーが発生するようにEclipseの設定を行うべきだと言っているかもしれません。その場合、私の最初の方法を使用する必要があります。

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }


    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }


    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }


}

コメント権限がないという事実は、他の人の回答を編集してコメントを追加することを許可しません。他人の回答を編集して、フォーマット、構文などを改善し、意見を追加しないようにします。50人の担当者に達すると、どこにでもコメントできるようになります。その間、あなたが抵抗できると確信しています(または、本当にできない場合は、投稿の既存の回答にコメントを書き込んでください)。(他の人への注意:私がこれを書いたのは、彼の提案されたコメントを見たり拒否したりしたためです。モデレーションツールの他の投稿への編集)
Matteo Italia

-1

これにより警告が消えます...

 static Map<String, String> getItems(HttpSession session) {
        HashMap<?, ?> theHash1 = (HashMap<String,String>)session.getAttribute("attributeKey");
        HashMap<String,String> theHash = (HashMap<String,String>)theHash1;
    return theHash;
}

1
いいえ、ありません。実際には、これは最初に1つあったのに2つの警告を作成します。
Stijn de Witt

あ、そう。どうしてそう思ったのか分かりません。
lukewm 2014

-3

解決策:Eclipseでこの警告を無効にします。@SuppressWarningsではなく、完全に無効にしてください。

上記の「解決策」のいくつかは非常に古く、馬鹿げた警告を抑制するためにコードを読みにくくしています。


9
理由を聞いてもよろしいですか?警告をグローバルに無効にすると、この問題が発生している他の場所が非表示になります。を追加し@SuppressWarningsても、コードがまったく読めなくなるわけではありません。
MByD 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.