tags:

views:

87

answers:

6

Defining a method as

myMethod(Object... obj){}

allows arbitrary number and types of parameters to be used.

I'd love to use generics for strict definition of the number and types of parameters.

For example, Let's assume that the above mentioned myMethod(Object...) is a method in a class named MyClass and MyClass can be instantiated by default constructor.

I need to define instances in a way similar to this:

MyClass<Integer, Integer, String> instance1 = new MyClass<Integer, Integer, String>();
MyClass<String, String, Integer, Integer> instance2 = new MyClass<String, String, Integer, Integer>();

so the type definitions above will set the number and types of parameters allowed on calls to myMethod():

instance1.myMethod(1, 2, "test");
instance2.myMethod("one", "two", 1, 2);

The question is: How to define MyClass in such a way that will allow any number of type parameters?

Any advice will be appreciated.

A: 

You could try this :

Class type : MyClass <List<?>>

Ritz
That was my first thought too, but it doesn't allow type-safe heterogenous list elements - which is ultimately the crux of the question.
Andrzej Doyle
+3  A: 

I don't think what you're trying to do can be achieved, but perhaps you could give some indication of what myMethod() does?

harto
A: 

You have to be content with myMethod(Object...). Instances of MyClass are not even aware of the parameter types at runtime.

fastcodejava
+1  A: 

You can't, number of type parameters is fixed per class. you can play crazy tricks

class Tuple
{ 
    Object[] objects() { return ...; }
}
class Tuple1 ...
class Tuple2 ...
class Tuple3<T1,T2,T3> extends Tuple
{
    static public<S1,S2,S3> Tuple3<S1,S2,S3> of(S1 o1, S2 o2, S3 o3){ return ...; }
}
class Tuple4<T1,T2,T3,T4> extends Tuple
{
    static public<S1,S2,S3,S4> Tuple4<S1,S2,S3,S4> of(S1 o1, S2 o2, S3 o3, S4 o4){ return ... ; }
}
...
class Tuple9 ...

class MyClass<TupleN extends Tuple>
{
    void myMethod(TupleN ntuple)
    {
        Object[] objects = ntuple.objects();
        // work on objects
    }
}

MyClass<Tuple3<Integer,Integer,String>> instance3 = new MyClass<Tuple3<Integer, Integer, String>>();
instance3.myMethod( Tuple3.of(1,2,"test") );

It's not worth it. Sometimes you have to give up extraneous type checking for simplicity.

irreputable
now I kind of like this tuple idea, your fault! The `of` methods can all be moved into `Tuple` class to write `Tuple.of(1,2,"test")`
irreputable
So far this seems to be the best option and I'll examine using it. If I do I will accept this answer.What's the purpose?! I have a useful (so I think) decoration of java.sql.PreparedStatement which can be used in the following way: aPreparedStatement.executeUpdate(param1, param2, param3);and I want the parameters given to this method to be constrained by the instance declaration, similar to what is done with generic types.
Joel
well, why declare a type safe instance `stmtBlah`, while you can declare an old fashion method, which is of course type safe, `updateBlah(Integer,Integer,String)`.
irreputable
+2  A: 

What's the point? I can't imagine a scenario where this would be useful, and be the best solution available. I'm not trying to be derogatory, but it's worth mentioning that you should subscribe to the KISS principle. Sounds like you're falling victim to over-engineering, and it's creating code smell.

An alternative design pattern that might serve useful is the Builder pattern. The wiki page examples aren't that great, but you should read the Effective Java section about Builders. A builder will help create an immutable object constructed with required and/or optional parameters by chaining mutator methods together and calling a private constructor via a builder method:

public class MyClass {

    private final String string1;
    private final String string2;
    private final int int1;
    private final int int2;

    private MyClass(Builder builder) {
     this.string1 = builder.string1;
     this.string2 = builder.string2;
     this.int1 = builder.int1;
     this.int2 = builder.int2;
    }

    public String getString1() {
     return string1;
    }

    public String getString2() {
     return string2;
    }

    public int getInt1() {
     return int1;
    }

    public int getInt2() {
     return int2;
    }

    public static class Builder {
     private String string1;
     private String string2;
     private int int1;
     private int int2;

     // set required parameters in the constructor
     public Builder() { }

     public Builder string1(String string1) {
      this.string1 = string1;
      return this;
     }

     public Builder string2(String string2) {
      this.string2 = string2;
      return this;
     }

     public Builder int1(int int1) {
      this.int1 = int1;
      return this;
     }

     public Builder int2(int int2) {
      this.int2 = int2;
      return this;
     }

     public MyClass build() {
      return new MyClass(this);
     }
    }
}

You would construct an object like this:

MyClass myClass = new MyClass.Builder().string1("sample1").string2("sample2").int1(1).int2(2).build();

Or (using the same class)

MyClass myClass = new MyClass.Builder().string1("sample1").int1(1).build();

These are horrible method names, but I'm going off your hypothetical scenario.

Droo
+1 using a Builder seems like a more appropriate approach.
harto
+2  A: 

What you're describing is a type-safe heterogeneous list.

Here's one I wrote earlier.

Apocalisp
the call site is quite ugly when you have 3 or 4 arguments, `MyClass<X<Integer,X<Integer,X<String,END>>>> instance3` and `instance3.call(x(1,x(2,x("test",END))))`. I like my Tuple idea better
irreputable
The reservation is in place but I still think this is not a bad idea at all! I will consider using this. There might be many many parameters when we speak of a prepared statement and simplicity is a consideration here.
Joel