读书笔记-《ON JAVA 中文版》-摘要18[第十八章 字符串-1]

news2024/9/29 21:25:33

文章目录

  • 第十八章 字符串
    • 1. 字符串的不可变
    • 2. + 的重载与 StringBuilder
    • 3. 意外递归
    • 4. 字符串操作
    • 5. 格式化输出
      • 5.1 printf()
      • 5.2 System.out.format()
      • 5.3 Formatter 类
        • 5.3.1 格式化修饰符
        • 5.3.2 Formatter 转换
      • 5.4 String.format()
    • 6. 自我学习总结

第十八章 字符串

字符串操作毫无疑问是计算机程序设计中最常见的行为之一。

1. 字符串的不可变

String 对象是不可变的。查看 JDK 文档你就会发现, String 类中每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String 对象,以包含修改后的字符串内容。而最初的 String 对象则丝毫未动。

public class Immutable {
    public static String upcase(String s) {
        return s.toUpperCase();
    }

    public static void main(String[] args) {
        String q = "howdy";
        System.out.println(q);
        String qq = upcase(q);
        System.out.println(qq);
        System.out.println(q);
    }
}

输出:

howdy
HOWDY
howdy

当把 q 传递给 upcase() 方法时,实际传递的是引用的一个拷贝。其实,每当把 String 对象作为方法的参数时,都会复制一份引用,而该引用所指向的对象其实一直待在单一的物理位置上,从未动过。

—PS:q 还是那个皮蛋

2. + 的重载与 StringBuilder

重载的意思是,一个操作符在用于特定的类时,被赋予了特殊的意义(用于 String 的 + 与 += 是 Java 中仅有的两个重载过的操作符,Java 不允许程序员重载任何其他的操作符 )。

—PS:+ 在数值是相加,在字符串是相连。+ 的重载与方法重载是两码事

操作符 + 可以用来连接 String :

public class Concatenation {
    public static void main(String[] args) {
        String mango = "mango";
        String s = "abc" + mango + "def" + 47;
        System.out.println(s);
    }
}

输出:

abcmangodef47

可以想象一下,这段代码是这样工作的: String 可能有一个 append() 方法,它会生成一个新的 String 对象,以包含“abc”与 mango 连接后的字符串。该对象会再创建另一个新的 String 对象,然后与“def”相连,生成另一个新的对象,依此类推。 这种方式当然是可行的,但是为了生成最终的 String 对象,会产生一大堆需要垃圾回收的中间对象。

用 JDK 自带的 javap 工具来反编译以上代码,发现编译器自动引入了 java.lang.StringBuilder 类,就因为它更高效。

在这里,编译器创建了一个 StringBuilder 对象,用于构建最终的 String ,并对每个字符串调用 了一次 append() 方法,共计 4 次。最后调用 toString() 生成结果,也许你会觉得可以随意使用 String 对象,反正编译器会自动为你做性能优化。

但是从下面这段代码的反编译结果来看,显式的使用 StringBuilder 会节省很多资源。

public class WhitherStringBuilder {
    public String implicit(String[] fields) {
        String result = "";
        for (String field : fields) {
            // PS:反编译后,每次循环都会创建一个 StringBuilder 对象
            result += field;
        }
        return result;
    }

    public String explicit(String[] fields) {
        // PS:反编译后,explicit() 不仅循环部分的代码更简短、更简单,只会创建一个 StringBuilder 对象
        StringBuilder result = new StringBuilder();
        for (String field : fields) {
            result.append(field);
        }
        return result.toString();
    }
}

显式地创建 StringBuilder 还允许你预先为其指定大小。如果你已经知道最终字符串的大概长度,那预先指定 StringBuilder 的大小可以避免频繁地重新分配缓冲。

—PS:简单的字符串连接可以直接用 + ,涉及到循环时最好用 StringBuilder

StringBuilder 提供了丰富而全面的方法,包括 insert() 、 replace() 、 substring() 、delete() ,甚至还有 reverse() ,但是最常用的还是 append() 和 toString() 。

3. 意外递归

如果你希望 toString() 打印出类的内存地址,也许你会考虑使用 this 关键字:

@Override
    public String toString() {
        return " InfiniteRecursion address: " + this + "\n";
    }

当你创建了 InfiniteRecursion 对象,并将其打印出来的时候,你会得到一串很长的异常信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1cc4F9yp-1688095585633)(img/181.png)]

其实,当运行到如下代码时:

"InfiniteRecursion address: " + this

编译器发现一个 String 对象后面跟着一个 “+”,而 “+” 后面的对象不是 String ,于是编译器试着将 this 转换成一个 String 。它怎么转换呢?正是通过调用 this 上的 toString() 方法,于是就发生了递归调用。

—PS:this 的 toString() 还是这个方法,自己调自己

如果你真的想要打印对象的内存地址,应该调用 super.toString() 方法。

4. 字符串操作

推荐一个大佬的文章:Java 字符串常见的操作

当需要改变字符串的内容时, String 类的方法都会返回一个新的 String 对 象。同时,如果内容不改变, String 方法只是返回原始对象的一个引用而已。这可以节约存储空间以及避免额外的开销。

5. 格式化输出

5.1 printf()

printf() 并不使用重载的 + 操作符来连接引号内的字符串或字符串变量,而是使用特殊的占位符来表示数据将来的位置。而且它还将插入格式化字符串的参数,以逗号分隔,排成一行。

控制符说明
%d整数
%8d整数,右对齐,输出长度为8位
%-8d整数,左对齐,输出长度为8位
%f浮点数
%8f浮点数,右对齐,输出长度为8位,有 - 为左对齐
%.2f浮点数,精确到百分位
%8.3f浮点数,精确到千分位,输出长度为8位(算上小数点)
%s字符串,与 %d 类似
%n换行符
public class StrTest {
    public static void main(String[] args) {
        System.out.printf("%d%n", 100);

        for (int i = 0; i < 5; i++) {
            System.out.printf("%4d", i);
        }
        System.out.println();

        for (int i = 0; i < 5; i++) {
            System.out.printf("%-4d", i);
        }
        System.out.println();

        System.out.printf("%f%n", 8d);

        System.out.printf("%.2f%n", 8d);

        System.out.printf("%8.3f%n", 8d);

        System.out.printf("%-8.3f%n", 8d);

        System.out.printf("%s%n", "a1");

        System.out.printf("不装了,%s有%d套房%n", "小悦", 66);
    }
}

输出:

100
   0   1   2   3   4
0   1   2   3   4   
8.000000
8.00
   8.000
8.000   
a1
不装了,小悦有66套房

5.2 System.out.format()

Java SE5 引入了 format() 方法,可用于 PrintStream 或者 PrintWriter 对象,其中也包括 System.out 对象。format() 和 printf() 是等价的,String 类也有一个 static format() 方法,可以格式化字符串。

public class SimpleFormat {
    public static void main(String[] args) {
        int x = 5;
        double y = 5.332542;
        System.out.println("Row 1: [" + x + " " + y + "]");
        System.out.format("Row 1: [%d %f]%n", x, y);
        System.out.printf("Row 1: [%d %f]%n", x, y);
        System.out.println(String.format("Row 1: [%d %f]%n", x, y));
    }
}

输出:

Row 1: [5 5.332542]
Row 1: [5 5.332542]
Row 1: [5 5.332542]
Row 1: [5 5.332542]

5.3 Formatter 类

在 Java 中,所有的格式化功能都是由 java.util.Formatter 类处理的。可以将 Formatter 看做一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。当你创建一个 Formatter 对象时,需要向其构造器传递一些信息,告诉它最终的结果将向哪里输出:

import java.io.PrintStream;
import java.util.Formatter;

public class Turtle {
    private String name;
    private Formatter f;

    public Turtle(String name, Formatter f) {
        this.name = name;
        this.f = f;
    }

    public void move(int x, int y) {
        f.format("%s The Turtle is at (%d,%d)%n",
                name, x, y);
    }

    public static void main(String[] args) {
        // PS:创建一个输出流
        PrintStream outAlias = System.out;

        // PS: Formatter 的重载构造器支持输出到多个路径,
        // 不过最常用的还是 PrintStream() 、 OutputStream 和 File 。
        Turtle tommy = new Turtle("Tommy", new Formatter(System.out));
        Turtle terry = new Turtle("Terry", new Formatter(outAlias));

        tommy.move(0, 0);
        terry.move(4, 8);
        tommy.move(3, 4);
        terry.move(2, 5);
        tommy.move(3, 3);
        terry.move(3, 3);
    }
}

输出:

Tommy The Turtle is at (0,0)
Terry The Turtle is at (4,8)
Tommy The Turtle is at (3,4)
Terry The Turtle is at (2,5)
Tommy The Turtle is at (3,3)
Terry The Turtle is at (3,3)

5.3.1 格式化修饰符

在插入数据时,如果想要优化空格与对齐,你需要更精细复杂的格式修饰符。以下是其通用语法:

%[argument_index$][flags][width][.precision]conversion

argument_index: 可选,是一个十进制整数,用于表明参数在参数列表中的位置。第一个参数由 “1 " 引用,第二个参数由 " 2 " 引用,第二个参数由 "2 "引用,第二个参数由"2” 引用,依此类推。

flags: 可选,用来控制输出格式

width: 可选,是一个正整数,表示输出的最小长度

precision:可选,用来限定输出字符数

conversion:必须,用来表示如何格式化参数的字符

推荐大佬文章,里面有详细说明:String.format()方法使用说明

5.3.2 Formatter 转换

类型含义
d整型(十进制)
cUnicode字符
bBoolean值
sString
f浮点数(十进制)
e浮点数(科学计数)
x整型(十六进制)
h散列码(十六进制)
%字面值“%”

对于 boolean 基本类型或 Boolean 对象,其转换结果是对应的 true 或 false 。

但是,对其他类型的参数,只要该参数不为 null ,其转换结果永远都是 true

5.4 String.format()

String.format() 是一个 static 方法,它接受与 Formatter.format() 方法一样的参数,但返回一个 String 对象。当你只需使用一次 format() 方法的时候, String.format() 用起来很方便。其实在 String.format() 内部,它也是创建了一个 Formatter 对象,然后将你传入的参数转给 Formatter 。

6. 自我学习总结

  1. String 对象是不可变的

  2. 操作符重载就是在不同场合有不同的作用,例如,+ 除了数值相加,还可以用于字符串连接,+ 与 += 是 Java 中仅有的两个重载操作符

  3. 简单的字符串连接可以使用 + ,这是因为编译器自动优化为了 StringBuilder 去处理,涉及到复杂的、繁多的字符串连接时,还是显式的使用 StringBuilder 最好

  4. StringBuilder 提供了很多方法,insert() 、 replace() 、 substring() 、delete() ,甚至还有 reverse() ,但是最常用的还是 append() 和 toString()

  5. 字符串操作很多返回的是 String 对象,所以可以链式的调用方法,例如:s.trim().replace(“a”,“b”).substring(0,1).toLowerCase();

  6. 字符串格式化输出的方式有:

    • System.out.printf()
    • System.out.format()
    • Formatter 类 format()
    • String.format()

以上都遵循下面的规则:

控制符说明
%d整数
%8d整数,右对齐,输出长度为8位
%-8d整数,左对齐,输出长度为8位
%f浮点数
%8f浮点数,右对齐,输出长度为8位,有 - 为左对齐
%.2f浮点数,精确到百分位
%8.3f浮点数,精确到千分位,输出长度为8位(算上小数点)
%s字符串,与 %d 类似
%n换行符

在这里插入图片描述
(图网,侵删)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/711507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【专题速递】更多的解决方案:传统行业不再「传统」

// 音视频技术作为企业数字化转型的关键技术与能力之一&#xff0c;为众多传统行业在生产、服务、管理与维护等方面提供了强有力的支持。那么&#xff0c;音视频技术是如何助力企业数字化转型的&#xff1f;7月28日LiveVideoStackCon上海站数字化与行业案例专场&#xff0c;为…

【AI】PyTorch安装记录及Anaconda环境配置

【AI】PyTorch安装记录及Anaconda环境配置 说下本地环境&#xff0c;RTX4070 12GB GPU&#xff1b;618刚买&#xff0c;不能让他闲着&#xff0c;配置一下炼丹环境&#xff0c;开始为打工人工作。为了方便后续部署模型之间依赖不冲突&#xff0c;所以使用Anaconda管理Python环…

【数据结构】第 1~10 章:思维导图与重点汇总

目录 一、概论 &#xff08;1&#xff09;思维导图 &#xff08;2&#xff09;常见名词 &#xff08;3&#xff09;数据结构的定义 &#xff08;4&#xff09;抽象数据类型 ADT &#xff08;5&#xff09;算法 &#xff08;6&#xff09;评价算法的好坏的因素 &am…

Python基础 —— 循环语句

如约来更新循环语句了.说到循环&#xff0c;有一定编程基础的小伙伴们都知道&#xff0c;我们最常用的循环莫过于 while循环&#xff0c;for循环和goto循环&#xff08;不过goto也不怎么常用&#xff09;&#xff0c;所以今天就来说一说 while循环和 for循环 来看一下本文大致…

IMX6ULL系统移植篇-uboot基础命令

一. uboot 启动 当设备上电启动时&#xff0c;需要马上按下回车键&#xff0c;开发板启动会停止在 uboot的启动Log信息时刻。 这就是 uboot的命令模式&#xff0c;即可以输入 uboot命令进行一些操作。 二. uboot 基础命令 1. help 命令 当开发板上电启动后&#xff0c;马…

电脑如何设置外网内网一起使用

如果你的电脑支持连接无线网&#xff0c;就可以设置内网外网一起使用。一般情况下&#xff0c;连接无线网还是网线都是系统自动链接的,但有时候开发中需要内网外网一块使用&#xff0c;不用手动切换网络。 首先确保我们的电脑有双网卡&#xff0c;可以两个都是有线网卡&#xf…

【机械臂视觉抓取从理论到实战】

1. 概述 GR-CNN&#xff1a;https://paperswithcode.com/paper/antipodal-robotic-grasping-using-generative 2. 环境搭建及模型训练 GR-CNN&#xff1a;https://github.com/skumra/robotic-grasping 下载源码创建环境 #下载robotic-grasping源码 git clone https://github.…

CVE-2021-3493:Overlay 文件系统 Ubuntu 本地提权漏洞分析

分析此漏洞的文章非常多&#xff0c;在此只是记录一下复现漏洞的过程以及对漏洞的个人理解。Linux 内核漏洞有一定的准入门槛&#xff0c;不适合小白阅读。 基本信息 [影响范围] Ubuntu 14.04 ~20.10 [漏洞描述] Ubuntu 内核代码允许低权限用户在使用 unshare() 函数创建的…

李彦宏:AI原生应用比大模型数量更重要

6月26日&#xff0c;百度创始人、董事长兼首席执行官李彦宏出席“世界互联网大会数字文明尼山对话”&#xff0c;发表了题为 《大模型重塑数字世界》 的演讲。 大模型是当下全球科技创新的焦点&#xff0c;也是全球人工智能竞赛的主战场。李彦宏认为&#xff0c;“新的国际竞争…

箱线图概念和使用介绍

箱线图时一种针对连续型变量的统计图。通常用作比较。 箱子中间的一条线&#xff0c;是数据的中位数&#xff0c;代表了数据的平均水平。 箱子的上限和下限&#xff0c;分别是数据的上四分位数和下四分位数&#xff0c;意味着箱子包含50%的数据。因此&#xff0c;箱子的高度在…

23.RocketMQ之NameServer处理Broker心跳包,更新本地路由信息

NameServer处理Broker心跳包,更新本地路由信息 DefaultRequestProcessor继承自NettyRequestProcessor:处理各种客户端的请求&#xff0c;如果请求类型是为REGISTER_BROKER&#xff0c;则将请求转发到RouteInfoManager#regiesterBroker,主要是服务器端 或者客户端或者broker发送…

go语言环境安装

文章目录 环境介绍安装软件包步骤环境变量设置来一个经典的hello worldNice 最近的项目需要用到go来开发了&#xff0c;前几天就已经在看书了&#xff0c;今天是个周末&#xff0c;先在家里的机器上把环境搭好&#xff0c;特此记录一下。 环境介绍 下载地址&#xff1a;https:…

RRT 算法研究(附 Python / C++ 实现)

RRT 算法研究 参考 机器人路径规划、轨迹优化课程-第五讲-RRT算法原理和代码讲解 机器人路径规划之RRT算法(附C源码) RRT算法(快速拓展随机树)的Python实现 《基于改进RRT算法的路径规划研究》 《面向室内复杂场景的移动机器人快速路径规划算法研究》 理论基础 RRT&#xff0…

meb stm32开发

matlab1028b以上 stm32cubemx5.6.0以上 stm32-mat/target 教程与代码分享 - 知乎 安装好这些后&#xff0c;打开matlab&#xff0c;打开路径STM32-MAT\STM32 打开simulink&#xff0c;view-lib 可以看到 在STM32CUBEMX完成底层配置&#xff0c;生成ioc文件

UI的绘制流程

1.App的启动流程 每个App都是一个独立的进程&#xff0c;当一个app启动的时候&#xff0c;当前进程也被启动&#xff0c;在Android中有一个类ActivityThread&#xff0c;就是进程的初始类&#xff0c;其中main方法就是整个app的入口。ActivityThread并不是一个线程&#xff0c;…

Java并发编程中的JMM、3个基本属性、synchronized和volatile

1、Java内存模型JMM (Java Meemory Model) JMM规定&#xff0c;所有变量均存储在主内存中每个线程都有自己的工作内存&#xff0c;保存了该线程中用到的变量的主内存副本拷贝线程对变量的所有操作&#xff0c;必须在自己的工作内存中&#xff0c;不可直接读写主内存不同线程无法…

2023-6-29-第十一式代理模式

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

C++primer(第五版)第八章(IO库)

8.1 IO库 上表中以w开头的类型和函数是C标准库为了支持使用宽字符的语言而定义的一组类型和对象来操纵wchar_t类型的数据.(然而我没有遇到过) 8.1.1 IO对象无拷贝或赋值 IO对象不能拷贝或赋值,通常用引用方式传递和返回流,由于读写一个IO对象回改变其状态,因此传递和返回的引…

Cetos7.x连接不上网络解决办法

Cetos7.x连接不上网络解决办法 Cetos7.x连接不上网络解决办法 在VM中设置网络连接为桥接&#xff0c;修改后仍无法连接网络 ##配置centos7中ens33&#xff0c;将默认的no修改为yes 启动CentOS系统&#xff0c;并打开一个连接终端会话&#xff0c;使用root登录&#xff1b;进…

tomcat多台应该怎么能设置

一个tomcat一般能处理5000-1000的并发量但是还是远远不够我们可以设置多台来满足我们的要求 首先进入tomcat目录 配置tomcat环境变量 vim /etc/profile.d/tomcat.sh 然后刷新 source /etc/profile.d/tomcat.sh 修改tomcat1里面的配置文件 然后进入tomcat1中的启动bin程序中…