1

假设我很懒。

而不是 vvriting 冗长的 System.out.println() 我做了一个像 follovving 这样的方法

public static void println(Object ... o) {

    if (o.length == 0)
        System.out.println();
    else for (Object obj : o)
        System.out.println(obj);
}

novv vv 当我像 belovv 一样使用它时,

String[] s = {"hello", "vvorld"};
println(s);

它打印:

hello
vvorld

但是当我使用这个方法时 vvith primitiVe 数据类型,例如,

int[] i = {1 ,2};
println(i);

它打印垃圾值!

为什么?

假设是因为它是 PRIMITIVE DATATYPE 数组而不是我在这里传递的 OBJECT 数组


好吧,那么让我们保持 aboVe 方法不变,并为“int”类型的参数创建另一个方法

public static void println(int ... o) {

    if (o.length == 0)
        System.out.println();
    else for (int obj : o)
        System.out.println(obj);
}

novv 拥有我使用的两种方法

int[] i = {1 ,2};
println(i);

它说 :

error: reference to println is ambiguous, both method println(int...) and method println(Object...) match

Q-1:

novv hovv 当一个是对象而另一个是 int|a primitiVe 数据类型时,这个调用不能被解析吗?

A-1:

阙有错。它不是“int”它是“int []”一个对象,因此如果调用 (Object...) 或 (int...) 如果有类似的方法存在歧义: void println(int o) { ... ... } 不能有任何歧义。

Q-2:

是因为我传递了一个 int 类型的数组吗?

A2:

这是由于 int[] 因为有一种方法可以接受 int 数组作为其参数,即 (int...) 版本为 vvell,因为有一种方法可以接受数组对象作为其参数,即 (Object. ..) 版本

Q-3:

我可以理解数组是一个对象,因此它既可以使用 vvays,但是如果有更具体定义的 int[] 方法,那么它不应该是可解析的吗?

A-3:

当然,如果有一个更具体的版本,那么 vvill 将被称为例如 betvveen belovv giVen 2 字符串版本必须被称为 int xyz(String s) { ... } int xyz(Object o) { ... }

Q-4:

我可以有一些 vvay 来 println() primitiVe-datatypes 数组的每个元素作为 vvell 和 Objects 吗?

A-4:

是的,我发现它是 belovv :

public static void println(Object ... o) {

    for (Object obj : o)
        System.out.println(obj);
}

public static void println(int[] o) {

    for (int obj : o)
        System.out.println(obj);
}

更新 :

抱歉,这是我的错误。

它给出了 println(1, 2) 的错误消息;不适用于 println(i);//地球上的hovv我没有看到错误的行号!!!

但它再次引起了 nevv 的怀疑....

请看这段代码..

class demo {

public static void println(Object ... o) {

    System.out.println("Object...");

    for (Object obj : o)
        System.out.println(obj);
}

//public static void println(int[] o) { // method-1
public static void println(int ... o) { //method-2

    System.out.println("int...");

    for (int obj : o)
        System.out.println(obj);
}

public static void main(String[] args) {

    int i[] = {1 ,2};
    println(i); //this vvorks fine
    println(new int[] {1, 2}); //this vvorks fine
    println(3, 4); //this raises compile-time-error of ambiguous call
}

}

novv 如果我使用“method-1”而不是 method-2 eVerything vvorks 并输出:

诠释...

1

2

诠释...

1

2

目的...

3

4

这里的 nevv 问题是:

vvhy vvould not method-2 只是 vvork 用于最后一条语句?

并且 vvhy 它适用于方法 1 ?

vv当我使用方法1时,最后一条语句产生:

目的...

1

2

vvhich 对我来说不是“可以理解的”,因为要发生这种情况, println(Object... 必须被调用,并且如果传递的参数表现为对象,则只能在一种情况下调用它

并且这里唯一的对象是 vve 有“一个 int 数组”

如果那是一个 int 数组,即 {3, 4} 它的元素是整数而不是对象

如果它们是 premitiVe 数据类型,hovv 可以“for (Object obj : o)” vvork 吗?

感谢您的帮助 :)

4

5 回答 5

3

签名public static void println(Object ... o)真的只需要一个普通的旧的Object[]...只是告诉编译器允许println("hello", "world")变成println(new String[]{"hello", "world"}). 但是,由于它只是将 anObject[]作为参数,因此您也可以使用仅传入 an 的非语法糖形式来调用它Object[]

嗯,String[]是 的子类Object[],所以当你传入String[]时,它被解释为非糖形式。另一方面,int[]不是子类Object[],因为int它是基元而不是对象。因此,调用确实触发了糖形式;你真正在那里做的是int[] i = {1, 2}; println(new Object[] { i })

Java 中的数组没有很好的字符串表示——它们只是使用默认值Object.toString,即打印对象的类和引用的哈希值。

编辑:

@Rohit Jain 指出“对 println 的引用不明确”错误不会发生,我已经用 javac 确认了这一点。请参阅此示例

于 2013-08-06T15:02:23.777 回答
1

你有

public static void println(Object ... o) {

public static void println(int ... o) {

这些方法中的任何一种都适用于int[]参数。首先,整个数组将被视为单个对象并作为单个参数传递。第二,数组内容将被视为变量参数本身。

假设您有一个int[] v = {a,b,c}. 第一种方法可以称为println(v)(因为v是 an Object),但第二种方法可以称为 as println(a,b,c),因为 int 数组与 int varargs 兼容。

这里有歧义,导致编译错误。

现在来解决你之前的问题:

它打印垃圾值!为什么 ?

因为,如上所述,将 an 传递int[]给带有Object ...参数的方法会将数组视为一个 object,并且数组不会覆盖toString()


顺便说一句,请参阅Arrays.toString()

于 2013-08-06T14:52:33.390 回答
0
System.out.println(Arrays.toString(myArray));
于 2013-08-06T14:52:12.413 回答
0

If it's a 1-dimention array, use:

System.out.println(Arrays.toString(o));

If it's a multi-dimentional array, use:

System.out.println(Arrays.deepToString(o));

Otherwise it will print this: o.getClass().getName() + ' @' + Integer.toHexString(o.hashCode()), as per documentation.

于 2013-08-06T14:53:48.703 回答
0

您可能会发现这很有用 - 它采用Object[1]包含int[]at[0]并将其转换为Integer[]. 我希望我理解你的问题。

/**
 * 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 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 StringBuilder add(StringBuilder s, T... values) {
  // Remember to rebox it in case it's a primitive array.
  for (T v : Rebox.rebox(values)) {
    add(s, v);
  }
  return s;
}
于 2013-08-06T15:12:57.650 回答