泛型..?超级T [英] Generics..? Super T

查看:120
本文介绍了泛型..?超级T的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能存在重复:


A)

 列表< ;?超级形状> shapeSuper = new ArrayList< Shape>(); 

shapeSuper.add(new Square()); //从SHAP
shapeSuper.add(new DoubleSquare()); //从SQ
shapeSuper.add(new TripleSquare()); //从DS
shapeSuper.add(new Rectangle()); //从SHAP
shapeSuper.add(new Circle()); //从SHAP

延伸(Object object:shapeSuper){...}

为什么当我只能添加Shape及其
导数时,迭代必须是Object的对象?

 列表< ;?超级形状> shapeSuper = new ArrayList< Object>(); 

shapeSuper.add(new Object()); //编译错误

为什么上面的行会产生编译错误?

对于您的示例,您可以使用普通的 List< Shape> 像丹和保罗说的;您不需要使用通配符问号语法,如 List <?超级形状> 列表< ;?扩展形状> )。我认为你的潜在问题可能是,我什么时候可以使用问号风格声明之一? (Julien引用的Get和Put原则是对这个问题的一个很好的回答,但是我认为它没有什么意义,除非你在一个例子的背景下看到它。)这是我对Get和扩展版的看法,将原则置于何时使用通配符。



使用<如果...


  • 方法有一个泛型类
    参数 Foo< T> readSource

  • GET方法从readSource中获取T的实例,并且不关心检索的实际对象是否属于T



使用<如果...


  • 一个方法有一个通用类参数 Foo< ; T> writeDest

  • 将方法PUTS的实例写入writeDest,并且不关心writeDest是否也包含T的子类的对象。
  • >


下面是一个演示通配符背后思想的特定示例演练。想象一下,您正在编写一个processSquare方法,该方法从列表中删除一个正方形,对其进行处理,并将结果存储在输出列表中。这里有一个方法签名:

$ pre $ void $ processSquare(List< s = iSqua.remove(0); s.doSquare(); oSqua.add(一个或多个); }

现在创建一个DoubleSquares列表,它扩展了Square,并尝试处理它们: p>

 列表< DoubleSquare> dsqares = ... 
列表< Square> processed = new ArrayList< Square>;
processSquare(dsqares,processed); //编译器错误! dsquares不是List< Square>

编译器失败并报错,因为dsquares的类型 List< DoubleSquare> 与processSquare的第一个参数类型不匹配, List< Square> 。也许DoubleSquare是一个Square,但你需要告诉编译器一个 List< DoubleSquare> 是-a List< Square> 用于processSquare方法。 使用<通过扩展Square> 通配符来告诉编译器你的方法可以接受Square的任何子类的List。

  void processSquare(List< ;? extends Square> iSqua,List< Square> oSqua)



<接下来,您将改进应用程序来处理Circles和Squares。您想要将所有已处理的形状汇总到包含圆形和正方形的单个列表中,因此您已将处理的列表的类型从 List< Square> 更改为 List< Shape>

  List< DoubleSquare> dsqares = ... 
列表< Circle>圆圈= ...
列表<形状> processed = new ArrayList< Square>;
processSquare(dsqares,processed); //编译器错误!处理不是List< Square>

编译器失败并出现新错误。现在处理的列表 List< Shape> 的类型与processSquare的第二个参数不匹配, List< Square> 使用< super square> 通配符告诉编译器一个给定的参数可以是Square的任何超类的列表

  void processSquare(List< ;? extends Square> iSqua,
List< ;? super Square> oSqua)
pre>

以下是示例的完整源代码。有时我会发现通过从一个工作示例开始,然后将其分解以查看编译器如何反应来学习东西更容易。

  package wild; 

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public abstract class Main {
//在处理广场时,
//我将输入任何可以生成(读取)正方形的列表。
//我将输出任何类型的可以接受(写)正方形的List。
static void processSquare(List< ;? extends Square> iSqua,List> super square> oSqua)
{Square s = iSqua.remove(0); s.doSquare(); oSqua.add(一个或多个); }

static void processCircle(List< ;? extends Circle> iCirc,List<?super Circle> oCirc)
{Circle c = iCirc.remove(0); c.doCircle(); oCirc.add(C); }

public static void main(String [] args){
//加载一些输入
List< Circle> circles = makeList(new Circle());
列表< DoubleSquare> dsqares = makeList(new DoubleSquare());

//完成形状的分页存储
List< Shape> processed = new ArrayList< Shape>();

//处理形状
processSquare(dsqares,processed);
processCircle(圈子,已处理);

//做后处理
(形状s:已处理)
s.shapeDone();


static class Shape {void shapeDone(){System.out.println(Done with shape。); }}
static class Square extends Shape {void doSquare(){System.out.println(Square!); }}
static class DoubleSquare extends Square {}
static class Circle extends {void doCircle(){System.out.println(Circle!); }}

static< T>列表与LT; T> makeList(T a){
List< T> list = new LinkedList< T>(); list.add(一);退货清单;
}

}


Possible Duplicate:
what is the difference between ‘super’ and ‘extends’ in Java Generics

A)

List<? super Shape> shapeSuper = new ArrayList<Shape>();

shapeSuper.add(new Square());       //extends from SHAP  
shapeSuper.add(new DoubleSquare()); //extends from SQ  
shapeSuper.add(new TripleSquare()); //extends from DS  
shapeSuper.add(new Rectangle());    //extends from SHAP  
shapeSuper.add(new Circle());       //extends from SHAP  

for (Object object : shapeSuper) { ... }

Why must the iteration be of Objects when I can add only Shape and its derivatives?

B)

List<? super Shape> shapeSuper = new ArrayList<Object>();  

shapeSuper.add(new Object()); //compilation error  

Why does the above line produce a compilation error?

解决方案

For your example, you can use a plain List<Shape> like Dan and Paul said; you don't need to use the wildcard question mark syntax such as List<? super Shape> or List<? extends Shape>). I think your underlying question may be, "when would I use one of the question mark style declarations?" (The Get and Put Principle that Julien cites is a great answer to this question, but I don't think it makes much sense unless you see it in the context of an example.) Here's my take at an expanded version of the Get and Put Principle for when to use wildcards.

Use <? extends T> if...

  • A method has a generic class parameter Foo<T> readSource
  • The method GETS instances of T from readSource, and doesn't care if the actual object retrieved belongs to a subclass of T.

Use <? super T> if...

  • A method has a generic class parameter Foo<T> writeDest
  • The method PUTS instances of T into writeDest, and doesn't care if writeDest also contains objects that are subclasses of T.

Here's a walkthrough of a specific example that illustrates the thinking behind wildcards. Imagine you are writing a processSquare method that removes a square from a list, processes it, and stores the result in an output list. Here's a method signature:

void processSquare(List<Square> iSqua, List<Square> oSqua)
{ Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }

Now you create a list of DoubleSquares, which extend Square, and try to process them:

List<DoubleSquare> dsqares = ... 
List<Square> processed = new ArrayList<Square>;
processSquare(dsqares, processed); // compiler error! dsquares is not List<Square>

The compiler fails with an error because the type of dsquares List<DoubleSquare> doesn't match the type of the first parameter to processSquare, List<Square>. Perhaps a DoubleSquare is-a Square, but you need to tell the compiler that a List<DoubleSquare> is-a List<Square> for the purposes of your processSquare method. Use the <? extends Square> wildcard to tell the compiler that your method can take a List of any subclass of Square.

void processSquare(List<? extends Square> iSqua, List<Square> oSqua)

Next you improve the application to process Circles as well as Squares. You want to aggregate all your processed shapes in a single list that includes both circles and squares, so you changed the type of the processed list from a List<Square> to a List<Shape>:

List<DoubleSquare> dsqares = ... 
List<Circle> circles = ... 
List<Shape> processed = new ArrayList<Square>;
processSquare(dsqares, processed); // compiler error! processed is not List<Square>

The compiler fails with a new error. Now the type of the processed list List<Shape> doesn't match the 2nd parameter to processSquare, List<Square>. Use the <? super Square> wildcard to tell the compiler that a given parameter can be a List of any superclass of Square.

void processSquare(List<? extends Square> iSqua, 
                          List<? super Square> oSqua) 

Here's the full source code for the example. Sometimes I find it easier to learn stuff by starting with a working example and then breaking it to see how the compiler reacts.

package wild;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public abstract class Main {
  // In processing the square, 
  // I'll take for input  any type of List that can PRODUCE (read) squares.
  // I'll take for output any type of List that can ACCEPT (write) squares.
  static void processSquare(List<? extends Square> iSqua, List<? super Square> oSqua) 
  { Square s = iSqua.remove(0); s.doSquare(); oSqua.add(s); }

  static void processCircle(List<? extends Circle> iCirc, List<? super Circle> oCirc) 
  { Circle c = iCirc.remove(0); c.doCircle(); oCirc.add(c); }

  public static void main(String[] args) {
    // Load some inputs
    List<Circle> circles = makeList(new Circle());
    List<DoubleSquare> dsqares = makeList(new DoubleSquare());

    // Collated storage for completed shapes
    List<Shape> processed = new ArrayList<Shape>();

    // Process the shapes
    processSquare(dsqares, processed);
    processCircle(circles, processed);

    // Do post-processing
    for (Shape s : processed)
      s.shapeDone();
  }

  static class Shape { void shapeDone() { System.out.println("Done with shape."); } }
  static class Square extends Shape { void doSquare() { System.out.println("Square!"); } }
  static class DoubleSquare extends Square {}
  static class Circle extends Shape { void doCircle() { System.out.println("Circle!"); } }

  static <T> List<T> makeList(T a) { 
    List<T> list = new LinkedList<T>(); list.add(a); return list; 
  }

}

这篇关于泛型..?超级T的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆