不懂就问,读一读源码——对于 toString 的问题?

介绍

所有 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。

今天到这。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值