源码浅谈(一):java中的 toString()方法

前言:

      toString()方法 相信大家都用到过,一般用于以字符串的形式返回对象的相关数据。

  最近项目中需要对一个ArrayList<ArrayList<Integer>> datas  形式的集合处理。

  处理要求把集合数据转换成字符串形式,格式为 :子集合1数据+"#"+子集合2数据+"#"+....+子集合n数据。

  举例: 集合数据 :[[1,2,3],[2,3,5]]  要求转成为 "[1,2,3]#[2,3,5]" 形式的字符串

  第一次是这样处理的:

        ArrayList<ArrayList<Object>> a = new ArrayList<>();    // 打造这样一个数据的集合 [[1,2],[2,3]] 要求 生成字符串 [1,2]#[2,3]
        for (int i = 0; i < 2; i++) { 
            ArrayList<Object> c = new ArrayList<>();
            c.add(i+1);
            c.add(i+2);
            a.add(c);
            //打印单个子集合的字符串形式数据
            Log.i("myinfo",c.toString());
        }
        StringBuilder builder = new StringBuilder();
        builder.append(a.get(0).toString()+"#"+a.get(1).toString());
        //打印该集合的字符串形式数据
        Log.i("myinfo",builder.toString());

  然后看该处理下的Log日志:

05-12 10:29:18.485 9565-9565/com.xxx.aaa I/myinfo: [1, 2]
05-12 10:29:18.485 9565-9565/com.xxx.aaa I/myinfo: [2, 3]
05-12 10:29:18.495 9565-9565/com.xxx.aaa I/myinfo: [1, 2]#[2, 3]

   我们会发现我们想要的是[1,2]#[2,3]形式的字符串,但是结果是[1, 2]#[2, 3]  ,在第二个值开始往后,前面都多了一个空格。

   接下来我们查看 集合下的.toString()方法的源码:

   翻译一下官方解释:

   1、返回这个Collection类(Set和List的父类) 的字符串表现形式

       2、这个表现形式有一个规定的格式,被矩形括号"[]"包含

       3、里面的子元素被“, ”(逗号和空格)分割 (这是重点)

    /**
     * Returns the string representation of this {@code Collection}. The presentation
     * has a specific format. It is enclosed by square brackets ("[]"). Elements
     * are separated by ', ' (comma and space).
     *
     * @return the string representation of this {@code Collection}.
     */
    @Override
    public String toString() {
        if (isEmpty()) {
            return "[]";
        }

        StringBuilder buffer = new StringBuilder(size() * 16);
        buffer.append('[');
        Iterator<?> it = iterator();
        while (it.hasNext()) {
            Object next = it.next();
            if (next != this) {
                buffer.append(next);
            } else {
                buffer.append("(this Collection)");
            }
            if (it.hasNext()) {
                buffer.append(", ");
            }
        }
        buffer.append(']');
        return buffer.toString();
    }

  分析这个Collection下的.toString()方法源码,分为几个部分:

1、判断集合是不是空(empty),即集合内有没有数据。如果是空值(没有数据)的话,直接返回字符串 "[]"

2、如果集合不是空值,说明有数据

    ①、迭代取下一个子元素(Object next = it.next()),如果这个子元素是集合本身,添加"(this Collection)"到StringBuffer类的buffer对象中

    ②、如果这个子元素不是集合本身,添加到buffer对象中

    ③、如果这个子元素下面还有子元素,则添加", "到buffer对象中去,用于分割两个相邻子元素

3、返回StringBuffer.toString()字符串

  由此可见,返回[1, 2]#[2, 3]是官方正确的返回形式,那么对于这个问题,其实在改不了源码的情况下 给得到的字符串后面使用.replaceAll(" ",""); 把字符串中的空格都去掉

  注意:源码中有一段代码:

            if (next != this) {
                buffer.append(next);
            } else {
                buffer.append("(this Collection)");
            }         

  这里可能有些同学看不懂,这里举个例子,还是上面的那个,我们在子集合里面 添加代码 c.add(c); 将集合本身添加到集合中去,看看打印结果

ArrayList<ArrayList<Object>> a = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            ArrayList<Object> c = new ArrayList<>();
            c.add(i+1);
            c.add(i+2);
            c.add(c);
            //打印单个子集合的字符串形式数据
            Log.i("myinfo",c.toString());
        }

看日志结果中红色部分,是不是看懂了,如果集合中的子元素是集合本身,就将"(this Collection)" 添加到返回集合中 

  至此,上面这个问题解决了,下面我们看下其他类下的.toString()源码。

---------------------------------------------------------------------------------------------------------------

一、Object

 /**
     * Returns a string containing a concise, human-readable description of this
     * object. Subclasses are encouraged to override this method and provide an
     * implementation that takes into account the object's type and data. The
     * default implementation is equivalent to the following expression:
     * <pre>
     *   getClass().getName() + '@' + Integer.toHexString(hashCode())</pre>
     * <p>See <a href="{@docRoot}reference/java/lang/Object.html#writing_toString">Writing a useful
     * {@code toString} method</a>
     * if you intend implementing your own {@code toString} method.
     *
     * @return a printable representation of this object.
     */
    public String toString() {
        return getClass().getName() + '@' + Integer.toHexString(hashCode());
    }

  翻译一下官方解释:

  1、返回一个对于这个Object 简明的、可读的 的字符串

  2、Object类的子类被鼓励去重写这个方法来提供一个实现用于描述对象的类型和数据

  3、默认的执行形式和下面这个例子一致

getClass().getName() + '@' + Integer.toHexString(hashCode())</pre>

  综上:当你的一个类中没有重写.toString()方法的时候就会执行根类Object的这个.toString()方法。

     返回形式:对象的类名+@+哈希值的16进制

getClass().getName()返回对象所属类的类名
hashCode()返回该对象的哈希值
Integer.toHexString(hashCode())将对象的哈希值用16进制表示

 举例:

Object d = new Object();
Log.i("myinfo",d.toString());

05-12 11:23:00.758 17406-17406/com.maiji.magkarepatient I/myinfo: java.lang.Object@e23e786

二、String,StringBuilder,StringBuffer

  三个都是字符串的表现形式,但是有区别的

  ①、String.toString()  , 直接返回本身

    /**
     * Returns this string.
     */
    @Override
    public String toString() {
        return this;
    }

  ②、StringBuilder

   官方解释:以字符串的形式 返回这个builder对象的内容

/**
     * Returns the contents of this builder.
     *
     * @return the string representation of the data in this builder.
     */
    @Override
    public String toString() {
        /* Note: This method is required to workaround a compiler bug
         * in the RI javac (at least in 1.5.0_06) that will generate a
         * reference to the non-public AbstractStringBuilder if we don't
         * override it here.
         */
        return super.toString();
    }

  追溯到super.toString()实现

 /**
     * Returns the current String representation.
     *
     * @return a String containing the characters in this instance.
     */
    @Override
    public String toString() {
        if (count == 0) {
            return "";
        }
        return StringFactory.newStringFromChars(0, count, value);
    }

  ③、StringBuffer

@Override
    public synchronized String toString() {
        return super.toString();
    }

  追溯到super.toString()

 /**
     * Returns the current String representation.
     *
     * @return a String containing the characters in this instance.
     */
    @Override
    public String toString() {
        if (count == 0) {
            return "";
        }
        return StringFactory.newStringFromChars(0, count, value);
    }

  综上我们发现,StringBuffer和StringBuilder最终都调用了父级  “AbstractStringBuilder” 中的toString()方法

  但是他们本身的toString()却有所不同,我们由此可以总结

  1、StringBuilder:线程非安全的

 StringBuffer:线程安全的

      2、StringBuilder 处理速度要比 StringBudiler 快的多

  3、单线程大量数据操作,用StringBuilder  ,因为 StringBuilder速度快 , 因为单线程所以不考虑安全性

多线程大量数据操作,用StringBuffer   ,  因为StringBuffer安全

三、Map

  先看源码:

  可以看到返回的形式是{key1=value1, key2=value2}

  注意   1、当Map集合中没有数据的时候 返回{}

2、每两个数据之前用", "分割,和Collection一致,一个逗号、一个空格

3、当键值是集合本身的时候,添加  (this Map)

public String toString() {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(',').append(' ');
        }
    }

  举例:

       Map<String,String> map = new HashMap<>();
        map.put("keyA","valueA");
        map.put("keyB","valueB");
        map.put("keyC","valueC");
        Log.i("myinfo",map.toString());

打印结果:

05-12 11:41:30.898 4490-4490/com.maiji.magkarepatient I/myinfo: {keyA=valueA, keyB=valueB, keyC=valueC}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏从零开始学 Web 前端

06 - JavaSE之常用类

public StringBuffer append(...) 可以为该 StringBuffer 对象添加字符序列,返回添加后的该 StringBuffer ...

702
来自专栏海说

Java源码学习 -- java.lang.String

java.lang.String是使用频率非常高的类。要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的。由java.lang.S...

2020
来自专栏三木的博客

Javascript中的数组

数组的定义: var colors = new Array(20); var colors = new Array('red');  // ['red'...

20610
来自专栏老马说编程

(89) 正则表达式 (中) / 计算机程序的思维逻辑

上节介绍了正则表达式的语法,本节介绍相关的Java API。 正则表达式相关的类位于包java.util.regex下,有两个主要的类,一个是Pattern,另...

1937
来自专栏java学习

面试题53(考察求职者对String声明变量在jvm中的存储方法)

(单选题) 1、有如下一段代码,请选择其运行结果() public class StringDemo{ private static final Stri...

2883
来自专栏Linyb极客之路

JAVA常用API整理

提供sin, cos, tan, exp, log, log10 等类方法,PI和E等类字段

2074
来自专栏武培轩的专栏

Leetcode#557. Reverse Words in a String III(反转字符串中的单词 III)

给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

653
来自专栏微信公众号:Java团长

Java集合类详解

上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如AbstractCollectio...

1071
来自专栏Java帮帮-微信公众号-技术文章全总结

16(02)总结泛型

2:泛型(掌握) (1)泛型概述 是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。 (2)格式: <数据类型> 注意:该数...

3347
来自专栏我是攻城师

关于Java里面的字符串拼接,你了解多少?

字符串拼接是我们日常开发中很常见的操作,虽然常见,但要是使用不当的的话,很有可能让你的程序处理效率降低一大半,所以我们有必要来重新了解一下Java里面的字符串操...

1493

扫码关注云+社区