1, 不可变 String
String 对象时不可变的 .String类中每一个看起来会修改String值得方法, 实际上都是创建一个全新的String对象 .
2, 重载 "+" 与 StringBuilder类.
2.1 "+" 和 "+="运算符
Java只重载了 "+" 和 "+="
这两个操作符,而且 Java 不允许程序员重载任何运算符 . Java在重载这两个运算符时自动创建一个StringBuilder
类的实例对象,然后使用append()
方法将字符串组装起来.
2.2 StringBuilder类.
一个可变的字符序列,此类提供一个和StringBuffer
兼容的API,但是 StringBuilder不是线程安全的 . 因此StringBuilder
的效率要比StringBuffer
高.使用率也较高.
如果需要处理多线程同步问题则建议使用StringBuffer
类.
注意 1 : 编译器优化问题
如果字符串操作比较简单那么可以使用
String
类,编译器会自动进行优化,但是如果有循环则必须自己创建StringBuilder
否则编译器会在每个循环内创建一个StringBuilder
这样的话效率低.
注意 2 : 无意识递归问题
// 测试类
public class InfiniteRecursion {
// 重写 String 方法.
@Override
public String toString(){
return "InfiniteRecursion address : " + this + '\n';
}
// mian 方法.
public static void main(String[] args){
InfiniteRecursion i = new InfiniteRecursion();
System.out.println(i);
}
}
上述代码执行后会产生堆栈溢出错误 :
Exception in thread "main" java.lang.StackOverflowError
at java.lang.String.length(String.java:623)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:414)
at java.lang.StringBuilder.append(StringBuilder.java:132)
at java.lang.StringBuilder.<init>(StringBuilder.java:110)
原因就是在这句"InfiniteRecursion address : " + this + '\n'
代码上,因为想要打印对象的内存地址而使用了 this
关键字. 但是 this
和 字符串
相加就会导致会将 this
强转成 String
类型也就是会调用 this
的 toString
方法, 也就出现了循环引用问题. 因此,此处不应该使用 this
而应该使用 super.toString()
.
3, 格式化输出
3.1 System.out.format()
Java SE5 引入了 format()
方法可用于 PrintStream
和 PrintWrite
对象.其中也包括System.out
对象.
示例代码 1 :
public class SimpleFormat {
public static void main(String[] args){
int x = 5;
double y = 5.11111;
// 方式一
System.out.println("x : " + x + " y : " + y);
// 方式二
System.out.format("x : %d y : %f\n",x,y);
// 方式三
System.out.printf("x : %d y : %f\n",x,y);
}
// 输出
/*
x : 5 y : 5.11111
x : 5 y : 5.111110
x : 5 y : 5.111110
*/
}
3.2 Formater 类
在 Java中 所有新的格式化功能都是由Formater类处理的 .具体使用可以查看JDK文档.
3.3 格式化说明符
抽象语法 :%[argument_index$][flag][width][.precision]conversion
-
width
: 用来设置最小宽度. -
pricision
: 设置最大宽度, (打印String
表示最多字符数、打印浮点数
小数点后的位数,不足则补零,多了进行四舍五入操作. - 最常用的格式化控制符如下 :
符号 | 含义 |
---|---|
d | 整数(十进制) |
c | Unicode 字符 |
b | Boolean 值 |
s | String |
f | 浮点数(十进制) |
e | 浮点数(科学计数) |
x | 整数(十六进制) |
h | 散列码(十六进制) |
% | 字符 %
|
3.4 String.format() 获取格式化字符串
Java SE5 中引入了 String.format()
方法 , 当只需要使用 format()
一次的情况可以使用 String.format()
.
3.5 十六进制转储工具
// 格式化工具类.
public class Hex {
// 格式化方法.
public static String format(final byte[] data) {
StringBuilder sb = new StringBuilder();
int address = 0;
for (byte b : data) {
// 每行显示 16 个数据.
if (address % 16 == 0) {
sb.append(String.format("%05X : ", address));
}
// 保存数据
sb.append(String.format("%02X ", b));
address ++;
// 判断是否是行尾
if (address % 16 == 0){
sb.append('\n');
}
}
sb.append('\n');
return sb.toString();
}
// 测试函数
public static void main(String[] args) {
final byte[] bs = new byte[100];
Arrays.fill(bs, (byte)1);
System.out.println(Hex.format(bs));
}
// 输出结果.
/*
00000 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00010 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00020 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00030 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00040 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00050 : 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00060 : 01 01 01 01
*/
}
4, 扫描输入类 Scanner
一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器.Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配.然后可以使用不同的 next 方法将得到的标记转换为不同类型的值.
// 从 System.in 中读取一个整数 .
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
// 扫描器还可以使用不同于空白的分隔符
String input = "1 fish 2 fish red fish blue fish";
Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
System.out.println(s.nextInt());
System.out.println(s.nextInt());
System.out.println(s.next());
System.out.println(s.next());
s.close();
// 使用正则表达式同时解析所有的 4 个标记
String input = "1 fish 2 fish red fish blue fish";
Scanner s = new Scanner(input);
s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
MatchResult result = s.match();
for (int i=1; i<=result.groupCount(); i++)
System.out.println(result.group(i));
s.close();