文章目录
介绍
所有 Java 类继承于 Object。就算是你自己写的类,当没有声明继承类时,编译时也会自动导入 Object 类。
toString 是 Object 类的一个方法。用来方便字符串操作。
测试样例
首先来写几段代码,我也是因为对于他们有疑惑,才开始探究的。
import com.sun.deploy.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("this");
list.add("is");
list.add("ArrayList");
System.out.println("println list: "+list);
System.out.println("println list.toString(): "+list.toString());
String[] array = list.toArray(new String[0]);
System.out.println("println list.toArray().toString(): "+ array.toString());
System.out.println("println Arrays.toString(list.toArray()): "+ Arrays.toString(array));
String listStr = StringUtils.join(list," ");
System.out.println("println StringUtils.join(list,\"\"): "+listStr);
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(listStr.split(" ")));
System.out.println("listStr to ArrayList: "+arrayList);
}
}
输出:
println list: [this, is, ArrayList]
println list.toString(): [this, is, ArrayList]
println list.toArray().toString(): [Ljava.lang.String;@1b6d3586
println Arrays.toString(list.toArray()): [this, is, ArrayList]
println StringUtils.join(list,""): this is ArrayList
listStr to ArrayList: [this, is, ArrayList]
println list.toArray().toString(): [Ljava.lang.String;@677327b6
如果你不懂的话,你肯定有疑惑(对我也是)。
直接看看源码
Object → toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Object 的 toString 很简单,不是用来转字符串的,而是返回一个 类名 + 对象的哈希码。
这个倒是和 输出的 list.toArray().toString() 一样。
println list.toArray().toString(): [Ljava.lang.String;@1b6d3586
为啥呢?
list.toArray() 得到的是 String 数组。奈何这个是 String 数组。我从 IDEA 看不到 String 数组的代码。String 倒是重写了 toString()。
String → toString()
/**
* This object (which is already a string!) is itself returned.
*
* @return the string itself.
*/
public String toString() {
return this;
}
Java 数组 → toString()?
我去查了下,Java 中 数组 是一种引用类型,也是一种类,但是它没有代码,看不到底层实现,因为是底层 C 语言实现的,(应该是在 JVM 的 native 库里面)。
但是根据这个结果 推断,native 内的 String 数组是没有重写 toString 的。因为 输出 与 Object 类的 toString 相同。
所以我调用了Arrays 的toString。
println Arrays.toString(list.toArray()): [this, is, ArrayList]
就没问题了。
那继续;
ArrayList → toString()?
ArrayList 只写了 toArray()。所以继续走
ArrayList → AbstractList → toString()?
没有 toString,看来设计的时候还考虑的挺早?
ArrayList → AbstractList → AbstractCollection → toString()
找到了
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
这我们就知道 [this, is, ArrayList] 括号和逗号的由来了。
但是 有一行是 直接打印 list 的,为什么还有这个?
println list: [this, is, ArrayList]
其实 toString 还有个比较好用的点,在碰到“println”之类的输出方法时会自动调用,不需要显式写出。
当然,这里的 自动调用 就不是我们所想要的那样了。
我想处理字符串的问题?
如果是像上面那样,显然不是我们想要的,所以我就用了 StringUtils.join (String.join 也行)。
StringUtils.join
这个方法 是 将数组或集合以某拼接符拼接到一起形成新的字符串。看看实现:
public static String join(Collection var0, String var1) {
StringBuffer var2 = new StringBuffer();
for(Iterator var3 = var0.iterator(); var3.hasNext(); var2.append((String)var3.next())) {
if (var2.length() != 0) {
var2.append(var1);
}
}
return var2.toString();
}
用的 StringBuffer 和 iterator 迭代器。(看来侧面显示了 没有 使用 RandomAccess)。
这么看来其实和我们 直接用 StringBuffer 和 for 循环差不多。当然 StringBuffer 是线程安全的。
数组转字符串
像 ArrayList 这样的容器类,一般都支持 直接 在构造方法中传入对象进行转换。
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(listStr.split(" ")));
说到这里 我突然想到了 toArray
集合类 的 toArray
一般有两个
<T> T[] toArray(T[] a);
Object[] toArray();
比如 ArrayList
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
就几个注意的,输入参数组空间大小的设置:
- 参数空间等于 0 时,将会动态的创建和集合 size 相同空间大小的数组,性能是最好的。
- 参数空间大于 0 但是小于 size 时,会重新创建大小等于集合 size 的数组,此时会增加GC的负担。
- 参数空间等于集合的 size 时,在普通情况下是没问题的,但是在高并发情况下,数组创建完成后,集合的 size 变大,此时影响跟第二条相同。
- 参数空间大于集合的 size 时,一方面会造成空间浪费,另一方面会在使用数组是产生空指针的异常。因为多出来的空间会存入 null。
今天到这。