Java第十一课. 核心API02-String
回顾
1. lang包:java内置的基础包,程序会帮我们自动导入;
2. enum:安全检查功能,规范参数值;
3. 包装类:8个
Byte | Short | Integer | Long | Float | Double | Boolean | Character |
---|---|---|---|---|---|---|---|
byte | short | int | long | float | double | boolean | char |
4. 为什么要使用包装类,他是为了替代基本数据类型吗?
1. 和面向对象的思想一致,基本数据类型没有方法属性;
2. 和其它数据类型转换,需要用到包装类中的方法;
3. 不是替代,只是有些场合基本数据类型使用不了,比如集合;
5. 自动拆箱:自动将 包装类 变成 基本数据类型;
自动装箱:自动将 基本数据类型 变成 包装类;
jdk1.5 以上才支持自动拆装箱: 拆:Integer i=10;int a=i;
装:int a=1,Integer i=a;
6. Integer:将字符串转成整数:int a=Integer.parselnt(string);
Integer i=Integer.valueOf(string)
7. Character:判断是字母,数字,大写,小写
8. String: charAt(int index) contains() equals() length()
isEmpty() valueOf(int i) equalsIgnoreCase(String anotherSring) toUpperCase() toLowerCase()
1. String
1.1 [面试题] String的==和equals()判断方法
1. ==判断的是两个字符串的[地址]是否相同;
2. equals(ObjectanObjct)判断的是两个[字符串的内容]是否相同;
//[注]:1.Object类的equals()方法,其实是判断地址,而不是内容;
String 继承 Object 类,重写了equals方法,变成了判断的是字符串的内容;
//注意:关于equals()方法的代码规范:尽量使用非空对象来调用equals()方法.避免出现空指针异常;
public class TestString01 extends Object{
public static void main(String[] args) {
//从前端接收到一个用户名,我们想判断值是否是admin
String username=null;
//if (username.equals("admin")) {
if ("admin".equals(username)) {
System.out.println("admin登录");
}else {
System.out.println("登录失败");
}
Person person=new Person("张三", 0);
Person person2=new Person("张三", 0);
System.out.println(person==person2);//false
System.out.println(person.equals(person2));//false
}//只有String方法重写了equals方法
}
1.2 [面试题] String的不可变性
1. String 在JDk源码中,该类是被 final 修饰,不可被继承;
String 底层是字符数组,被 final 修饰,表示不可变。
2. 用代码演示不变性
1.3 [面试题] String拼接问题
public class TestString03 {
public static void main(String[] args) {
//关于String拼接的问题
String string="A";
for (int i = 0; i < 9; i++) {
string+=i;//此做法,会不断生成新的对象,会造成内存资源的浪费,可以通过debug打点看出
}
System.out.println(string);
}
}
[注意]:不能使用String进行字符串的拼接动作;
2. 类 StringBuffer
2.1 概念
[概念]:[线程安全的可变字符序列]。一个类似于 String 的字符串缓冲区,但[能修改]。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
构造方法摘要 |
---|
StringBuffer 构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符。 |
StringBuffer(String str) 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容 |
2.2 常见方法:
int | capacity() 返回当前容量 |
---|---|
StringBuffer | append(String str) 将指定的字符串追加到此字符序列 |
char | charAt(int index) 返回此序列中指定索引处的 char 值 |
StringBuffer | reverse() 将此字符序列用其反转形式取代 |
public class TestStringBuffer {
public static void main(String[] args) {
// 创建一个StringBuffer对象
StringBuffer sBuffer=new StringBuffer("abc");
sBuffer.append("xyz");
System.out.println(sBuffer);//abcxyz
String string=new String("abc");
string="xyz";
System.out.println(string);//xyz
}
}
3. 类 StringBuilder
3.1 概念
一个可变的字符序列。这个类提供了一个API兼容StringBuffer,但无法保证同步.非线程安全;
构造方法 |
---|
StringBuilder() 构造一个没有字符的字符串生成器,并构造了16个字符的初始容量。 |
StringBuilder(String str) 构造一个初始化为指定字符串的内容的字符串生成器。 |
public class TestStringBuilder {
public static void main(String[] args) {
StringBuilder sBuilder=new StringBuilder("xyz");
}
}
4.【面试题:String和StringBuffer和StringBuilder】
4.1 问题: StringBuffer/ StringBuilder和String区别
String | StringBuffer | StringBuilder | |
---|---|---|---|
是否可变 | 不可变 | 可变 | 可变 |
线程同步安全 | 不同步 | 同步 | 不同步 |
4.2 问题: StringBuffer/ StringBuilder和String如何转换
public class TestChange {
public static void main(String[] args) {
//将String转换成StringBuffer与StringBuilder
String string="abc";
StringBuffer sbBuffer=new StringBuffer(string);
StringBuilder sBuilder=new StringBuilder(string);
System.out.println(sbBuffer.getClass().getName());//java.lang.StringBuffer
System.out.println(sBuilder.getClass().getName());//java.lang.StringBuilder
//怎么将StringBuffer与StringBuilder转成String
String string2=sbBuffer.toString();
System.out.println(string2.getClass().getName());//java.lang.String
String string3=sBuilder.toString();
}
}
4.3 问题: StringBuffer和StringBuilder相比为什么支持线程同步
StringBuffer:有一个线程同步的关键字,效率比较低,相对安全;
StringBuilder:无线程同步的关键字,效率高;
synchronized :用于指定多线程代码中的同步方法、变量或者代码块。
StringBuffer 与 StringBuilder 共同特征:可变性;
不同:一个线程安全,一个非线程安全;
//当有多个线程同时对一个字符串操作,StringBuffer因为有线程同步关键字,相当于上了一把锁,只有当其中一个线程操作完成,锁才会打开,下一个线程才能对其操作,所以效率较低,但相对安全;反之StringBuilder因为没有关键字,所以效率高,非线程安全;
5.方法的参数传递
5.1 基本数据类型作为参数【值传递】
public class MethodParameterTest {
public void changeInt(int a) {//形参
//改变
a=a+2;
System.out.println("changeInt:a="+a);//3
}
public static void main(String[] args) {
MethodParameterTest mp=new MethodParameterTest();
System.out.println("----基本数据类型作为参数【值传递】------");
int a=1;
mp.changeInt(a);//实参,将a的值拷贝一份给方法changeInt()的形参,值传递
System.out.println("main:a="+a);//1
}
}
基本数据类型作为参数,传递的是值的一个副本给形参,在方法内对形参的操作,不影响实参的值。
5.2 引用数据类型(数组、类)作为参数【引用传递】
将数组作为参数:
/**
* 数组作为参数
* @param args
*/
public void changeArray(int[] array) {
//改变数组的内容,将数组中的每一个元素*2
for (int i = 0; i < array.length; i++) {
array[i]=array[i]*2;
}
//再一次输出
for (int i = 0; i < array.length; i++) {
System.out.print("changeArray:数组元素:"+array[i]+" ");
}
}
测试类:
System.out.println("----数组作为参数【引用传递】------");
int[] array= {1,2,3};//array引用名在栈中,{1,2,3}真正的值在堆中
mp.changeArray(array);//2 4 6 将array引用名[堆的地址]传递给方法changeArray()的形参array,
//和当前形参,两个引用名其实指向的是堆中的同一个对象
for (int i = 0; i < array.length; i++) {
System.out.print("mainArray:数组元素:"+array[i]+" "); //2 4 6
}
把类作为参数:
/**
* 将类作为参数
* 自定义Dog
*
*/
public void changeObject(Dog dog) {
//dog=new Dog();//如果重新new 就是一个新的对象
dog.setName("哈巴狗");
System.out.println("changeObject 狗信息:"+dog.getName()); //哈巴狗
}
测试类:
System.out.println("------类作为参数传递[引用传递]---------");
Dog dog=new Dog();
dog.setName("哈士奇");
mp.changeObject(dog);
System.out.println("main:狗信息"+dog.getName()); //哈巴狗
原理和上面数组传参一样
数组、类等引用数据类型作为参数,传递的引用名的值其实是堆的地址给形参,则实参和形参两个引用名指向堆中的同一个对象,在方法体中对该地址中的值改变就会影响实参。
5.3 Sting字符串作为参数【值传递】
函数定义和函数调用:
/**
* 字符串String 引用类型作为参数 值传递
* @param args
*/
public void changeString(String str) {
str="world";//对str重新赋值,会重新开辟一个对象
System.out.println("changeString:str="+str);//world
}
测试类:
System.out.println("----String作为参数【值传递】------");
String str="Hello";
mp.changeString(str);
System.out.println("main:str="+str);//Hello
String传递的时候,其实也是将实参引用名中的堆的地址传递给形参,因为String具有不可变性,当方法体内对该地址的字符串重新赋值,则相当于在内存在重新创建了一个对象,不影响实参。
6. 总结:[值传递与引用传递]
[值传递]
(形式参数类型是基本数据类型):
方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。
[引用传递]
(形式参数类型是引用数据类型参数):
也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。
练习
public class TestMethod {
public static void main(String[] args) {
String s1="abc";
String s2="xyz";
changeStr(s1, s2);//值传递
System.out.println("执行方法后"+s1+"----"+s2);//abc xyz
System.out.println();
StringBuffer sb1=new StringBuffer("abc");
StringBuffer sb2=new StringBuffer("xyz");
changeStr(sb1, sb2);//引用传递
System.out.println("执行方法后"+sb1+"----"+sb2);//(=不会改变内容,而改变指向)abc----xyzxyz
}
public static void changeStr(StringBuffer sb1,StringBuffer sb2) {
sb1=sb2;//sb1和sb2的指向是一致的,在方法内,sb1临时指向 了sb2的内存xyz
sb2.append(sb1); //sb2=xyz sb1=xyz 经过append()sb2指向的内存对象又追加了xyz->xyzxyz
System.out.println("方法中:"+sb1+"----"+sb2);// xyzxyz----xyzxyz
}
public static void changeStr(String s1,String s2) {
s1=s2;//s1和s2的指向是一致的,指向xyz
s2=s1+s2;
System.out.println("方法中:"+s1+"----"+s2);//xyz xyzxyz
}
}
方法中:xyz----xyzxyz
执行方法后abc----xyz
方法中:xyzxyz----xyzxyz
执行方法后abc----xyzxyz
7. 字符串类小结:
1) String 和 StringBuffer 、 StringBuilder 相比, String 是不可变的, String 的每次修改操作都是在内存中重新 new 一个对象出来,而 StringBuffer 、 StringBuilder 则不用,并且提供了一定的缓存功能,默认16个字节数组的大小,超过默认的数组长度时,则扩容为原来字节数组的长度*2+2。
2) StringBuffer 和 StringBuilder 相比, StringBuffer 是 synchronized 的,是线程安全的,而 StringBuilder 是非线程安全的,单线程情况下性能更好一点;使用 StringBuffer 和 StringBuilder 时,可以适当考虑下初始化大小,减少扩容的次数,提高代码的高效性。
3) 方法传递:值传递(将基本数据类型, String 作为参数)->形参与实参的值互不影响,引用传递(将引用类型作为参数)->形参与实参的值相互影响;
8. 练习
1.编写一个程序,将下面的一段文本中的各个单词的字母顺序翻转,
“To be or not to be",将变成"oT eb ro ton ot eb."。
1)split(" ")-根据空格split;
2)遍历每一个元素,然后反转;
public class Testhw01 {
/**
* 1.编写一个程序,将下面的一段文本中的各个单词的字母顺序翻转,
“To be or not to be",将变成"oT eb ro ton ot eb."。
1)split(" ")-根据空格split
2)遍历每一个元素,然后反转
*/
@Test
public void test01() {
String string="To be or not to be";
String[] strs=string.split(" ");//通过空格去拆分,因为to be之间是空格,如果是to,be,参数就为","
//System.out.println("长度:"+strs.length);//6
for (int i = 0; i < strs.length; i++) {
//System.out.println(strs[i]);
StringBuilder sBuilder=new StringBuilder(strs[i]);
//System.out.print(sBuilder.reverse()+" ");
System.out.print(sBuilder.reverse().append(" "));
}
}
}
oT eb ro ton ot eb