Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the practical difference between `class <T extends A> { }` and a `class { }` that uses A?

Tags:

java

generics

I think that, for the most part, I understand bounded types, and the differences between, for example, List<? extends MyClass>, List<? super MyClass> and List<MyClass>. But when it comes to the implementation of classes and generic methods, I do not understand what <T extends MyClass> brings to the table.

Taken from the docs in Oracle:

[...] a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

public class Box<T> {

    private T t;          

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.set(new Integer(10));
        integerBox.inspect("some text"); // error: this is still String!
    }
}

This doesn't make much sense to me. If I removed the generic from the method and made the parameter type just Number...

    public void inspect(Number u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("Second: " + u.getClass().getName());
    }

it would still work just fine. I don't see where I'm gaining or losing type safety, although maybe that's not the point?

Same in something like this:

class A { void foo() { } }

class B extends A { void bar() { } }

class Generic<T extends B> {
    void baz(T obj) {
        obj.foo();
        obj.bar();
    }
}

// vs

class NonGeneric {
    void baz(B obj) {
        obj.foo();
        obj.bar();
    }
}

What's the difference between these?

like image 934
Robert Mangini Avatar asked Apr 17 '20 01:04

Robert Mangini


2 Answers

In your examples there is no practical difference.

The main practical difference is when you have return types using the generic.

But even without that, Generic<T extends B> and NonGeneric are not the same, because if we have class C extends B, then Generic<C> is not the same as NonGeneric, since the NonGeneric would allow non-C objects in the call to baz, and that's wrong.

like image 122
Andreas Avatar answered Sep 22 '22 05:09

Andreas


In Generic class baz function only accept T type value but in NonGeneric class you can give any object those can cast to B. Example:

public class Main {

    public static void main(String[] args) throws Exception {
        Generic<C> generic = new Generic<C>();
        generic.baz(new B()); // error
        generic.baz(new C()); // works fine
        generic.baz(new D()); // error
        NonGeneric nonGeneric = new NonGeneric();
        nonGeneric.baz(new B()); // works fine
        nonGeneric.baz(new C()); // works fine
        nonGeneric.baz(new D()); // works fine
    }

    static class A {
        void foo() {}
    }

    static class B extends A {
        void bar() {}
    }

    static class C extends B {}

    static class D extends B {}

    static class Generic<T extends B> {
        void baz(T obj) {
            obj.foo();
            obj.bar();
        }
    }

    static class NonGeneric {
        void baz(B obj) {
            obj.foo();
            obj.bar();
        }
    }
}
like image 23
SMortezaSA Avatar answered Sep 24 '22 05:09

SMortezaSA