1
interface Node<T extends Number> {
    default public T getData() {
        return (T) Integer.valueOf(1);
    }
}

class MyNode<T extends Integer> implements Node<T> {
}

class FinalNode extends MyNode{
    public static void main(String[] args) {
        MyNode mn = new MyNode();
        mn.getData();
    }
}

This piece of code is just a simplification of the problem I faced in the huge code base. I extract it so it is easier to focus on the problem rather than the business logic :).

When I write the code, my IDE report me mn.getData() return a Number type. But mn is an instance of class MyNode, which is bounded by type "Integer". So I expect mn.getData() should return result with type "Integer". It looks like the generic type bound is not working for inheritance. Could anyone give me some clue?

Modify the code. Is it also a raw type?

 class MyNode implements Node<Integer> {
    }

    class FinalNode extends MyNode{
        public static void main(String[] args) {
            MyNode mn = new MyNode();
            mn.getData();
        }
    }
dashenswen
  • 540
  • 2
  • 4
  • 21
  • It's because using the raw type `MyNode` is the same as using the erasure (non-generic) of that type and its supertypes, so `getData` returns `Number`. There's more information at the linked question under the heading *A raw type is the erasure of that type*. By the way, `(T) Integer.valueOf(1)` doesn't look like a good idea. If you have special knowledge that `getData` will always return `Integer` (such that the cast is safe), then you shouldn't use generics at all. – Radiodef Dec 04 '17 at 03:39
  • Ah. It is a problem of raw type. But why it is bounded by its supertype? Since it is raw type, it should not be bounded at all? – dashenswen Dec 04 '17 at 05:07
  • The erasure of a type variable is its left-most bound. Since `getData` is inherited, the return type is erased to the left-most bound of the type variable as declared in `Node`. I think if you override it in `MyData` to just `@Override public T getData() { return super.getData(); }`, it will actually erase to `Integer` like you might be expecting. The takeaway here, though, is to not use raw types. [*"The use of raw types in code written after the introduction of generics is strongly discouraged."*](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8) – Radiodef Dec 04 '17 at 05:23
  • What happens is that I can not change the Node class and the initialization method.They are both framework level. The only class I can change is the MyNode class..God damn it is disgusting.. – dashenswen Dec 04 '17 at 06:25
  • Hi, I modify the change. Is it also consider as raw type? – dashenswen Dec 04 '17 at 06:36
  • No, it's not a raw type anymore. – shmosel Dec 04 '17 at 06:40

0 Answers0