目录
一. StringBuilder和StringBuffer
String类的特点:任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指 向而已。
Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象:
●String不可变字符串
●StringBuilder可变字符串public static void main(String[] args) { String不可变字符串 //StringBuilder可变字符串 //StringBuilder(); 无参构造创建,初始化数组char[]的容量为16,扩容<<1+2容量够,则直接返回newCapcity ,如果扩容后容量不够newCpacity = minCpacity //StringBuilder(容量); 初始化容量为指定容量的char[]数组 //StringBuilder(str); super(str.length() + 16); StringBuilder sb = new StringBuilder("我爱学习"); for (int i = 0; i < 100; i++) { // 追到到末尾 sb.append(i).append(","); } // insert追加内容到指定位置 sb.insert(0, "你好"); String str = null;// StringBuilder可以追加null sb.append(str); System.out.println(sb); }
扩容机制:
链式操作:
如果我们查看StringBuilder的源码,可以发现,进行链式操作的关键是,定义的append()方法会返回this,这样,就可以不断调用自身的其他方法。
一些方法:
●replace(start, end, str) 替换指定区间的字符串
StringBuilder sb = new StringBuilder("还是想考研"); // replace(start, end, str) 替换指定区间的字符串 sb.replace(0, 1, "zkt"); System.out.println(sb);// zkt是想考研
●reverse() 反转
// 反转 StringBuilder sb = new StringBuilder("还是想考研"); sb.reverse(); System.out.println(sb);// 研考想是还
●delete(起始,结束)::删除从start(包含)到end(不包含)位置的字符,start为0~length-1,end可以超出长度。
sb.delete(4, 8);
●deleteCharAt(下标):删除某个索引位置上的字符,index不能越界
sb.deleteCharAt(5);
细节:
由于StringBuilder和StringBuffer没有重写equals方法,所以还是使用的Object的equals方法。对比的是两个对象的地址是否相等。为了比较StringBuilder和StringBuffer字符串内容是否相等,需要先将其转换为string,String 由于重写了equals方法,所以使用equals函数是对比两个字符串内容是否相等。
StringBuilder sb1 = new StringBuilder("abc"); StringBuilder sb2 = new StringBuilder("abc"); System.out.println("地址是否相等" + (sb1 == sb2));// 地址是否相等false // 没有重写equals,比较的仍旧是地址 System.out.println("内容是否相等" + (sb1.equals(sb2)));// 内容是否相等false System.out.println(sb1.toString().equals(sb2.toString()));// true
区别:
●StringBuilder 类的继承和实现一样 1.5 线程不安全 性能好
●StringBuffer 类的继承和实现一样 JDK1.0 线程安全 效率相对差一点点StringBuffer sbBuffer=new StringBuffer(); sbBuffer.append("a");
String[] nameString = { "zkt1", "zkt2", "zkt3", "zkt4" }; StringBuilder sb = new StringBuilder(); for (int i = 0; i < nameString.length; i++) { sb.append(nameString[i]).append(","); } //sb.replace(sb.length()-1, sb.length(), "!"); sb.deleteCharAt(sb.length()-1).append("还是想考研!"); System.out.println(sb);//zkt1,zkt2,zkt3,zkt4还是想考研!
StringBuilder拼接:
单参构造方法:参数含义每个元素之间的拼接符
//单参构造方法:参数含义每个元素之间的拼接符 StringJoiner sj =new StringJoiner(",");
多参构造方法:
参数1:连接符
参数2:拼接结果的字符串的开始字符串
参数3:拼接结果的字符串的结束字符串// 多参构造方法: // 参数1:连接符 // 参数2:拼接结果的字符串的开始字符串 // 参数3:拼接结果的字符串的结束字符串 StringJoiner sj =new StringJoiner(",", "hello:", "!");
实例:
String[] nameString = { "zkt1", "zkt2", "zkt3", "zkt4" }; // 单参构造方法:参数含义每个元素之间的拼接符 // StringJoiner sj =new StringJoiner(","); // 多参构造方法: // 参数1:连接符 // 参数2:拼接结果的字符串的开始字符串 // 参数3:拼接结果的字符串的结束字符串 StringJoiner sj =new StringJoiner(",", "hello:", "!"); for (String str : nameString) { sj.add(str); } System.out.println(sj);//hello:zkt1,zkt2,zkt3,zkt4! //如果只对数组中元素进行拼接,开头结尾没元素,String.join方法简便 String string = String.join(",", nameString); System.out.println(string);//zkt1,zkt2,zkt3,zkt4
小结:
●StringBuilder是可变对象,用来高效拼接字符串。
●StringBuilder可以支持链式操作,实现链式操作的关键是返回实例本身。
●StringBuffer线程安全(现在很少使用),性能较差;StringBuilder线程不安全,但性能较好。
二. 包装类
在Java中,数据类型被分两种:基本类型和引用类型。引用类型可以赋值为null,表示空,但基本类型不能赋值为null:
●基本类型:byte,short,int,long,boolean,float,double,char
●引用类型:所有class和interface类型、数组String s = null; int n = null; // compile error!
Java核心库为每种基本类型都提供了对应的包装类型, 我们可以直接使用,并不需要自己去定义:
基本类型
对应的引用类型
boolean
java.lang.Boolean
byte
java.lang.Byte
short
java.lang.Short
int
java.lang.Integer
long
java.lang.Long
float
java.lang.Float
double
java.lang.Double
char
java.lang.Character
创建对象:
●new操作符创建Integer对象
//new操作符创建Interger对象 Integer n =new Integer("22"); int i = 10; Integer n1 =new Integer(i);
●调用valueOf方法创建Integer对象(发生方法的重载)
//调用valueOf方法创建Interger对象 Integer n2 = Integer.valueOf(20); Integer n3 = Integer.valueOf("99");
自动装箱:
因为int和Integer可以互相转换,所以,Java编译器可以帮助我们自动在int和Integer之间自动进行类型转换:
自动装箱: 基本数据类型-->引用数据类型
这种直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing)
编译器自动使用Integer.valueOf(int)
// 自动装箱: 基本数据类型-->引用数据类型 int i1 = 10; Integer n1 = i1; // Integer.valueOf(i1)自动装箱 System.out.println(n1.toString());
自动拆箱:
自动拆箱: 基本数据类型<--引用数据类型
把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)
编译器自动使用Integer.intValue()
// 自动拆箱: 基本数据类型<--引用数据类型 Integer n2 = new Integer(99); int i2 = n2; // n2.intValue();自动拆箱 System.out.println(i2);
装箱和拆箱会影响代码的执行效率,因为编译后的class代码是严格区分基本类型和引用类型的。并且,自动拆箱执行时可能会报NullPointerException
// 自动拆箱可能会有异常,不能为null,不然会出现NullPointerException Integer n3 = null; int i3 = n3; System.out.println(i3);
注意:自动装箱和自动拆箱只发生在编译阶段,目的是减少代码量
缓存池:
可以发现,==比较,较小的两个相同的Integer返回true,较大的两个相同的Integer返回false,这是因为Integer内部已经把-128~+127在缓存池中已经创建好了。所以,编译器把Integer x = 127;自动变为Integer x = Integer.valueOf(127);就可以直接使用缓存池中的127,从而节省内存。所以,基于缓存池的存在,Integer.valueOf()对于-128~+127之间的数字,始终返回相同的实例,因此,==比较“恰好”为true,但我们绝不能因为Java标准库的Integer内部有缓存优化就用==比较,必须用equals()方法比较两个Integer。
//Integer.valueOf() 缓存池 -128-127之间 Integer i1 = Integer.valueOf(127); Integer i2 = Integer.valueOf(127); System.out.println(i1 == i2);//true System.out.println(i1.equals(i2));//true Integer i3 = Integer.valueOf(128); Integer i4 = Integer.valueOf(128); System.out.println(i3 == i4);//false System.out.println(i3.equals(i4));//true //new开辟新空间 Integer i5 = new Integer(100); Integer i6 = new Integer(100); System.out.println(i5 == i6);//false
进制转换:
进制转换 String<--->int:
●Integer.parseInt();对应进制的字符串转成10进制的整数
// Integer.parseInt();对应进制的字符串转成10进制的整数 int x1 = Integer.parseInt("10");// 10进制字符串10->10进制整数10 System.out.println("10进制字符串->10进制整数" + x1);// 10
int x2 = Integer.parseInt("10", 2);// 2进制字符串10->10进制整数2 System.out.println("2进制字符串10->10进制整数" + x2);// 2
●Integer还可以把整数格式化为指定进制的字符串
// Integer.toString();10进制整数转成对应进制的字符串 String s1 = Integer.toString(100);// 10进制整数100->10进制字符串 System.out.println("10进制整数100->10进制字符串" + s1);// 100 String s2 = Integer.toString(5, 2);// 10进制整数5->2进制字符串 System.out.println("10进制整数5->2进制字符串" + s2);// 101 // 将10进制的整数转成16,8,2进制的字符串 // 10->16 String hexString = Integer.toHexString(15); System.out.println(hexString);// f // 10->8 String octString = Integer.toOctalString(8); System.out.println(octString);// 10 // 10->2 String binString = Integer.toBinaryString(5); System.out.println(binString);// 101
一些常量:
Java的包装类型还定义了一些有用的静态变量:
System.out.println(Integer.MAX_VALUE);//2147483647 System.out.println(Integer.MIN_VALUE);//-2147483648 System.out.println(Long.SIZE);//64 System.out.println(Long.BYTES);//8 System.out.println(Long.MAX_VALUE);//9223372036854775807 System.out.println(Long.MIN_VALUE);//-9223372036854775808
最后,所有的整数和浮点数的包装类型都继承自Number,因此,可以非常方便地直接通过包装类型获取各种基本类型:
Integer i1 = new Integer(128); System.out.println(i1.byteValue());//-128 System.out.println(i1.shortValue());//128
// 向上转型为Number: Number num = new Integer(999); // 获取byte, int, long, float, double: byte b = num.byteValue(); int n = num.intValue(); long ln = num.longValue(); float f = num.floatValue(); double d = num.doubleValue();
小结:
●Java核心库提供的包装类型可以把基本类型包装为class
●自动装箱和自动拆箱都是在编译期完成的(JDK>=1.5)
●装箱和拆箱会影响执行效率,且拆箱时可能发生NullPointerException
●包装类型的比较必须使用equals()
●整数和浮点数的包装类型都继承自Number