Java的String类 - 那些犄角旮旯的点

简介: 不搞流水账,本文详细介绍我们日常开发中使用String类的痛点问题。

不搞流水账,本文详细介绍我们日常开发中使用String类的痛点问题。

你真的了解 toString() 吗?


可能有的小伙伴看到这个问题会不屑一顾,这个玩意老子天天用!


可是,相信你一定有过被 NullPointerException 支配的痛苦经历,而 toString() 方法就是其中一个罪魁祸首!


我先问大家一个问题,是不是所有的Java变量都有toString呢?


如果你觉得有,请把1打在公屏上,如果没有,就打2。(话说我在干嘛,这是博客,又不是Bilibili,emmm,不过可以考虑后期写个弹幕系统)


现在我来公布答案:基本数据类型是没有的,不能使用toString方法!


不相信你可以在Eclipse或者idea里面试一试,编译会报错的。


包装类

上面已经说了,基本数据类型是没有toString的,那么包装类有吗?

包装类,用的比较多的,那就是Integer了,看下Integer有没有toString 呢?答案肯定是有的,包装类不是基本数据类型,那就是有的。

public class StringTest1 {
    public static void main(String[] args) {
        Integer i = 1;
        System.out.println(i.toString());
    }
}

注意,Integer的toString方法用了重载(jdk1.8版本源码)

public String toString() {
   return toString(value);
}

重新调用了另一个toString,也是写在Integer类中:

public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

这些代码如果看的吃力,也没有关系,我们只需要理解大概的意思就行。在调用toString方法的时候,实际上就是把Integer类内部的value属性,转换成一个String对象返回。


Integer自动装箱原理

顺便说一下Integer的自动装箱原理

Integer作为一个典型的包装类,当你写了如下代码:

Integer i = 1;


实际上,编译器会调用Integer的valueOf方法,将原始类型值转换成Integer对象,这个过程我们是感觉不到的。Integer还维护了一个缓存IntegerCache,它会判断i是否在-128和127之间,存在则从IntegerCache中获取包装类的实例,否则new一个新实例。IntegerCache使用了享元模式,其内部维护了一个缓存池,数值范围是-128和127之间,这个缓存是静态的,类加载的时候会自动加载。因为我们正常使用Integer的时候,赋予的值一般不会太大,所以只需牺牲一点点内存,这里用享元模式可以有效地提升效率。


附上Integer的valueOf方法:

public static Integer valueOf(int i) {
    //判断i是否在-128和127之间,存在则从IntegerCache中获取包装类的实例,否则new一个新实例
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

这个功能从jdk1.5开始就有了。


Object类

在Java中,所有的类都继承自Object,所以我们有必要再来看看Object的情况。首先是Object类的toString实现:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

可以看到,Object的toString方法就是把对象的hashCode值转为16进制而已。比如:

java.lang.Object@16d3586


但是实际上,调用toString还是会根据当前对象来具体分析的,比方说下面的代码:

Object i = 1;
System.out.println(i.toString());


1明明是基本数据类型,但是赋值给Object以后,编译器就会把它看成是Integer对象。不妨做一个实验,在eclipse或者idea中打开调试模式,然后在Integer的toString方法中打上一个断点。当你调试这段代码的时候,就会发现可以进入到Integer的toString方法。

64244460b99ae7d1e53648f643ff99ec.png


这也就印证了,这种情况编译器是会认识到,当前的1应该是一个Integer对象。

再看一个例子:

Object i = new ArrayList<>();
System.out.println(i.toString());

这时候的i其实是ArrayList的实例对象,所以实际调用toString方法的时候,也就是直接调用ArrayList的toString方法了,而ArrayList并未对toString进行重写,而是ArrayList的父类AbstractList,AbstractList的父类AbstractCollection重写了toString:


————————————————

版权声明:本文为CSDN博主「剽悍一小兔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_39570751/article/details/122637202

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(' ');
    }
}

这也是为什么,我们打印ArrayList的时候(这个操作实在是很普遍,懂的都懂),打印出来的是一个数组字符串。


综上,Object类调用toString,如果当前实际的对象没有重写toString,就是调用父类的toString,如果父类也没有重写toString,就层层冒泡最终到Object类。


相关文章
|
2月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
173 57
|
1月前
|
存储 JavaScript Java
Java 中的 String Pool 简介
本文介绍了 Java 中 String 对象及其存储机制 String Pool 的基本概念,包括字符串引用、构造方法中的内存分配、字符串文字与对象的区别、手工引用、垃圾清理、性能优化,以及 Java 9 中的压缩字符串特性。文章详细解析了 String 对象的初始化、内存使用及优化方法,帮助开发者更好地理解和使用 Java 中的字符串。
Java 中的 String Pool 简介
|
28天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
1月前
|
缓存 安全 Java
java 为什么 String 在 java 中是不可变的?
本文探讨了Java中String为何设计为不可变类型,从字符串池的高效利用、哈希码缓存、支持其他对象的安全使用、增强安全性以及线程安全等方面阐述了不可变性的优势。文中还通过具体代码示例解释了这些优点的实际应用。
java 为什么 String 在 java 中是不可变的?
|
2月前
|
JSON Java 关系型数据库
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
在Java中,使用mybatis-plus更新实体类对象到mysql,其中一个字段对应数据库中json数据类型,更新时报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
232 4
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
|
1月前
|
存储 Java
Java 11 的String是如何优化存储的?
本文介绍了Java中字符串存储优化的原理和实现。通过判断字符串是否全为拉丁字符,使用`byte`代替`char`存储,以节省空间。具体实现涉及`compress`和`toBytes`方法,前者用于尝试压缩字符串,后者则按常规方式存储。代码示例展示了如何根据配置决定使用哪种存储方式。
|
2月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
76 8
|
2月前
|
Java
在Java中如何将基本数据类型转换为String
在Java中,可使用多种方法将基本数据类型(如int、char等)转换为String:1. 使用String.valueOf()方法;2. 利用+运算符与空字符串连接;3. 对于数字类型,也可使用Integer.toString()等特定类型的方法。这些方法简单高效,适用于不同场景。
133 7
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
78 2
|
2月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
89 17