Java – Operator ‘cannot be applied to’t’, which represents a bounded generic type

See English answers > generic type extending number, calculations 2

class MathOperationV1<T extends Number> {
        public T add(T a,T b) {
            return a + b; // error: Operator '+' cannot be applied to 'T','T' 
        }
    }

It would be appreciated if someone could provide some clues. Thank you!

Solution

There is a basic problem in the implementation of this generic algorithm The problem is not how you mathematically say this reasoning should work, but how it is compiled into bytecode meaning by the java compiler

In your example, you have this:

class MathOperationV1<T extends Number> {
        public T add(T a,'T' 
        }
}

Regardless of boxing and unpacking, the problem is that the compiler doesn't know how it should compile your operators Which of multiple overloaded versions should the compiler use? JVM has different arithmetic operators (i.e. opcodes) for different primitive types; Therefore, the integer sum operator is a completely different opcode, not a double precision opcode (for example, see Iadd vs Dadd). If you consider it, it makes sense, because after all, integer operations and floating-point operations are completely different Different types also have different sizes, etc. (see e.g. Ladd) We should also consider extending BigInteger and BigDecimal of number, but those do not support automatic boxing, so there is no opcode to deal with them directly There may be many other digital library implementations, just like in other libraries How does the compiler know how to handle them?

Therefore, when the compiler infers that t is a number, it is not enough to determine which opcodes are valid for the operation (i.e., boxing, unpacking, and arithmetic)

Later, you suggest changing the code to:

class MathOperationV1<T extends Integer> {
        public T add(T a,T b) {
            return a + b;
        }
    }

Now operators can be implemented with integers and opcodes, but the result of the sum will be an integer, not a T, which will still invalidate the code, because from the compiler's point of view, t can be anything other than integer

I believe there is no way to make your code generic enough that you can forget these underlying implementation details

– edit –

To answer your question in the comments section, please consider the following scenarios according to the final definition of mathoperationv1 < T extends integer > above.

When you say that the compiler will type erase the class definition, you are right. It will be compiled as if it were

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

Given this type of erasure, it seems that subclasses using integer should work here, but this is not true because it makes the type system unhealthy Let me try to prove it

The compiler can not only worry about declaring sites, but also must consider what happens in multiple call sites, which may use different type parameters of T

For example, imagine (for my argument) that there is a subclass of integer, which we call smallint And assume that our code compiles well (this is actually your question: why doesn't it compile?)

What if we do the following?

MathOperationV1<SmallInt> op = new MathOperationV1<>();
SmallInt res = op.add(SmallInt.of(1),SmallInt.of(2));

As you can see, the result of the op.add () method should be smallint, not integer However, from the class definition we erased, the result of our a and B always returns an integer instead of smallint (because it uses JVM integer arithmetic opcode), so this result will be unsound, right?

You may want to know now, but if the type erase of mathoperationv1 always returns an integer, what other things (such as smallint) might it have in the world of the calling site?

Well, the compiler adds some extra magic by converting the result of add to smallint, but only because it ensures that the operation cannot return anything other than the expected type (which is why you see compiler errors)

In other words, your calling website will be deleted as follows:

MathOperationV1 op = new MathOperationV1<>(); //with Integer type erasure
SmallInt res = (SmallInt) op.add(SmallInt.of(1),SmallInt.of(2));

However, this only works if you can ensure that the added return is always smallint (we can't answer the operator question described in my original answer)

So, as you can see, your type erasure just ensures that you can return anything that extends integer according to the subtype rules, but once your calling site declares a type parameter for T, you should always assume the same type, no matter t appears in the original code, so as to maintain the sound of the type system

In fact, you can use the Java decompiler (a tool named javap in the JDK bin directory) to prove these points If you think you need them, I can provide better examples, but you'd better try it yourself and see what happens behind the scenes: -)

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>