java generic addition

2020-04-23 03:13发布

问题:

I'm attempting implement the add method mentioned in the Generic sparse matrix addition question

class Matrix<T extends Number>
{
  private T add(T left, T right)
  {
   if (left instanceof Integer)
   {
     return new Integer(((Integer)left).intValue() + ((Integer)right).intValue());
   }
}

The compiler errors with found java.lang.Integer Required T at the line where I return a new Integer. I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number.

回答1:

The compiler doesn't let you do this because T might be some other class, such as Double.
You know that T is Integer from the instanceof check, but the compiler doesn't.



回答2:

Java's type system is simply not capable of expressing this. Here is a work around.

Create an interface Numeric that provides the numeric operations you are interested in, and write its implementations for the data types you are interested in.

interface Numeric<N> {
  public N add(N n1, N n2);
  public N subtract(N n1, N n2);
  // etc.
}

class IntNumeric extends Numeric<Integer> {
  public static final Numeric<Integer> INSTANCE = new IntNumeric();

  private IntNumeric() {
  }

  public Integer add(Integer a, Integer b) {
    return a + b;  
  }

  public Integer subtract(Integer a, Integer b) {
    return a - b;  
  }

  // etc.
}

And rewrite your Matrix class constructor to accept this implementation.

class Matrix<N> {
  private final Numeric<N> num;
  private final List<List<N>> contents;

  public Matrix(Numeric<N> num) {
    this.num = num;
    this.contents = /* Initialization code */;
  }

  public Matrix<N> add(Matrix<N> that) {
    Matrix<N> out = new Matrix<N>(num);
    for( ... ) {
      for( ... ) {
        out.contents.get(i).set(j,
          num.add(
            this.contents.get(i).get(j),
            that.contents.get(i).get(j),
          )
        );
      }
    }
    return out;
  }
}

// Use site
Matrix<Integer> m = new Matrix<Integer>(IntNumeric.INSTANCE);

Hope that helps.



回答3:

"I'm not sure what I'm missing since T extends Number and Integer is a subclass of Number."

This statement is false. In general if you have:

 public class B extends A {
 }

 public class C extends A {
 }

it does not mean that B can be cast to C. So writing something like:

 public <T extends A> T method(T arg) {
     return (B)arg;
 }

and you calling it with B b = (B)method(C); is obviously wrong.



回答4:

package generics;

public class Box<T> {

      public T j,k;
      int l;
      float f;

      @SuppressWarnings("unchecked")
    public void add(T j,T k) {
        this.j = j;
        this.k=k;

        if(j.toString().contains("."))
        {
              this.f=Float.parseFloat(j.toString())+Float.parseFloat(k.toString());


        } else{
        this.l=Integer.parseInt(j.toString())+Integer.parseInt(k.toString());
        }
      }

      public int getInt() {
        return l;
      }

      public float getFloat() {
            return f;
          }

      public static void main(String[] args) {
         Box<Integer> integerBox = new Box<Integer>();
         Box<Float> floatBox = new Box<Float>();

         integerBox.add(new Integer(10),new Integer(20));
         floatBox.add(new Float(2.2),new Float(3.3));

         System.out.printf("Integer Value :%d\n\n", integerBox.getInt());
         System.out.printf("float Value :%f\n", floatBox.getFloat());
      }
    }


标签: java generics