简体   繁体   中英

Java varags not detect when call vararg method inside another vararg method

I have implemented Java methods to resolve IN and OR condition.

Below is my code.

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));
}

Output is:

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

But I was expecting the following output:

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

I don't understand why varargs size in 1 in in method.

In the method

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

When you are passing a boolean array values , the whole array is taking as a single element T That's the reason for showing it 1 .

You are passing boolean array and the receiving type is T , where each element considering as an array.

You can print the values inside in method and see what is the result. Youl' see an array object. Not the individual boolean elements.

When you are entering or , the boolean... values parameter gets converted to an array of boolean . Then, when you call in(true, values) , the second parameter of in is actually an array of the primitive type boolean (so a single value). The actual problem is that Java does not automatically box array of primitive types.

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));
}

You can tackle this problem by boxing your boolean to a Boolean object like this:

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));
}

Note that beginning with Java 7, this code will emit a warning that you can disable with the @SafeVarargs annotation.

I use a static tool to deal with this strange edge case.

/**
 * 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));
}

This prints:

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

as you require.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM