《Java编程思想》笔记10------字符串

栏目: Java · 发布时间: 6年前

内容简介:《Java编程思想》笔记10------字符串

String对象是不可变的,每一个看起来会修改String值的方法其实都是创建了一个新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。

/**
 * String是不可变的
 * @author LiangYu
 * 2018-01-20
 */
public class ImmutableTest {
	@Test
	public void test() throws Exception {
		String text = "qwERtYuIOp";
		System.out.println(text);
		String text2 = text.toUpperCase();
		System.out.println(text2);
		System.out.println(text);
	}
}

二、重载“+”和StringBuilder

String对象是不可变的,可以给String对象加任意多的别名。String对象具有只读特性,所以,指向它的任何引用都不会改变它的值。由此会带来效率问题。

例如: 为String对象重载的"+"操作符就是一个例子。

重载操作符的意思:一个操作符应用于特定的类时,被赋予了特殊意义。(用于String的+ 、+=是 Java 语言仅有的两个重载操作符)。

/**
 * String中的“+”
 * @author LiangYu
 * 2018-01-20
 */
public class StringAppendTest {
	@Test
	public void test() throws Exception {
		String message = "Hello";
		String hw = message + " World"+"!"+55;
		System.out.println(hw);
	}
}

输出结果: Hello World!55

底层的原理:

编译器自动引入了StringBuilder类,创建StringBuilder对象,用以构造最终的String。并为每个字符串调用一次StringBuilder的append()方法,总计四次。最后调用toString()生成结果。

即使编译器已经自动优化了性能,但是我们仍然要深入的看一下编译器为我们优化到了什么程度。

eg:通过两种方法来生成一个String。

(1) 使用多个String对象

(2) 在代码中使用StringBuilder

/**
 * 两种方式生成字符串
 * @author LiangYu
 * 2018-01-20
 */
public class WhitherStringBuilderTest {
	String implicit(String[] field){
		String result = "";
		for(int i = 0 ; i < field.length ; i++){
			result += field[i];
		}
		return result;
	}
	String explicit(String[] field){
		StringBuilder sBuilder = new StringBuilder();
		for(int i = 0 ; i < field.length ; i++){
			sBuilder.append(field[i]);
		}
		return sBuilder.toString();
	}
	@Test
	public void test() throws Exception {
		String[] texts = {"Hello"," ","World","!","hahah"};
		System.out.println(implicit(texts));
		System.out.println(explicit(texts));
	}
}

通过 javap -c WhitherStringBuilderTest查看两个方法的字节码

《Java编程思想》笔记10------字符串

implicit():

在第5行到第35行构成了一个循环体

在第35行:比较栈顶两int型数值大小,当结果小于0时跳转到第8行,构造一个新的StringBuilder;

在第5行:返回到循环体的起始点(第32行)

可以看到,StringBuilder是在循环体中构造,即:每次循环都会生成一个新的StringBuilder

explicit():

可以看到,只会在第0行生成了一个StringBuilder。

同时,显式的使用StringBuilder还可以预先为其设定大小。如果已经知道最终的字符串大概有多长。那预先指定StringBuilder的大小可以避免多次重新分配缓冲。

三、无意识的递归

Java中的每一个类都是从Object继承而来的,标准容器类也不例外。因此,容器类都有toString()方法,并且覆盖了该方法,使得其生成的String结果能够表达容器自身。

如果希望toString()方法打印出对象的内存地址,不能够使用this关键字。

/**
 * 在toString方法中,不可以使用this来显示对象的内存地址
 * @author LiangYu
 * 2018-01-20
 */
public class InfiniteRecursionTest {
	@Test
	public void test() throws Exception {
		ArrayList<InfiniteRecursionTest> infiniteRecursionTests = new ArrayList<InfiniteRecursionTest>();
		for(int i = 0 ; i < 5 ; i++){
			infiniteRecursionTests.add(new InfiniteRecursionTest());
		}
		System.out.println(infiniteRecursionTests);
	}
	@Override
	public String toString() {
		return "address"+this;
	}
}

此时会报错,因为在 return "address"+this; 运行的时候发生了强制类型转换,将InfiniteRecursionTest类型转换为String类型,此处调用this上的toString(),会造成无穷递归。

如果要打印对象的内存地址,应该调用Object中的toString().

四、String上的操作

4-1 构造方法

String(byte[ ] bytes):通过byte数组构造字符串对象。

String(char[ ] value):通过char数组构造字符串对象。

String(Sting original):构造一个original的副本。即:拷贝一个original。

String(StringBuffer buffer):通过StringBuffer数组构造字符串对象。

4-2 常用方法

  1. public char charAt(int index) 返回字符串中第index个字符;
  2. public int length() 返回字符串的长度;
  3. public int indexOf(String str) 返回字符串中第一次出现str的位置;
  4. public int indexOf(String str,int fromIndex) 返回字符串从fromIndex开始第一次出现str的位置;
  5. public boolean equalsIgnoreCase(String another) 比较字符串与another是否一样(忽略大小写);
  6. public String replace(char oldchar,char newChar) 在字符串中用newChar字符替换oldChar字符
  7. public boolean startsWith(String prefix) 判断字符串是否以prefix字符串开头;
  8. public boolean endsWith(String suffix) 判断一个字符串是否以suffix字符串结尾;
  9. public String toUpperCase() 返回一个字符串为该字符串的大写形式;
  10. public String toLowerCase() 返回一个字符串为该字符串的小写形式
  11. public String substring(int beginIndex) 返回该字符串从beginIndex开始到结尾的子字符串;
  12. public String substring(int beginIndex,int endIndex) 返回该字符串从beginIndex开始到endsIndex结尾的子字符串
  13. public String trim() 返回该字符串去掉开头和结尾空格后的字符串
  14. public String[] split(String regex) 将一个字符串按照指定的分隔符分隔,返回分隔后的字符串数组

五、格式化输出

printf()和 C语言 类似,通过特殊的占位符来表示未来要显示的内容类型。

/**
 * 类似C语言的格式化输出
 * @author LiangYu
 * 2018-01-20
 */
public class PrintfTest {
	@Test
	public void test() throws Exception {
		int x = 55;
		double y = 3.14;
		System.out.printf("Row 1:[%d,%f]",x,y);
	}
}

System.out.format()

format()方法用于PrintStream或PrintWriter对象。模仿自C的printf(),与printf()方法等价。

Formatter类

在Java中,所有新的格式化功能都有java.util.Formatter处理。Formatter构造器经过重载可以接受多种输出目的地,最常用的还是PrintStream()\OutputStream和File。

/**
 * Formatter的使用
 * @author LiangYu
 * 2018-01-20
 */
public class FormatterTest {
	@Test
	public void test() throws Exception {
		Hero hero1 = new Hero("百里守约", new Formatter(System.out));
		Hero hero2 = new Hero("百里玄策", new Formatter(System.out));
		hero1.move(3, 5);
		hero2.move(11, 7);
		hero1.move(4, 5);
		hero1.move(4, 6);
		hero2.move(10, 7);
	}
}

class Hero{
	private String name;
	private Formatter formatter;
	public Hero(String name,Formatter formatter){
		this.name = name;
		this.formatter = formatter;
	}
	public void move(int x,int y){
		if(name != null && formatter != null){
			formatter.format("%s的位置在:[%d,%d]\n",name,x,y);
		}
	}
}

格式化说明符

为了在插入数据是控制空格和对齐,需要更加精细的格式修饰符。格式如下:

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

flags表示左右对齐,默认是右对齐,如果想左对齐就使用“-”标志

width控制最小尺寸(宽度)至少该这么长,不够用空格替代。

在width后面加上"."后面表示精度precision。

用于String(%s)时,表示最多可写的字符数

用于浮点数(%f)表示小数点后面的位数,多了舍入,少了补0,默认是6位

用于整数(%d)时,不可用于整数,会触发异常

Formatter转换

常用的类型转换:

d 整型 (十进制)

c Unicode字符

b Boolean

s String

f 浮点型 (十进制)

e 浮点型(科学计数)

x 整数 (十六进制)

h 散列码(十六进制)

% 字符"%"

六、正则表达式

正则表达式是一个强大而灵活的文本处理工具。它提供可一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配、选择、编辑和验证。

正则可以切分,替换,判断字符串,通过设定的regex规则。

基础

在Java中, \\ 的意思是“我要插入一个正则表达式的反斜线,所以其后字符含有特殊意义”

\\d 表示一位数字

\\W 表示非单词字符

\\w 表示单词字符

\\\\ 表示普通反斜线

\n 换行符

\t 制表符

+ 一个或多个前一位的表达式

| 或者

? 可能有

\\+ 正号(加号在正则表达式中有特殊的意义,必须用 \\ 将其转译为一个普通字符)

/**
 * 正则表达式的简单应用
 * @author LiangYu
 * 2018-01-20
 */
public class IntegerMatchTest {
	@Test
	public void test() throws Exception {
		System.out.println("-1234".matches("-?\\d+"));
		System.out.println("4596".matches("-?\\d+"));
		System.out.println("+911".matches("-?\\d+"));
		System.out.println("+911".matches("(-|\\+)?\\d+"));
	}
}

创建正则表达式

B 指定字符B

\xhh 十六进制值为oxhh的字符

\uhhhh 十六进制表示为0xhhhh的Unicode字符

\t 制表符

\n 换行符

\r 回车符

\f 转页符

\e 转义符

常用的字符类:

. 任意字符

[abc] 包含a、b、c的任何字符

[^abc] 除了a、b、c的任何字符

[a-zA-Z] 从a-z或者A-Z的所有字符

[abc[hij]] 包含a、b、c、h、i、j的所有字符

[a-z&&[hij]] 包含h、i、j(交集)

\s 空白符(空格、tab、换行、换页、回车)

\S 非空白符

\d 数字[0-9]

\D 非数字[^o-9]

\w 词字符[a-zA-Z_0-9]

\W 非词字符[^\w]

逻辑操作符:

XY X后面有Y

X|Y X或Y

(X) 捕获组。可以在表达式中用\i引用第i个捕获组

边界匹配符:

^一行的开始

$ 一行的结束

\b 单词的边界

\B 非单词的边界

\G 前一个匹配的结束

量词

量词描述了一个模式吸收输入文本的方式:

贪婪型:贪婪表达式会为所有可能的模式发现尽可能多的匹配。假定我们的模式仅能匹配第一个可能的字符串组,如果表达式是贪婪的,那么它就会继续往下匹配。

勉强型:用问号来指定,这个量词匹配满足模式所需的最少字符数。因此也称作懒惰的、最少匹配的、非贪婪的、或不贪婪的。

占有型:这种类型的量词只有Java语言中才可用,并且更高级。当正则表达式被应用与字符串时,它会产生相当多的状态,以便在匹配失败时可以会说。而“占有的”量词并不保存这些中间状态,以防止他们回溯。他们常常用于防止正则表达式失控,因此可以使正则表达式执行起来更有效。

这部分太恶心了,暂时跳过,什么时候用什么时候看


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Book of CSS3

The Book of CSS3

Peter Gasston / No Starch Press / 2011-5-13 / USD 34.95

CSS3 is the technology behind most of the eye-catching visuals on the Web today, but the official documentation can be dry and hard to follow. Luckily, The Book of CSS3 distills the heady technical la......一起来看看 《The Book of CSS3》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码