首页 > 解决方案 > Java 泛型 - 关于大于对象的方法的快速问题

问题描述

我在 Java 课上有一个作业,我们正在学习泛型,我查看了我的笔记、课程,甚至在互联网上,但我仍然无法弄清楚最后一个作业问题要求我做什么,即:

编写一个通用的“大于”函数,它接受两个对象作为参数,每个对象都有一个“值”方法,该方法返回一个整数并返回其“值”方法返回较大整数的参数。你的泛型函数应该约束它的类型参数,这样就不能使用没有“值”方法的类型。

引号中的“值”是否有原因以及方法如何约束其类型参数以便不能使用没有“值”方法的类型。我主要是要求澄清或举个小例子。我是否创建了一个 Value 类,然后做这样的事情:

public static <T> int greaterThan(Value obj1, Value obj2){ // Value will have the "value" method?
    // do I compare the objects here or in the Value class?
}

标签: javagenerics

解决方案


他们显然是在要求您实现一个通用maxByValue方法。由于greater-than包含连字符,因此无论如何都是无效的 Java 标识符,我将坚持使用maxByValue.

有一个value方法的要求被提到了几次,所以让我们把它编码为一个接口:

interface Value {
    int value();
}

现在,这里有一个泛型参数的主要目的是确保返回类型maxByValue足够具体以便有用。我们称这种类型T。为了使参数具有可比性,T必须是 的子类型Value。获取返回类型的唯一有意义的来源是参数的类型。综合三点:

  • 类型参数T子类型Value
  • 从参数推断的类型
  • 结果类型为T

给你签名:

    public static <T extends Value> T maxByValue(T a, T b)

基本上只有两种有意义的实现方式。让我们采用左偏的(即,如果值相同,则返回左参数):

public static <T extends Value> T maxByValue(T a, T b) {
    if (a.value() < b.value()) {
        return b;
    } else {
        return /* left as an exercise */;
    }
}

让我们在一个简单的整数示例上尝试一下:

    class IntValue implements Value {
        final int v;
        public IntValue(int v) {
            this.v = v;
        }
        public int value() {
            return v;
        }
        @Override
        public String toString() {
            return "" + v;
        }
    }
    
    IntValue a = new IntValue(42);
    IntValue b = new IntValue(58);
    IntValue c = max(a, b);
    System.out.println(c); // prints "58"

到目前为止,一切都很好。让我们看看类型推断有多精确:

static interface Vehicle extends Value {
    String doGenericVehicleSound();
}
static abstract class Car implements Vehicle {
    public abstract String doCarSpecificSound();
    public String doGenericVehicleSound() {
        return doCarSpecificSound();
    }
}
static class Train implements Vehicle {
    public String doGenericVehicleSound() {
        return "tk-tk-------tk-tk--tk-tk--------------tk-tk";
    }
    public int value() {
        return 10000000;
    }
}
static class Ferrari extends Car {
    public String doCarSpecificSound() {
        return "rr-rrr-rrrr-rrrrrrr-rrrrrrrrrrrrrrrrrrrr-RRRRRRRRRR";
    }
    public int value() {
        return 222000;
    }
}
static class Tesla extends Car {
    public String doCarSpecificSound() {
        return "...        ...           ¯\\_(ツ)_/¯";
    }
    public int value() {
        return 50000;
    }
}

public static void main(String []args){
    System.out.println(maxByValue(new Ferrari(), new Tesla()).doCarSpecificSound());
    System.out.println(maxByValue(new Tesla(), new Train()).doGenericVehicleSound());
    // System.out.println(maxByValue(new Tesla(), new Train()).doCarSpecificSound());
        
}

这里要看的要点如下。我们有以下子类型关系:

Train   extends Vehicle
Car     extends Vehicle
Ferrari extends Car
Tesla   extends Car

以及具体实例的以下最小上限:

LUB(Train, Train) = Train
LUB(Train, Ferrari) = Vehicle
LUB(Train, Tesla) = Vehicle
LUB(Ferrari, Ferrari) = Ferrari
LUB(Ferrari, Tesla) = Car
LUB(Tesla, Tesla) = Tesla

(以及所有对称情况)。

现在,当我们

  • 把两辆车放进去maxByValue,我们拿出一辆车(第一个例子),但是
  • 当我们将汽车和火车放入maxByValue时,我们会得到更通用的Vehicle,因此特定于汽车的方法变得不可用(示例二和三;第三个没有编译 - 正确,因为火车没有汽车方法)。

推荐阅读