2016-01-19 7 views
7

私はOCP Java SE7, certification guide from Mala Guptaを読んでいます。 297ページで、次のコードスニペット型推論アルゴリズムのどのような変更によりこの現象が発生しますか?

import java.util.HashMap; 
import java.util.Map; 

public class TestGenericTypeInference { 
    Map<String,Double> salaryMap  = new HashMap<>(); 
    Map<String,Object> copySalaryMap = new HashMap<>(salaryMap); 
} 

は、Java 8でコンパイルされたが、Java 7とコンパイラが文句を言う:

TestGenericTypeInference.java:8: error: incompatible types: HashMap<String,Double> cannot be converted to Map<String,Object> 
    Map<String,Object> copySalaryMap = new HashMap<>(salaryMap); 
           ^

私の質問は次のとおりです。型推論アルゴリズムでどのような変更は、この動作の原因は?

答えて

1

私はそれがJLS 8, ch 18.2.1に記述されていると思う:

ポリ式として、ネストされた汎用的なメソッド呼び出しを処理することにより、我々は、ネストされた呼び出しのための推論の挙動を改善 。例えば、 以下は、Java SE 8でJava SE 7に違法が、合法である:

ProcessBuilder b = new ProcessBuilder(Collections.emptyList()); // ProcessBuilder's constructor expects a List<String>

外側およびネストされた呼び出しの両方が推論が必要な場合、 問題はより困難です。例えば:

List<String> ls = new ArrayList<>(Collections.emptyList());

我々 アプローチは、「リフト」境界はしようとし、この場合、(外 推論プロセスにネストされた呼び出し (emptyListの場合単に{ α <: Object })のために推測します コンストラクタがタイプArrayList<β>の場合はβを推論します)。また、ネストされた推論変数と外部推論の間の依存関係(‹List<α> → Collection<β>> 、従属性α = β)は、従属性を推測します( )。このようにして、ネストされた呼び出し内の推測 変数の解決は、外部呼び出し( 割り当てターゲットに基づく、β = Stringに基づく)から追加の 情報を推測できるまで待つことができます。

この例のList<String> ls = new ArrayList<>(Collections.emptyList());もjava-7ではコンパイルされません。

+0

本当に '新しいHashMap <>(salaryMap);'はネストされたジェネリックメソッド呼び出しと見なすことができますか? –

+0

'new ArrayList <>(Collections。)と同じことです。上記を参照してください。 – Andremoniy

+0

はい、しかし、 'salaryMap'は、' Collections.emptyList'のような推論を必要とするメソッド呼び出しではなく、オブジェクト参照です。 –

1

は、以下のリンクを見てください:
https://forums.manning.com/posts/list/36712.page
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

Javaコンパイラは、ジェネリックメソッド呼び出しの型パラメータを推測するために、ターゲットタイピングを利用しています。

static <T> List<T> emptyList(); 
List<String> listOne = Collections.emptyList(); 

の両方で動作します。
ただし、これはこの文脈では必要ではありません。しかしそれは他の状況では必要でした。以下の方法を考えてみます。

void processStringList(List<String> stringList) { 
    // process stringList 
} 

あなたは空のリストとメソッドのprocessStringListを起動するとします。 Java SEの7では、次の文はコンパイルされません:

processStringList(Collections.emptyList()); 

をするJava SE 7コンパイラは次のようなエラーメッセージを生成します。

List<Object> cannot be converted to List<String> 

コンパイラは型引数Tの値を必要とするため、値Objectで始まります。したがって、Collections.emptyListの呼び出しは、List型の値を返します。この値は、processStringListメソッドと互換性がありません。次のようにこのように、Java SEの7では、あなたは型引数の値の値を指定する必要があります。

processStringList(Collections.<String>emptyList()); 

をこれは、ターゲットであるものの概念8. Java SEの中にもはや必要ではありませんメソッドのprocessStringListへの引数など、メソッド引数を含むように型が拡張されました。この場合、processStringListには、リスト< String>型の引数が必要です。 Collections.emptyListはList < T>の値を返します。リスト< String>のターゲットタイプを使用すると、コンパイラは型引数Tの値がStringであることを推測します。このように、JavaのSE 8で、次の文は、コンパイルされます。

processStringList(Collections.emptyList()); 
0

私の質問への答え:

タイプに推論アルゴリズムは、この動作の原因は何の変化?

は、the Generics FAQ from Angelina Langerである。同様の例が与えられる。

// error in Java 7 ; fine since Java 8 
Set<Number> s3 = new HashSet<>(Arrays.asList(0L,0L)); 
  • [...]式は割り当ての左側が実際に無視されることを実証している(ジャワ7で)。コンパイラーは、コンストラクターの引数、つまりasListメソッドの結果から、新しいHashSetの欠落した型パラメーターがLongでなければならないことを再度推測します。これは、タイプの不一致とそれに伴うエラーメッセージにつながります。コンパイラーは、欠落している型パラメーターがNumberでなければならないと結論づけません。これは、割り当ての左辺を無視するためです。 Java 8では、型推論が変更され、改善されました。それ以来、コンパイラはコンパイラの右側にある新しいHashSetの型パラメータ型としてNumberを推論し、そこからasListメソッドの型パラメータとしてNumberを導き出します。 Java 8では、これはうまくコンパイルされます。
関連する問題