1

コードがあります (マップ インターフェイスをテストしています)。

これが私の主な方法です:

import blue.*;

public class Test {
    public static void main(String[] args) throws InterruptedException, java.io.IOException {

        MapCollections.<String, Number>frequencyTable(args);
    }
}

そして、MapCollectionsこれが私が使用する私のクラスです:

package blue;
import java.util.*;
import static java.lang.System.out;

public class MapCollections {

   /**
   * The Generic Method. K is String and V is Number.
   */ 
   public static <K extends String, V extends Number> void frequencyTable(K[] args) {
        int initialCapacity = 10;

        // Now I pass the same types (K,V) to the getHashMap method
        // but it doesn't work, I get compile error on the hm.put() call, see a little below...
        // If I explicitly change K,V for String and Number it compiles fine, without errors
        Map<K, V> hm = MapCollections.<K,V>getHashMap(initialCapacity);

        // ... the error is
        // error: method put in interface Map<K#2,V#2> cannot be applied to given types
        hm.put("one", 1);
        hm.put("two", 2);
    };


    public static <K, V> Map<K, V> getHashMap(int initialCapacity) {

        return new HashMap<K,V>(initialCapacity);
    };
}

エラーは次のとおりです。

C:\java>javac Test.java
.\blue\MapCollections.java:13: error: method put in interface Map<K#2,V#2> cannot be applied to given
 types;
                hm.put("one", 1);
                  ^
  required: K#1,V#1
  found: String,int
  reason: actual argument String cannot be converted to K#1 by method invocation conversion
  where K#1,V#1,K#2,V#2 are type-variables:
    K#1 extends String declared in method <K#1,V#1>frequencyTable(K#1[])
    V#1 extends Number declared in method <K#1,V#1>frequencyTable(K#1[])
    K#2 extends Object declared in interface Map
    V#2 extends Object declared in interface Map

私は渡すことができないことを理解してKおりV、あるメソッドから別のメソッドへと、それらは意味を失います。

1)しかし、なぜですか?

2) とはK#1, V#1, K#2, V#2? それらの追加の数が表示されるのはなぜですか?

3) そして、私が望んでいたように使用する方法はありKますか?V

4

3 に答える 3

2

を使用している場合は、コレクションに追加できませんx extends AnyType

理由:次の 例を検討してください。

class Animal {

}
class Dog extends Animal {

}
class Cat extends Animal {

}

今、あなたは持っていますList<? extends Animal>

public void someMethod(List<? extends Animal> list) {
    list.add(new dog()); //no valid
}

そして、次のようにメソッドを呼び出します。

List<Cat> catList = new ArrayList<Cat>(); 
somemethod(catList);

extends でワイルドカードを使用するときにコレクションに追加できる場合は、Cat またはサブタイプ タイプのみを受け入れるコレクションに Dog を追加したことになります。したがって、上限のあるワイルドカードを使用するコレクションには何も追加できません。

ところで、String最終クラスでありk extends String、コンパイルされますが、最終クラスを拡張できるものは何もないため有効ではありません

于 2012-12-30T14:03:34.900 に答える
1

与えられた順序であなたの質問に答えるために(回答番号はあなたの質問に対応しています)

1) GanGnaMStYleOverFlowErroR はすでにこれに回答しています。それでも、あなた自身の例で試してみましょう。

Test クラスの型パラメーターを使用して、frequencyTable メソッドを次のように呼び出しました。

MapCollections.<String, Number>frequencyTable(args);

したがって、 hm.put("one", 1) が成功することを期待しています。String は拡張可能ではありませんが、さらに説明するために、拡張可能であると仮定し、SplittableString というサブクラスがあると仮定します。

他の誰かがあなたのコードを使用していて、電話をかけたいとしましょう

MapCollections.<SplittableString, Number>frequencyTable(args);

彼は自分のキーをサブタイプ (SplittableString) にしたいと考えています。しかし、親クラスのオブジェクトをキーとして(メソッドで)ロードしています。メソッドを呼び出した後、別の開発者は、SplittableString を取得すると想定してキーを取得しようとします。しかし実際には、彼が返すのは String であり、そのサブクラスの参照に割り当てることはできません。

2) 両方の方法でデラリングした K と V が異なります。

public static <K extends String, V extends Number> void frequencyTable(K[] args) {...}

public static <K, V> Map<K, V> getHashMap(int initialCapacity) {...}

エラー メッセージで両者を区別するために、コンパイラは K#1、K#2 および V#1、V#2 を使用します。実際には(エラーメッセージで)それらを次のように表現しようとします

public static <K#1 extends String, V#1 extends Number> void frequencyTable(K[] args) {...}

public static <K#2, V#2> Map<K, V> getHashMap(int initialCapacity) {...}

3) hm.put("one", 1) に値を入れる代わりに、次のようなものを使用します

public static <K extends String, V extends Number> void frequencyTable(K[] args, V[] values) {
    pm.put(args[0], values[0]);
}

これにより、ユーザーが望んでいないだけでなく、型の安全性を破る可能性のあるものを入れる代わりに、呼び出し元が入れることを意図した型のオブジェクトを入れています。

于 2012-12-30T15:46:28.447 に答える
1

問題はK extends String、文字列のサブクラスである場合とそうでない場合があることです (Generics はクラスが であるという事実を無視しfinalます)。これは、これらのクラスの別のサブクラスである可能性があるキーと値を更新できることを意味します。

Map<String, Double> map = new HashMap<>();
Map<String, ? extends Number> map2 = map; // ok
Number n = map2.get("Hello"); // ok
map2.put("Hello", 1); // not ok.

K extends String唯一の有効なオプションがString. V extends Numberコレクションを変更するのではなく、ルックアップのみを意図している場合は作成できます。

この特定の例では、カウントが 20 億を超えると予想される場合を除き、Number を Integer にしてそのままにしておきます。容量が気になる場合は、そのようなコレクションの更新を容易にするTObjectIntHashMapを使用します。例えば

TObjectIntHashMap<String> counters = new TObjectIntHashMap<>();
counters.adjustOrPut("Hello", 1, 1); // one liner to add or increment for a key.
于 2012-12-30T14:05:24.540 に答える