【问题标题】:Java varags not detect when call vararg method inside another vararg method当在另一个 vararg 方法中调用 vararg 方法时,Java varargs 不会检测到
【发布时间】:2015-09-08 08:08:40
【问题描述】:

我已经实现了 Java 方法来解析 IN 和 OR 条件。

下面是我的代码。

public static <T> boolean in(T parameter, T... values) {
    if (null != values) {
        System.out.println("IN values size.. " + values.length);
        return Arrays.asList(values).contains(parameter);
    }
    return false;
}

public static boolean or(boolean... values) {
    System.out.println("OR values size.. " + values.length);
    return in(true, values);
}

public static void main(String[] args) {
    System.out.println(or(false, true, false));
}

输出是:

OR values size.. 3
IN values size.. 1
false

但我期待以下输出:

OR values size.. 3
IN values size.. 3
true

我不明白为什么在in 方法中可变参数大小为 1。

【问题讨论】:

    标签: java methods variadic-functions


    【解决方案1】:

    在方法中

    in(T parameter, T... values) //in(true, values); // values is T
    

    当您传递布尔数组 values 时,整个数组将被视为单个元素 T 这就是显示它的原因 1

    您正在传递布尔数组,接收类型为T,其中每个元素都视为一个数组。

    你可以打印方法里面的值,看看结果如何。你会看到一个数组对象。不是单个布尔元素。

    【讨论】:

    • 谢谢。那么解决方案是什么。我的意思是循环内部的值,或者如果存在真实条件,则返回 true ?
    • @ChamlyIdunil 我猜你似乎永远不需要那个方法。您可以在 or 方法本身中编写该单行。如果您仍想维护该方法,请检查您的 in 方法中的元素类型。如果它是数组类型,则在该对象上循环并返回 if contains
    • 是的。谢谢。但仍然是重复的事情。同样的东西写在两个地方对吧?
    • 但是当它使用单一方法时会发生同样的问题。即使我使用 return Arrays.asList(values).contains(Boolean.TRUE);当我将该方法称为 or(false, true, false) 时,它返回 false。
    【解决方案2】:

    当您输入or 时,boolean... values 参数将转换为boolean 的数组。那么,当你调用in(true, values)时,in的第二个参数实际上是一个原始类型boolean的数组(所以是一个值)。实际的问题是 Java 不会自动装箱原始类型数组。

    public static boolean or(boolean... values) {
        System.out.println("OR values size.. " + values.length);
        // here values is an array of the primitive boolean
        return in(true, values);
    }
    
    public static void main(String[] args) {
        System.out.println(or(false, true, false));
    }
    

    您可以通过将boolean 装箱到Boolean 对象来解决这个问题,如下所示:

    public static <T> boolean in(T parameter, T... values) {
        if (null != values) {
            System.out.println("IN values size.. " + values.length);
            return Arrays.asList(values).contains(parameter);
        }
        return false;
    }
    
    public static boolean or(boolean... values) {
        System.out.println("OR values size.. " + values.length);
        Boolean[] boxedValues = new Boolean[values.length];
        for (int i = 0; i < values.length; i++) {
            boxedValues[i] = values[i];
        }
        return in(true, boxedValues);
    }
    
    public static void main(String[] args) {
        System.out.println(or(false, true, false));
    }
    

    请注意,从 Java 7 开始,此代码将发出警告,您可以使用 @SafeVarargs 注释禁用该警告。

    【讨论】:

    • 谢谢。那么解决方案是什么。我的意思是循环内部的值,或者如果存在真实条件,则返回 true ?
    • 不幸的是,我们使用的是 Java 1.6。也因为我们在侧边循环值 OR 我们可以在有真值时返回真,而不是拥有另一个布尔数组并调用 IN 方法。
    【解决方案3】:

    我使用静态工具来处理这种奇怪的边缘情况。

    /**
     * Can rebox a boxed primitive array into its Object form.
     *
     * Generally I HATE using instanceof because using it is usually an indication that your hierarchy is completely wrong.
     *
     * Reboxing - however - is an area I am ok using it.
     *
     * Generally, if a primitive array is passed to a varargs it is wrapped up as the first and only component of an Object[].
     *
     * E.g.
     *
     * public void f(T... t) {}; f(new int[]{1,2});
     *
     * actually ends up calling f with t an Object[1] and t[0] the int[].
     *
     * This unwraps it and returns the correct reboxed version.
     *
     * In the above example it will return an Integer[].
     *
     * Any other array types will be returned unchanged.
     *
     * @author OldCurmudgeon
     */
    public static class Rebox {
    
        public static <T> T[] rebox(T[] it) {
            // Default to return it unchanged.
            T[] result = it;
            // Special case length 1 and it[0] is primitive array.
            if (it.length == 1 && it[0].getClass().isArray()) {
                // Which primitive array is it?
                if (it[0] instanceof int[]) {
                    result = rebox((int[]) it[0]);
                } else if (it[0] instanceof long[]) {
                    result = rebox((long[]) it[0]);
                } else if (it[0] instanceof float[]) {
                    result = rebox((float[]) it[0]);
                } else if (it[0] instanceof double[]) {
                    result = rebox((double[]) it[0]);
                } else if (it[0] instanceof char[]) {
                    result = rebox((char[]) it[0]);
                } else if (it[0] instanceof byte[]) {
                    result = rebox((byte[]) it[0]);
                } else if (it[0] instanceof short[]) {
                    result = rebox((short[]) it[0]);
                } else if (it[0] instanceof boolean[]) {
                    result = rebox((boolean[]) it[0]);
                }
            }
            return result;
        }
    
        // Rebox each one separately.
        private static <T> T[] rebox(int[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Integer.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(long[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Long.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(float[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Float.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(double[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Double.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(char[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Character.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(byte[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Byte.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(short[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Short.valueOf(it[i]);
            }
            return boxed;
        }
    
        private static <T> T[] rebox(boolean[] it) {
            T[] boxed = makeTArray(it.length);
            for (int i = 0; i < it.length; i++) {
                boxed[i] = (T) Boolean.valueOf(it[i]);
            }
            return boxed;
        }
    
        // Trick to make a T[] of any length.
        // Do not pass any parameter for `dummy`.
        // public because this is potentially re-useable.
        public static <T> T[] makeTArray(int length, T... dummy) {
            return Arrays.copyOf(dummy, length);
        }
    }
    
    public static <T> boolean in(T parameter, T... values) {
        if (null != values) {
            System.out.println("IN values size.. " + values.length);
            return Arrays.asList(values).contains(parameter);
        }
        return false;
    }
    
    public static boolean or(boolean... values) {
        System.out.println("OR values size.. " + values.length);
        return in(true, Rebox.rebox(values));
    }
    
    public void test() {
        System.out.println(or(false, true, false));
    }
    

    打印出来:

    OR values size.. 3
    IN values size.. 3
    true
    

    如你所愿。

    【讨论】:

      猜你喜欢
      • 2012-01-08
      • 2018-12-11
      • 2018-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      相关资源
      最近更新 更多