题目:
public class Demo {
public static void main(String[] args) {
char a[]=new char[]{'a','b','c'};
char b='a';
int c[]=new int[]{1,2};
int d=1;
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
}
输出:
abc
a
[I@4eec7777
1
详解:
1. char a[]
当打印字符串char a[]的时候,调用的println()方法为:
public void println(char[] x) {
if (getClass() == PrintStream.class) {
writeln(x);
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
其中的writeln()方法为:
private void writeln(char[] buf) {
try {
synchronized (this) {
ensureOpen();
textOut.write(buf);
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
这里调用的write()方法为:
public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}
即,在最初println()方法中传入了整个字符数组,并在write()方法中依次打印出来。
2. char b
当打印字符char b的时候,调用的println()方法为:
public void println(char x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
相比于打印字符串,这里使用了valueOf()方法:
public static String valueOf(char c) {
if (COMPACT_STRINGS && StringLatin1.canEncode(c)) {
return new String(StringLatin1.toBytes(c), LATIN1);
}
return new String(StringUTF16.toBytes(c), UTF16);
}
这段代码是 Java 中的Srting类的valueOf()方法实现:它接受一个字符c作为参数,并返回该字符的字符串表示。
valueOf原理:该方法的第一部分检查常量COMPACT_STRINGS是否为真,以及使用StringLatin1.canEncode()方法判断给定字符c是否能够使用StringLatin1编码进行编码。
如果这两个条件都成立,则使用StringLatin1.toBytes()方法将字符转换为Latin-1编码的字节数组,并使用接受字节数组和Charset对象的String构造函数创建一个使用 Latin-1 编码的String对象。
如果任一条件失败,则使用StringUTF16.toBytes()方法将字符转换为字节数组,然后使用相应的String构造函数创建一个使用 UTF-16 编码的String对象。
当已经转换为String后,调用writeln()方法如下:
private void writeln(String s) {
try {
synchronized (this) {
ensureOpen();
textOut.write(s);
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
此处的write()方法为:
public void write(String str) throws IOException {
write(str, 0, str.length());
}
即,从头到尾将String打印出来。
3. int c[]
当打印字符int c[]的时候,因为int []并没有重写自己的println()方法,所以调用的object类的println()方法:
public void println(Object x) {
String s = String.valueOf(x);
if (getClass() == PrintStream.class) {
// need to apply String.valueOf again since first invocation
// might return null
writeln(String.valueOf(s));
} else {
synchronized (this) {
print(s);
newLine();
}
}
}
同样,这里调用的valueOf()方法,仍然是Object类的valueOf()方法:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
由于这里调用的是以Object对象为参数的valueOf()方法,可明显看出与打印字符时的valueOf()方法有明显区别:
public static String valueOf(char c) {
if (COMPACT_STRINGS && StringLatin1.canEncode(c)) {
return new String(StringLatin1.toBytes(c), LATIN1);
}
return new String(StringUTF16.toBytes(c), UTF16);
}
尽管二者都是将输入的内容以一种方式转化为String类型数据,但是有本质区别。
最初的、未被重写过的valueOf()方法,即Object类的valueOf()方法为:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
即,得到的String类型数据为:输入内容的数据类型+@+根据输入内容而形成的哈希码值。
而不是像valueOf(char c)方法中直接以StringLatin1编码规则转换成形式上与输入内容相同的字符串。
因此,当打印int数组时:
public class Demo {
public static void main(String[] args) {
int c[]=new int[]{1,2};
System.out.println(c);
}
}
输出:
[I@4eec7777
I:int类型
@:@
4eec7777:对应哈希码
如果想让int数组按我们想要的结果打印,可以用Arrays类的toString()方法:
public class Demo {
public static void main(String[] args) {
int c[]=new int[]{1,2};
System.out.println(Arrays.toString(c));
}
}
输出:
[1,2]
这是因为,在Arrays类中,toString()方法被重写:
public static String toString(int[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
使输入的int数组以一种标准形式输出。
4. int
当打印int d的时候,调用的println()方法为:
public void println(int x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
其中使用重写了的valueOf()方法:
public static String valueOf(int i) {
return Integer.toString(i);
}
调用了Integer类的toString()方法:
public static String toString(int i) {
int size = stringSize(i);
if (COMPACT_STRINGS) {
byte[] buf = new byte[size];
getChars(i, size, buf);
return new String(buf, LATIN1);
} else {
byte[] buf = new byte[size * 2];
StringUTF16.getChars(i, size, buf);
return new String(buf, UTF16);
}
}
Integer类中的toString()方法分为两个分支,具体的分支取决于Java版本和是否启用了紧凑字符串(Compact Strings)的特性。
Compact:
(n)契约、协定
(adj)紧凑的,小型的
如果启用了紧凑字符串特性,将创建一个指定长度的字节数组(buf),并调用getChars()方法将整数 i 转换为一系列字节。然后,将这个字节数组转换为一个使用LATIN1编码的字符串并返回。
如果未启用紧凑字符串特性,将创建一个指定长度的字节数组(buf)并调用 StringUTF16.getChars() 方法将整数 i 转换为一系列 UTF-16 编码的字节。然后,将这个字节数组转换为一个使用 UTF-16 编码的字符串并返回。
因此,返回的内容是与输入内容形式上相同的String数据。
总结
使用println()打印char[]时:
println(char[] x) --> writeln(char[] buf) --> write(char cbuf[])。
调用的方法均是重写后的、以char[]为参数的方法,最终write(cbuf,0,cbuf.length)将数组从头到尾打印出来。
使用println()打印char时:
println(char x)--> valueOf(char c) --> writeln(String s)。
先调用重写后的、以char为参数的valueOf()方法,将char型数据根据StringLatin1编码规则转化为String类型数据,再用以String为参数的writeln()方法将String输出。
使用println()打印int[]时:
println(Object x) --> valueOf(Object obj) -->toString() --> writeln(String s)。
由于int[]没有对应的重写后的println()方法,因此,调用的均为Object类的方法,和最原始的toString()方法。即,将输入的int数据转化为“输入内容的数据类型+@+根据输入内容而形成的哈希码值”的String类型数据,再用以String为参数的writeln()方法将String输出。
使用println()打印int时:
println(int x) --> valueOf(int i) --> toString(int i) --> writeln(String s)。
调用重写后的、以int为参数的方法,将int型数据根据StringLatin1编码规则转化为String类型数据,再用以String为参数的writeln()方法将String输出。