Generic with Variable Type Arguments

20,342

Solution 1

Since you apparently want to be able to make bar take multiple parameters of different types (something varargs are not used for), I'd suggest making it instead take a single parameter. You can then make that single parameter be a container that holds each of the individual "parameters" you want to use.

In general, it would be best to make a class for each set of parameters you want to use with this method so that you have good names for each of the objects it contains. However, you could also do something like creating a series of tuple types (such as Pair) to use as holders.

Here's an example:

public class Foo<R, P> {
  /*
   * Not sure how you intend to provide any kind of implementation
   * here since you don't know what R or P are.
   */
  public R bar(P parameters) { ... }
}

public class SomeFoo extends Foo<SomeResult, Pair<Baz, Bar>> {
  public SomeResult bar(Pair<Baz, Bar> parameters) { ... }
}

SomeFoo foo = ...
SomeResult result = foo.bar(Pair.of(baz, bar));

Solution 2

You wrote:

I want to use it (or something similar) to have my method accept several arguments, each of which is a member of a given different class.

I don't think it's possible to do this in a type-safe way without some ugly hacks, like including an instance of Class along with the object.

The problem is, that with VarArgs you're actually being passed in an Array. But you can't have an array with different types of objects in it, they all have to be the same (or subclasses, so if you have X[] y then each element must be a subclass of X)

If your function can really deal with multiple types you could create something like a class that stores an instance of Class along with an instance of T, and the pass in a var args list of that container.

So for example you could have

class TypedInstance<T>{
   Class<T> type;
   T instance;
}

and then have a function that looks something like

public whatever(TypedInstance<? extends Object>... whatever){
  ...
  doSomethingWith(whatever[0].type, whatever[0].instance);
  ...
}

These kinds of hacks are needed because of Java's type erasure. The generic parameter gets removed at runtime, so if you want to use it, you have to put it back.

Share:
20,342
Aaron J Lang
Author by

Aaron J Lang

Updated on January 04, 2020

Comments

  • Aaron J Lang
    Aaron J Lang over 4 years

    I want to do something like

    public interface Foo<R, P...> {
        public R bar(P...) {/*misc*/}
    }
    

    to get an array of types to use in my bound implementation. Is this possible in java?

    Varargs is designed to let me have any number of arguments of a given class.

    I want to use it (or something similar) to have my method accept several arguments, each of which is a member of a given different class. These classes are defined when the generic is bound.

    I aware there are work arounds, but is there a type-safe way to do this?

  • Aaron J Lang
    Aaron J Lang over 12 years
    +1 Good idea, but the function never uses P. There's no type-safety for the parameter types other than that they have to extend Object. The type of 'instance' can be acquired by instance.getClass(); basically you're wrapping an instance of type T in a wrapper<T>, which is a little pointless.
  • Aaron J Lang
    Aaron J Lang over 12 years
    I think this is a good idea, it allows the binding class to define the number and type of arguments, by wrapping them in a container/tuple object. Are tuple/pair part of the core libraries/jdk ? I couldn't find them, although I'd imagine it'd be trivial to write my own. Would I be correct to suggest that tuples in java fulfil exactly the role of structs in c?
  • ColinD
    ColinD over 12 years
    In general I would avoid making tuple types (they don't exist in the JDK because they just don't work well for various reasons) and make real classes that give each contained object a useful name. I mostly just mentioned that because it's close to what you seemed to be requesting and because it is an option that you have. The short answer is that if you want to group an arbitrary number of objects of arbitrary types, a class is the way to go. You could make a class very small and simple and have it basically act as a struct.
  • Chad Okere
    Chad Okere over 12 years
    True, but there is no real way of doing this directly... although Colin D's idea of using nested tuples is pretty brilliant. Reminds me of the way things are done in Scheme/lisp.
  • AJMansfield
    AJMansfield over 10 years
    Eclipse actually has a feature for automatically doing this: refactor > introduce parameter object