281

I'm having some trouble navigating Java's rule for inferring generic type parameters. Consider the following class, which has an optional list parameter:

import java.util.Collections;
import java.util.List;

public class Person {
  private String name;
  private List<String> nicknames;
  
  public Person(String name) {
    this(name, Collections.emptyList());
  }
  
  public Person(String name, List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
  }
}

My Java compiler gives the following error:

Person.java:9: The constructor Person(String, List<Object>) is undefined

But Collections.emptyList() returns type <T> List<T>, not List<Object>. Adding a cast doesn't help

public Person(String name) {
  this(name,(List<String>)Collections.emptyList());
}

yields

Person.java:9: inconvertible types

Using EMPTY_LIST instead of emptyList()

public Person(String name) {
  this(name, Collections.EMPTY_LIST);
}

yields

Person.java:9: warning: [unchecked] unchecked conversion

Whereas the following change makes the error go away:

public Person(String name) {
  this.name = name;
  this.nicknames = Collections.emptyList();
}

Can anyone explain what type-checking rule I'm running up against here, and the best way to work around it? In this example, the final code example is satisfactory, but with larger classes, I'd like to be able to write methods following this "optional parameter" pattern without duplicating code.

For extra credit: when is it appropriate to use EMPTY_LIST as opposed to emptyList()?


An alternative to the Dictionary/Config File approach would be

1) to define a interface for each of the transaction editors.

2) In your EXE or UI assembly have each of the forms register itself with the assembly that creates the individual transaction.

3) The class controlling the registration should be a singleton so you don't have multiple form instances floating around.

3) When a individual transaction is created it pulls out the correct form variable from the registration object and assigns it do an internal variable.

4) When the Edit method is called it just uses the Show method of the internal method to start the chain of calls that will result in the display of that transacton editor.

This eliminates the need for config files and dictionaries. It continues to separate the UI from the object. Plus you don't need any switch statement

The downside is having to write the interface for each every form in addition to the form itself.

If you have a great deal of different types of editors (dozens) then in that case I recommend that you use the Command Pattern

You have a master command that contains the dictonary recommend by Jonathan. That commands in turns will use that dictornary to execute one of a number of other command that calls the correct form with the correct object. The forms continue to be separate from the object themselves. The forms reside in the Command assembly. In addition you don't have to update the EXE to add another editor only the Command assembly. Finally by putting things inside of Command you can implement Undo/Redo a lot easier. (Implement a Unexecute as well as a Execute)

4

4 に答える 4

465

発生している問題は、メソッドがをemptyList()返してもList<T>、型を指定していないため、デフォルトでを返すことList<Object>です。typeパラメーターを指定して、次のようにコードを期待どおりに動作させることができます。

public Person(String name) {
  this(name,Collections.<String>emptyList());
}

これで、直接代入を行うときに、コンパイラーがジェネリック型パラメーターを理解できるようになります。これは型推論と呼ばれます。たとえば、これを行った場合:

public Person(String name) {
  List<String> emptyList = Collections.emptyList();
  this(name, emptyList);
}

その場合、emptyList()呼び出しは正しくを返しますList<String>

于 2008-11-20T20:34:46.067 に答える
106

使用したい:

Collections.<String>emptyList();

emptyListのソースを見ると、実際には

return (List<T>)EMPTY_LIST;
于 2008-11-20T20:25:10.423 に答える
27

emptyListメソッドには次のシグネチャがあります。

public static final <T> List<T> emptyList()

Listという<T>単語の前にあるということは、結果が割り当てられている変数の型からジェネリックパラメーターTの値を推測することを意味します。したがって、この場合:

List<String> stringList = Collections.emptyList();

次に、戻り値は型の変数によって明示的に参照されるList<String>ため、コンパイラーはそれを把握できます。この場合:

setList(Collections.emptyList());

コンパイラーがジェネリック型を理解するために使用する明示的な戻り変数がないため、デフォルトで。になりObjectます。

于 2008-11-20T20:25:29.533 に答える