36

As everyone knows you can have a generic class in Java by using type arguments:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}

But you can also have generic constructors, meaning constructors that explicitly receive their own generic type arguments, for example:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

I'm struggling to understand the use case. What does this feature let me do?

0xbe5077ed
  • 4,565
  • 6
  • 35
  • 77
  • 11
    Maybe in situations like this: ` Bar(U a, U b)`? – Henry Dec 14 '17 at 05:37
  • 1
    This example is not very helpful. But generics would help you to establish contracts on arguments when U would have to extend another type or be an intersection type. (e.g. ) – M. Reif Dec 14 '17 at 05:50
  • 7
    Generic methods are useful. Constructors are similar to methods. It would be more effort to *forbid* generic constructors than to allow them, even if there's no particularly compelling use case. – Sebastian Redl Dec 14 '17 at 09:54
  • 5
    Tip: if you _can_ do something it doesn't mean you _should_ do it. – Alma Do Dec 14 '17 at 10:31
  • Also see https://stackoverflow.com/a/18176765/1398418 your question is almost a duplicate, there is no difference between a generic constructor and a generic method that doesn't return anything. – Oleg Dec 14 '17 at 20:39
  • 2
    See [javafx.animation.KeyValue](https://docs.oracle.com/javase/9/docs/api/javafx/animation/KeyValue.html#constructor.summary). You can require multiple arguments to apply to consistent types. – VGR Dec 14 '17 at 21:06

5 Answers5

24

The use case I'm thinking of might be that some wants an Object which inherits from 2 Types. E.g. implements 2 interfaces:

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}

Though I have never used it in production.

Lino
  • 19,604
  • 6
  • 47
  • 65
  • 1
    This is a good example. I didn't think of it! Although strictly speaking you can also solve this with `interface BarBaz extends Bar, Baz` or similar, this is probably a nicer way of saying the same. But it's, funnily enough, more *weakly* typed since there's no runtime type. – 0xbe5077ed Dec 15 '17 at 02:15
  • @0xbe5077ed exactly, and because the runtime type is unknown, or just not even really needed, this is more dynamic – Lino Dec 15 '17 at 06:50
19

It's clear in the example you provided that U does not play any role in the class' constructor, as it effectively becomes an Object at runtime:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

But let's say that I wanted my constructor to only accept types that extend some other class or interface, as seen below:

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}

Notice that the class already has a different generic type in use; this allows you to utilize a separate, unrelated generic type to the class definition.

Granted, I've never used something like this, and I've never seen it in use, but it's possible!

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 21
    If all you need to know is that `u` is a `Bar`, then isn't it better practice to simply do `Foo(Bar u) {}`? I completely agree with your idea of being generic over descendants of `Baz` though - a good example is `` for comparison-based-ordered data structures, like search trees – musicman523 Dec 14 '17 at 09:02
  • 6
    ` Foo(U u)` where Bar and Baz are not related (eg two interfaces, both of which are required by the constructor). – Draco18s no longer trusts SE Dec 14 '17 at 17:17
  • Yes, that would have been better. – Jacob G. Dec 14 '17 at 17:18
  • @Draco18s if `Bar` and `Baz` are interfaces in the context of your example, would you still use `extends` and not `implements`? – musicman523 Dec 25 '17 at 01:35
  • @musicman523 Yes, as `implements` is not the appropriate keyword, and will not compile. – Jacob G. Dec 25 '17 at 01:36
  • @musicman523 [Yes, I'm sure](https://github.com/Draco18s/ReasonableRealism/blob/master/src/main/java/com/draco18s/hardlib/EasyRegistry.java#L32) – Draco18s no longer trusts SE Dec 25 '17 at 02:23
  • Thanks for the clarification both of you. From a language design standpoint, I'm curious about the reason that decision was made...maybe because `U` is a generic **interface** and not a **class**? – musicman523 Dec 26 '17 at 04:22
15

What does this feature let me do?

There are at least three two things it lets you do that you could not otherwise do:

  1. express relationships between the types of the arguments, for example:

    class Bar {
        <T> Bar(T object, Class<T> type) {
            // 'type' must represent a class to which 'object' is assignable,
            // albeit not necessarily 'object''s exact class.
            // ...
        }
    }
    
  2. <withdrawn>

  3. As @Lino observed first, it lets you express that arguments must be compatible with a combination of two or more unrelated types (which can make sense when all but at most one are interface types). See Lino's answer for an example.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • 1
    Isn't example 2 just going to deduce `T` as `Object` for unrelated types, thus letting anything through? – user2357112 Dec 14 '17 at 18:45
  • @user2357112, if you rely on type inference and have nothing else by which to constrain it, then yes, `Object` can be the type inferred in case 2. Placing a lower bound is more interesting when there are other constraints in play alongside it. – John Bollinger Dec 14 '17 at 18:51
  • The second case doesn't compile, you can't use a lower bound this way. – Oleg Dec 14 '17 at 19:16
  • Ok, @Oleg, item 2 is withdrawn. – John Bollinger Dec 14 '17 at 19:27
  • @JohnBollinger, I think you nailed it with #1. It occurred to me that collections are probably the *natural* use case, but #1 is just as valid. See also my answer somewhere else on this thread. – 0xbe5077ed Dec 15 '17 at 02:26
10

Actually, this constructor

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

is just like a generic method. It would make a lot more sense if you had multiple constructor arguments like this:

class Bar {
    <U> Bar(U you, List<U> me) {
        // Why!?
    }
} 

Then you could enforce the constraint, that they have the same time with the compiler. Without making U a generic for the whole class.

keuleJ
  • 3,418
  • 4
  • 30
  • 51
  • 4
    The compiler could decide to insert Object as U to solve the problem, in what case you can still pass an int and a string object. – Ferrybig Dec 14 '17 at 08:45
  • 4
    But note that unless you specify the type argument explicitly when you invoke the example constructor, Java can infer `U` to be `Object`, thus placing no restriction. – John Bollinger Dec 14 '17 at 17:23
  • I get that it's like a generic method, in fact it *is* a generic method with a special name, ``. But for a generic method, usually you're dealing with a `static` method in practice since for the main, instance methods can usually do what they need using the "genericness" they "inherit" from the class. I was wondering what you could possibly do with a generic constructor since constructors mainly initialize *class* state and it's hard to imagine scenarios where you set *class* state based on a generic dimension that's not available to the class... – 0xbe5077ed Dec 15 '17 at 02:29
  • 1
    @keuleJ, I think you're misunderstanding what @JohnBollinger is saying. The point is that `javac` your example is 100% identical *both* at compile time *and* at runtime to `Bar(Object you, Object me)`. So the generic parameter is redundant and slightly confusion-inducing. Whereas there are many uses of generic parameters that actually express meaningful constraints that can be statically verified at compile time. – 0xbe5077ed Dec 15 '17 at 02:32
8

Because that unbound generic type erases to Object, it'd be the same as passing Object in your constructor:

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}

...but like passing a blank Object, unless you're doing something clever, this has little practical value.

You see benefits and wins if you pass in bound generics instead, meaning that you can actually have guarantees around the type that you care about.

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}

Effectively, this is more about flexibility than it being something revolutionary. If you want the flexibility to pass in a specific category of types, then you have the power to do so here. If you don't, then there's nothing wrong with standard classes. It's merely here for your convenience, and since type erasure is still a thing, an unbound generic is the same (and has the same utility) as passing Object.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • 2
    The OP seems focused on the generic constructor in his class `Bar`, having presented the generic class `Foo` primarily for contrast. Though everything in this answer appears to be correct, I'm having trouble seeing how it responds to the generic constructor issue. – John Bollinger Dec 14 '17 at 17:29