繁体   English   中英

java中的简单通用列表

[英]simple generic list in java

为什么java泛型如此棘手? 我以为我终于理解了,但是eclipse在下面的somOtherMethod中使用下面的getOuterList方法给出了一个错误。

protected List<?> getOuterList() {
  // blah blah
}

protected List<? extends Object> getOuterList() {
  // blah blah
}

protected void someOtherMethod() {
  ...
  getOuterList().add((MyObject)myObject);  //compile error
  ...
}

更新 :好的 - 所以我现在理解错误。 我对List<?>List<? extends SomeObject>缺乏了解List<? extends SomeObject> List<? extends SomeObject>真的意味着。 在前一种情况下,我认为这意味着可以包含任何内容的列表。 在后一种情况下,我假设它是一组扩展SomeObject的对象的列表。 我理解的正确表示只是List<Object>List<SomeObject> (没有扩展)。 我认为extend帮助我解决了他们没有解决的问题。 所以这就是我真正的问题所在:

public interface DogKennel {
  public List<Dog> getDogs();
}

public class GreyHoundKennel implements DogKennel {

  protected List<GreyHound> greyHounds;

  public List<GreyHound> getGreyHounds() {
    return this.greyHounds;
  }

  public List<Dog> getDogs() {
    // Is there no way to handle this with generics
    // w/out creating a new List?
    return getGreyHounds(); //compiler error
  }

}

您说该方法返回“某些未知类型的List ”(您无法添加,因为您无法保证您要添加的内容是该类型的子类型)。 你真的想说,“你想要的任何类型的List ”,所以你必须使方法通用:

protected <T> List<T> getOuterList() {
  // blah blah
}

好的,我刚看了你的更新:

这一切都取决于你打算如何处理getDogs()的结果。 如果您不打算能够将任何项添加到列表中,那么getDogs()应该返回类型List<? extends Dog> List<? extends Dog> ,然后问题将得到解决。

如果你打算能够添加东西,并且类型为List<Dog>则意味着你可以添加任何种类的Dog ,然后逻辑上这个列表不能和greyHounds ,因为greyHounds有类型List<GreyHound>所以Dog对象不应该进入它。

这意味着您必须创建一个新列表。 请记住,新列表的任何更改都不会反映在原始列表greyHouds

本声明:

List<?> getOuterList() { }

正在告诉编译器“我真的不知道我会找回什么样的列表”。 然后你基本上执行

list<dunno-what-this-is>.add((MyObject)myObject)

它不能将MyObject添加到它不知道它是什么类型的东西的列表中。

本声明:

protected List<? extends Object> getOuterList() { ... }

告诉编译器“这是Object的子类型的列表”。 所以再次,当然你不能转换为“MyObject”然后添加到对象列表。 因为所有编译器都知道列表可以包含对象。

但是,您可以这样做:

List<? super MyObject>.getOuterList() { ... }

然后成功添加MyObject。 那是因为现在编译器知道List是MyObject的列表,或MyObject的任何超类型,因此它肯定可以接受MyObject。

编辑:至于您的DogKennel示例,我想这个代码片段可以满足您的需求:

protected List<GreyHound> greyHounds;

// We only want a List of GreyHounds here:
public List<GreyHound> getGreyHounds() {
    return this.greyHounds;
}

// The list returned can be a List of any type of Dog:
public List<? extends Dog> getDogs() {
    return getGreyHounds();
}

您正在嘲笑Java泛型不是类型参数的多态。

通过你的代码片段,让我们分开示例:

protected List<GreyHound> greyHounds; // List<GreyHound> is fine

/** This method returns a lovely List of GreyHounds */
public List<GreyHound> getGreyHounds() { 
  return this.greyHounds;
}

/** Here is the problem.  A List<GreyHound> is not a List<Dog> */
public List<Dog> getDogs() {
  return getGreyHounds(); //compiler error
}

所以你的原始评论是正确的。 两个列表肯定是不同的,它们之间没有继承。 所以,我建议您调查这两个选项:

  1. 尝试按照您在评论中的建议返回新列表。 例如, return new ArrayList<Dog>(this.greyHounds);

  2. 你真的需要保留一个特定品种的狗的名单吗? 也许您应该将数据成员定义为您添加特定GreyHounds的List<Dog> 即, protected List<Dog> greyHoundsOnly; 您可以通过对象的外部界面管理狗窝中允许携带哪些狗。

除非你有充分的理由保留特定类型的列表,否则我会认真考虑选项2。

编辑:充实我上面建议的选项:

选项1: 返回新列表 优点:简单,直接,你得到一个打字列表,它消除了一个线程安全问题(不暴露对世界的内部引用)。 缺点:看似性能成本。

// Original code starts here.
public interface DogKennel {
  public List<Dog> getDogs();
}

public class GreyHoundKennel implements DogKennel {

  protected List<GreyHound> greyHounds;

  public List<GreyHound> getGreyHounds() {
    return this.greyHounds;
  }
// Original code ends here

  public List<Dog> getDogs() {
    // This line eliminates the thread safety issue in returning 
    // an internal reference.  It does use additional memory + cost
    // CPU time required to copy the elements.  Unless this list is
    // very large, it will be hard to notice this cost.
    return new ArrayList<Dog>(this.greyHounds);
  }

}

选项2: 使用不同的数据表示 优点:使用多态性更好,返回原始目标的通用列表。 缺点:这是一个略有不同的架构,可能不适合原始任务。

public abstract class DogKennel {
  protected List<Dog> dogs = new ArrayList<Dog>();
}

public class GreyHoundKennel extends DogKennel {

  // Force an interface that only allows what I want to allow
  public void addDog(GreyHound greyHound) { dogs.add(greyHound); }

  public List<Dog> getDogs() {
    // Greatly reduces risk of side-effecting and thread safety issues
    // Plus, you get the generic list that you were hoping for
    return Collections.unmodifiableList(this.dogs);
  }

}

一般类型的? 意思是“某些特定的类型,但我不知道哪个”。 什么用? 本质上是只读的,因为你知道实际的类型不能写它。

已经有一个已接受的答案,但请考虑以下代码修改。

public interface DogKernel {
    public List<? extends Dog> getDogs();
}

public class GreyHoundKennel implements DogKernel {
    protected List<GreyHound> greyHounds;

    public List<GreyHound> getGreyHounds() {
        return this.greyHounds;
    }

    public List<? extends Dog> getDogs() {
        return getGreyHounds(); // no compilation error
    }

    public static void main(String[] args) {
    GreyHoundKennel inst = new GreyHoundKennel();
    List<? extends Dog> dogs = inst.getDogs();
    }
}

Java泛型确实被破坏了,但并没有破坏。 BTW Scala通过提供差异处理以非常优雅的方式解决了这个问题。

更新----------

请考虑更新的代码段。

public interface DogKennel<T extends Dog> {
    public List<T> getDogs();
}

public class GreyHoundKennel implements DogKennel<GreyHound> {
    private List<GreyHound> greyHounds;

    public List<GreyHound> getDogs() {
        return greyHounds; // no compilation error
    }

    public static void main(String[] args) {
        GreyHoundKennel inst = new GreyHoundKennel();
        inst.getDogs().add(new GreyHound()); // no compilation error
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM