In Java, can I specify any amount of generic type parameters?

前端 未结 3 1361
野的像风
野的像风 2021-01-17 16:14

I am looking to create a particular type of interface in Java (although this is just as applicable to regular classes). This interface would need to contain some me

相关标签:
3条回答
  • 2021-01-17 16:38

    No, there is nothing like that directly available. However if you use a library with Tuple classes you can simulate it by just making the interface

    interface Foo<T> {
        void invoke(T t);
    }
    

    (This interface is essentially the same as Consumer<T>.)

    Then you could do for example

    Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() {
        ...
    }
    

    You would need a separate Tuple type for each number of parameters. If you have a Tuple class for 4 parameters, but not one for 5, you could squeeze an extra parameter in by using a Pair class.

    Foo<Tuple<String, Integer, Date, Pair<Long, BigDecimal>>> foo = ...
    

    By nesting tuple types in this way you get an unlimited number of parameters. However, these workarounds are really ugly, and I would not use them.

    0 讨论(0)
  • 2021-01-17 16:40

    Is anything like this available? I have read about variadic templates in C++, but cannot find anything similar in Java. Is any such thing available?

    No, this feature is not available in Java.

    0 讨论(0)
  • 2021-01-17 16:40

    Given the context you provided I would recommend using a List as a parameter. If these parameters have something in common, you can restrain your list to <T extends CommonParrent> instead of using List<Object>. If not, you may still want to use marker interface.

    Here is an example.

    public class Main {
    
        public static void main(String[] args) {
            delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15)));
        }
    
        private static <T extends Parent> void delegate(List<T> list) {
            list.forEach(item -> {
                switch (item.type) {
                    case ONE: delegateOne((ChildOne) item); break;
                    case TWO: delegateTwo((ChildTwo) item); break;
                    default: throw new UnsupportedOperationException("Type not supported: " + item.type);
                }
            });
        }
    
        private static void delegateOne(ChildOne childOne) {
            System.out.println("child one: x=" + childOne.x);
        }
    
        private static void delegateTwo(ChildTwo childTwo) {
            System.out.println("child two: abc=" + childTwo.abc);
        }
    
    }
    
    public class Parent {
        public final Type type;
    
        public Parent(Type type) {
            this.type = type;
        }
    }
    
    public enum Type {
        ONE, TWO
    }
    
    public class ChildOne extends Parent {
        public final int x;
    
        public ChildOne(int x) {
            super(Type.ONE);
            this.x = x;
        }
    }
    
    public class ChildTwo extends Parent {
        public final int abc;
    
        public ChildTwo(int abc) {
            super(Type.TWO);
            this.abc = abc;
        }
    }
    

    The biggest flaw of this solution is that children have to specify their type via enum which should correspond to the casts in the switch statement, so whenever you change one of these two places, you will have to remember to change the other, because compiler will not tell you this. You will only find such mistake by running the code and executing specific branch so test driven development recommended.

    0 讨论(0)
提交回复
热议问题