public <t> void run(T object){}是什么意思?

时间:2015-08-09 11:01:15

标签: java generics

我正在阅读泛型并尝试编写以下代码。没有编译错误。

import java.util.*;

public class JavaApplication14 {

    public<T>  void run (T obj ) {
        //Do Something
    }

  public static void main(String[] args) {     
      JavaApplication14  m= new JavaApplication14();
      m.run(new ArrayList<>());  
      m.run(new Interger(5);
      m.run(5);
     }
}

如果功能

 public<T extends Number>  void run (T obj) {
            //Do Something
        }

这是有意义的,因为我们可以将此函数的参数限制为Number及其子类型。但我非常困惑这个功能的运行&#39;没有任何约束意味着? 它现在可以将任何对象作为参数吗?在什么情况下我需要在泛型中使用这样的函数?

6 个答案:

答案 0 :(得分:10)

你的一些困惑可能源于这样一个事实,即run在这种情况下是一般的方法是没有意义的。通常使用类型参数来创建两个参数类型之间和/或参数类型和返回类型之间的关系。在您的示例中,run也可以声明为需要Object参数(没有声明绑定的类型参数实际上有Object作为其绑定)。

我知道有一种情况可以在单个参数类型中有用地使用类型参数:当您希望能够以不依赖于元素类型的方式操作集合时,这需要将元素插入集合中。例如,考虑一个假设的反向列表&#34;方法:

<T> void reverse(List<T> list)
{
    List<T> reversed = new ArrayList<T>();
    for (int i = list.size(); i > 0; i--) {
        reversed.add(list.get(i - 1));
    }
    list.clear();
    list.addAll(reversed);
}

以一种不需要类型参数的方式编写它是很困难的,即采用List<?>参数。没有演员表的唯一方法是:

void reverse2(List<?> list)
{
    reverse(list);  // call reverse as defined above!
}

但同样,这并不适用于你讨论的例子。

总结如下:

没有显式绑定的类型参数有效Object

为什么方法可能需要类型参数(有或没有显式绑定)有两个原因:

  • 指定参数类型和/或返回类型
  • 之间的关系
  • 捕获潜在的通配符作为类型参数,以允许以其他方式无法执行的操作(如reverse示例中所示)。

您讨论的示例方法:

public<T>  void run (T obj )

...不会这些,因此类型参数毫无意义。该方法可能也被声明为public void run(Object obj)

答案 1 :(得分:3)

它允许您避免任何演员。

public class SomeClass {
      void doStuff();    
}

public<T extends SomeClass>  void run (T obj) {
    //can call doStuff without any casting
    obj.doStuff();
}

public<T>  void run (T) {
    //Here, there's no clue to perform the implicit cast.
    obj.doStuff();  //won't compile
}

答案 2 :(得分:1)

虽然在这种情况下该函数也可以使用Object,但对您有意义的变体也等同于public void run(Number obj) { ... }。对于缺少绑定有意义的示例,请考虑返回类型提到Tpublic <T> List<T> singletonList(T obj)的情况。

答案 3 :(得分:1)

一些理论

有通用的方法。他们的主要目标是通用算法(接收和返回相同的类型)。

使用泛型的代码比非通用代码有许多好处:

  • 消除演员阵容。
  • 在编译时进行更强的类型检查。
  • 使程序员能够实现通用算法。

一点练习

请考虑以下代码:

class MyClass {

    public void method() {}

    public static void main(String[] args) {
        runFirst(new MyClass());
        runSecond(new MyClass());
    }

    public static <T extends MyClass> void runFirst(T obj) {
        obj.method();
    }

    public static <T> void runSecond(T obj) {
        ((MyClass) obj).method();
    }
}

runFirst()方法允许我们避免强制转换为类及其所有子类。在runSecond()方法中,我们可以获得任何类型的参数(<T>,粗略地说,意味着<T extends Object>)。首先,我们必须转换为MyClass,然后调用它的方法。

答案 4 :(得分:1)

首先,我将从public <T> void run(T object) { ... }的含义开始。当您使用那种代码时,可以使用任何对象作为运行参数。如果要将此函数的参数限制为特定接口,类或其子类,则可以编写如NotGenericRun之类的代码,如下所示。

public class NotGenericRun {

    public void run(ArrayList<?> list) {
        String message = "Non Generic Run List: ";
        System.out.println(message.concat(list.toString()));
    }

    public void run(int intValue) {
        String message = "Non Generic Run Int: ";
        System.out.println(message.concat(String.valueOf(intValue)));
    }

}

在这里,我测试了GenericRunNotGenericRun类的输出。

public class TestClass {

    public static void main(String[] args) {
        GenericRun m = new GenericRun();
        m.run(new ArrayList<>());
        m.run(new Integer(5));
        m.run(5);

        NotGenericRun n = new NotGenericRun();
        n.run(new ArrayList<>());
        n.run(new Integer(5));
        n.run(13);
    }

}

此代码的输出如下:

Generic Run: []
Generic Run: 5
Generic Run: 5
Non Generic Run List: []
Non Generic Run Int: 5
Non Generic Run Int: 13

当你使用Generic run时,因为我已经说过,参数可能是任何对象,但还有其他方法在使用泛型时限制参数。

public class GenericRun {

    public <T> void run(T object) {
        String message = "Generic Run: ";
        System.out.println(message.concat(object.toString()));
    }

}

这是怎么做的。

public class GenericRun <T> {

    public void run(T object) {
        String message = "Generic Run: ";
        System.out.println(message.concat(object.toString()));
    }

}

在这种情况下,您将使用GenericClass,如下所示:

GenericRun<Integer> m = new GenericRun<Integer>();
m.run(new Integer(5));
m.run(5);

并且在创建课程时应该只说明它将要解决的问题。我不能想到可能需要public <T> void run(T object) { ... }的场景,但是当你需要方法来获得每个参数或者你不知道将会是什么参数时(或者它真的不太可能),它可能会发生。我想更多的时候你会在这样的运行中使用泛型:

public class GenericRun <T> {

    public void run(T object) {
        ...
    }

}

我正在搜索通用方法here的使用情况,您可以阅读更多有关我们为什么需要通用方法的信息。

这是另一个例子:

public class GenericRun {

    public <T> void run(T[] inputArray) {
        for (T element : inputArray) {
            System.out.printf("%s ", element);
        }
        System.out.println();
    }

}

使用此类,您可以使用单个Generic方法打印不同类型的数组:

public class TestClass {

    public static void main(String[] args) {
        GenericRun m = new GenericRun();
        // Create arrays of Integer, Double and Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

        System.out.println("Array integerArray contains:");
        m.run(intArray); // pass an Integer array

        System.out.println("\nArray doubleArray contains:");
        m.run(doubleArray); // pass a Double array

        System.out.println("\nArray characterArray contains:");
        m.run(charArray); // pass a Character array
    }

}

我希望我回答你的问题。

答案 5 :(得分:0)

这里唯一有意义的是,如果这是某种伪抽象或基类,它为行为提供了框架,让另一个编码器实现自己的逻辑,但也提供了默认的空行动。

它可以允许更好的通用类型设置,例如:

class MySubClass extends JavaApplication14 {
    public <T> void run(T obj){
        new ArrayList<T>().add(obj);
    }
}