【问题标题】:Generic class - operator issue通用类 - 运算符问题
【发布时间】:2013-05-29 21:14:28
【问题描述】:

我正在尝试在 Java 中创建一个泛型类。 阅读了一些指南,我发现了如何声明它以及如何调用它的函数。

我的课是一个点,没有方法它会是这样的:

class Pnt<type>{
  protected type x, y;
  protected int col;
}

现在,我正在尝试创建一个add 方法,但我做不到。

我尝试的是:

  void add(type x_, type y_){
    x += x_;
    y += y_;
  }

IDE 对我大喊 += 未定义 type 变量...

我知道在 Java 中不可能像在 C++ 中那样定义一个新的运算符,所以我要求另一种方法来添加两个 type 变量!

附:我将使用的所有类型都是doubles、floats 和integers,这就是我尝试简单上瘾的原因。

【问题讨论】:

    标签: java operator-keyword generics


    【解决方案1】:

    当您说class Pnt&lt;type&gt; 时,ti 表示type 是一个对象,而不是像intdouble 这样的原始数据类型。您可以对数字原始数据类型(如 intfloat 等)而不是对象执行 += 操作。事实上,您无法对任何通用对象执行+= 操作。

    IntegerFloat 等的对象支持+= 运算符,因为它们是包装类,可以拆箱为原始类型并在以后自动装箱。但是编译器无法确认typeInteger 还是Float。因此,它会产生编译时错误。

    【讨论】:

    • 它也不适用于对象类型。事实上,该语句在 x+=x_ 处失败;这很奇怪。我想这与原语无关。
    • 这就是为什么我必须使用Double 而不是double 等的原因......但是对象DoubleFloatInteger 都支持+=
    • 是的,Integer 支持+= 运算符,但编译器无法确认type 是否为Integer。它可以是File 或任何其他类。
    • 你可以试试class Pnt&lt;type extends Number&gt;。我自己还没有测试过,但它表明唯一合法的类是数字,这可能足以让它编译。
    • @chessbot 使用 ` 符号将代码包装在您的 cmets 中。不,它不能使用type extends Number。请注意,BigInteger(以及其他类)也从 Number 扩展而来,并且不支持像 += 这样的操作。 IntegerLong 和其他包装类支持这一点是因为它们被自动装箱为基元类型,然后对这些基元执行操作,然后在操作完成后,将值自动装箱一次以Integer(或您使用的包装类)。
    【解决方案2】:

    有两个问题:第一,如果要快,就得直接使用原语,而这些在泛型中是不支持作为参数的。这实际上意味着您必须分别为Point 维护三个版本。

    如果要使用泛型,可以使用对应的类(比如Integer),但是还有一个问题:他们的超类型Number没有add方法(更别提@987654325了) @运算符或+=)。

    所以我知道的唯一方法是实现您自己的支持add 方法的数字类层次结构:

    abstract class Numeric<T extends Number> {
        public abstract T getValue();
    
        public abstract Numeric<T> add(Numeric<T> other);
    
        @Override
        public String toString() {
            return getValue().toString();
        }
    }
    
    class MyInt extends Numeric<Integer> {
        public final Integer value;
    
        public MyInt(Integer _value) {
            super();
            this.value = _value;
        }
    
        @Override
        public Integer getValue() {
            return this.value;
        }
    
        @Override
        public Numeric<Integer> add(Numeric<Integer> other) {
            return new MyInt(this.value + other.getValue());
        }
    }
    
    class MyDouble extends Numeric<Double> {
        public final double value;
    
        public MyDouble(Double _value) {
            super();
            this.value = _value;
        }
    
        @Override
        public Double getValue() {
            return this.value;
        }
    
        @Override
        public Numeric<Double> add(Numeric<Double> other) {
            return new MyDouble(this.value + other.getValue());
        }
    }
    

    基于此,您至少可以实现一个通用点:

    class NumericPoint<T extends Number> {
        public final Numeric<T> x;
        public final Numeric<T> y;
    
        public NumericPoint(Numeric<T> _x, Numeric<T> _y) {
            super();
            this.x = _x;
            this.y = _y;
        }
    
        public NumericPoint<T> add(NumericPoint<T> other) {
            return new NumericPoint<T>(this.x.add(other.x), this.y.add(other.y));
        }
    
        @Override
        public String toString() {
            return "(" + this.x + "/" + this.y + ")";
        }
    }
    

    配合使用

    NumericPoint<Integer> ip1 =
        new NumericPoint<Integer>(new MyInt(1), new MyInt(2));
    NumericPoint<Integer> ip2 =
        new NumericPoint<Integer>(new MyInt(3), new MyInt(4));
    NumericPoint<Integer> ip = ip1.add(ip2);
    System.out.println(ip);
    
    NumericPoint<Double> dp1 = 
      new NumericPoint<Double>(new MyDouble(1.1), new MyDouble(2.1));
    NumericPoint<Double> dp2 = 
      new NumericPoint<Double>(new MyDouble(3.1), new MyDouble(4.1));
    NumericPoint<Double> dp = dp1.add(dp2);
    System.out.println(dp);
    

    我修改了您的示例:数字和点是不可变的。例如,它的实现类似于BigDecimal。所以add方法属于泛型类,它返回一个新的实例。

    【讨论】:

    • 很重,很重,我想我会改成三个不同的课程......不幸的是它不符合我的需要,但是嘿!你让它成为可能! =D
    • 我同意,它很重。 C++ templates 解决了这个问题(C++ 模板允许 int 作为模板参数)。
    • 是的,但是 Processing 不支持 C++!
    猜你喜欢
    • 2010-12-24
    • 2011-06-11
    • 2011-03-21
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多