开发者

Multiple object types for varargs in a method prototype?

I'm trying to write the prototype of a Java function that can be called with any number of i开发者_Go百科ntegers and strings:

myMethod(1, 2, 3, "Hello", "World"); // Valid call
myMethod(4, "foo", "bar", "foobar"); // Valid call

Ideally, I would like the ints and strings to be given in any order (and possibly mixed):

myMethod(1, "Hello", 2, "World", 3); // Valid call

I thought of using varargs, but there can be only one in the prototype. Another idea I've had is to use the following prototype:

public void myMethod(Object ... objs) { [...] }

...but I feel that there should be a compilation error in case it is called with something other than the expected types. Of course, a runtime check (instanceof) could be performed, but that wouldn't be a very elegant solution, would it?

How would you do it?


If you want it to be type safe, I'd go with this:

public myMethod(Thing<?>... thing) { ... }

And then create your Thing classes:

public interface Thing<T> {
    public T value();
}

public class IntThing implements Thing<Integer> {
    private final int value;

    public IntThing(int value) {
        this.value = value;
    }

    public Integer value() {
        return value;
    }
}

I'll leave it to your imagination to figure out how to write StringThing. Obviously, use a better name than "Thing", but I can't help you with that one.

You then make two static methods:

public static Thing<Integer> thing(int value) {
    return new IntThing(value);
}

public static Thing<String> thing(String value) {
    return new StringThing(value);
}

Then you wrap each object in a call to thing:

myMethod(thing(1), thing(2), thing(3), thing("Hello"), thing("World"));

Messy? Yup. Unfortunately, Java doesn't have the capability to hide this stuff away like other languages. Scala's implicit defs would help you here, but that comes with a whole barrel of other problems. Personally, I'd go with the instanceof checks, but this one will make sure your code is safe at compile-time.


There is no way in the Java programming language to get it to work so that you can pass an arbitrary number of strings and integers, and have the compiler give an error when you pass something else than a string or integer.


There is no way to use generics to match two types, eg

public <T extends String | Integer> void myMethod(T... objs); // You can't do this


The only possible solution to the problem you've described is the one that already stated, where the function takes in a varargs argument of type Object. This is due to the restriction in Java where there can only be one vararg in a method signature, and that it has to be the last parameter.

It's hard to say what an alternative elegant solution might be without knowing the details of what you intend myMethod to do.


(Workaround)

Add to your lib:

package mylib;

public class Lang {
    public static <T> T[] varargs (T...ts) {
        return ts;
    }
}

In your program:

package myprog;

import static mylib.Lang.*;

public class MyProg {

    public static void testfunc (Integer[] ints, String[] strs) {

        for (int i : ints)
            System.out.println(i);

        for (String s : strs)
            System.out.println(s);
    }

    public static void main (String[] args) {
        testfunc(
            varargs(1,2,3),
            varargs("Sophia", "Jacob")
        );
    }
}

(Breaking many coding style rules)


The syntax is allowed

public class Foo<T extends Number & List> {
  ...
}

The type variable T allow types that are subtypes of Number and List at same type (for example, types that implementing multiple interfaces).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜