【问题标题】:type T parameters in generic method arguments在泛型方法参数中键入 T 参数
【发布时间】:2013-03-21 14:13:27
【问题描述】:

假设定义了以下类:

class Shape { }
class Circle extends Shape {  }
class Rectangle extends Shape { }  //  1

你可以写一个通用的方法来绘制不同的形状:

public static <T extends Shape> void draw(T shape) { }   // 2

Java 编译器将 T 替换为 Shape:

public static void draw(Shape shape) {  } // 3

我的问题是,如果我们在类中直接定义 // 3,那么我们仍然可以将 ShapeCircleRectangle 引用传递给 //3 处的方法。那我们为什么要写 // 2 泛型方法,类型参数 &lt;T extends Shape&gt; 不合时宜地和 //3 一样?

您可以使用相同的示例参考此链接:http://docs.oracle.com/javase/tutorial/java/generics/genMethods.html

【问题讨论】:

  • 你很可能不会。这基本上会成为一个坏例子。
  • 你不需要做方法 //2。实际上,最好使用方法 //3,因为继承的目的之一是传递继承对象的许多“形状”。所以在这种情况下 //3 更有意义。

标签: java generics


【解决方案1】:

您可能需要也可能不需要它。如果您的方法必须处理必须与 T extends Shape 的类型完全匹配的 T 类型的其他对象,则需要它,例如:

public static <T extends Shape> void drawWithShadow(T shape, Class<T> shapeClass) {
    // The shadow must be the same shape as what's passed in
    T shadow = shapeClass.newInstance();
    // Set the shadow's properties to from the shape...
    shadow.draw(); // First, draw the shadow
    shape.draw();  // Now draw the shape on top of it
}

上面,传递Shape 是不够的,因为我们无法制作完全相同类型的阴影。

如果没有这样的要求,一个简单的Shape 就足够了。

【讨论】:

    【解决方案2】:

    在这种特殊情况下,您不需要泛型方法。

    但您可以在泛型方法中做更多事情,而不是在其参数上调用动态链接方法。

    例如,您可能有一个接受并返回 T 元素集合的泛型方法。按类型参数化它允许您在多种集合类型上使用它。

    Java tutorial 中还有其他有用的泛型方法示例。

    【讨论】:

      【解决方案3】:

      在您的示例中,//3 确实与//2 相同。但在其他用例中,泛型类型可能有用:

      • 你想从方法中返回值,与参数的类型相同

      • 您有 2 个或更多参数并希望设置它们必须为同一类型的限制

      【讨论】:

        【解决方案4】:

        不同之处在于您使用的多态类型。

        在一般情况下,您使用的是参数多态性,而在第二种情况下,您使用的是子类型的多态性。实际上,您的第一个案例同时使用了这两种多态性。

        现在,它们在某些方面可能相似,但它们并不相同。一个实际的例子:

        List<Shape> shapes;
        List<T extends Shape> specificShapes;
        

        您可以看到,在第一种情况下,没有类型参数,我无法管理 Shape 的特定子类型的列表,我只能管理一个固定的形状列表,但我无法强制执行任何特定的一个就可以了。所以我没有任何编译时汁液禁止我将TriangleRectangle 添加到shapes

        class ShapeDecorator {
          private Shape shape;
        
          ..
        
          Shape get() { return shape; }
        }
        
        class ShapeDecorator<T extends Shape> {
          private T shape;
        
          T get() { return shape; }
        }
        

        这是另一个示例,在这种情况下,您可以编写一个通用装饰器,它能够返回类型 T 而无需任何强制转换。这在许多将共同祖先作为子类型还不够的情况下很有用。

        【讨论】:

          【解决方案5】:

          主要兴趣在于您可以在代码的不同部分将方法的使用限制为特定类型的形状。

          在某些时候,您可能希望将其参数化为仅绘制Rectangle,而在另一个地方仅绘制Circle,这将在编译时进行检查,即使在运行时您将传递Shape

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多