目录
- 一、String简介:
- 二、String的创建方式:
- 面试题一:String s = new String("abc");方式创建对象,在内存中创建了几个对象?
- 四、一个笔试题:
- 五、字符串的常用方法:
- String和基本类型数据的转换:
- String 与char[]之间的转换:
- String 与byte[]之间的转换:
- String、StringBuffer与StringBuilder之间区别:
- String、StringBuffer与StringBuilder底层源码分析:
- String与StringBuffer/StringBuilder之间转换:
- 总结String与常用类型之间的转换:
- StringBuffer/StringBuilder常用方法:
- 对比三者的效率:
一、String简介:
String:字符串,使用一对“”引起来表示。
1.String 声明为final的,不可被继承。
2.Stirng 实现了了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:b表示String可以比较大小。
3.String内部定义了final char[] value 用于存储字符串数据。
4.String:代表不可以变的字符序列。
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串。
注意:不可变性主要体现三点:
1.对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2.当对现有的字符串赋值时,有需要重新指定内存区域赋值,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3.当调用String的replace()方法修改指定字符或者字符串时,也需要重新指定内存区域重新赋值。
代码演示:
package com.fan.domain;
import org.junit.Test;
public class StringTest {
@Test
public void test1(){
String s1 = "abc";
String s2 = "abc";
//1.对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
s1 = "hello";
System.out.println(s1 == s2);//比较的是地址
System.out.println(s1);
System.out.println(s2);
System.out.println("***************");
//2.当对现有的字符串赋值时,有需要重新指定内存区域赋值,
// 也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
String s3 ="abc";
s3 += "def";
System.out.println(s3);//abcdef
System.out.println(s2);
System.out.println("***************");
//3.当调用String的replace()方法修改指定字符或者字符串时
// ,也需要重新指定内存区域重新赋值。
String s4 = "abc";
String s5 = s4.replace('a','m');
System.out.println(s4);//abc
System.out.println(s5);//mbc
}
}
注意:jdk1.6的时候字符串常量池在方法区。
jdk1.7的时候,字符串常量池已经被安排在堆里面了。
jdk1.8中 字符串常量池是在堆里面。
二、String的创建方式:
常见的两种方式:
方式一:通过字面量的方式定义。
方式二:通过new + 构造器 的方式。
面试题一:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?
回答:两个。前提是常量池中没有字符串常量“abc”;其中一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”;
三、String内存结构:
字符串拼接:
结论:
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中。
四、一个笔试题:
内存图详解:
上述代码解释:最终输出good和best
注意:栈中存的是局部变量和对象的引用。
堆中存的是对象本身(包含对象的属性)
先从main方法开始执行。创建了一个本类的对象,然后对象调用其方法change().==这里特别注意,change()参数中是一个新的局部变量str,和ch,不是成员变量str和ch,局部变量的范围是在其{}内。方法执行完后局部变量失效。传递的本质都是地址值。
jvm中常量池到底在哪里:
总结:jvm中字符串常量池存放位置说明:
jdk1.6:字符串常量池存储在方法区(永久区)
jdk1.7:字符串常量池存在于堆空间中
jdk1.8:字符串常量池存在于堆中(上图有误)
五、字符串的常用方法:
1.charAt(int index)类似于数组中取指定位置的元素一样,通过字符串的封装取指定索引处 的元素。
String和基本类型数据的转换:
基本数据类型,包装类—>String类型
基本数据类型,包装类—>String类型:调用String.valueOf(基本类型);
int num1=10;
方法1:
String str1= num1+"";
方法2:调用String的valueOf()
float f1=12.3f;
String str2 = String.valueOf(f1);
String类型–>基本数据类型和包装类:都需要调用包装类的parseXXX(String s);
String s=“123”;
int num2 = Integer.parseInt(s);
Integer a1 = Integer.parseInt(s);
String 与char[]之间的转换:
String --> char[] :调用String的toCharArray()方法。
char[] --> String :调用String的构造器String(char value[])。
String 与byte[]之间的转换:
编码:String–> byte[]:调用String的getBytes()方法
解码:byte[] --> String: 调用String的构造器 String(byte[] bytes);
代码演示:
StringBuffer与StringBuilder:
String、StringBuffer与StringBuilder之间区别:
String:不可变的字符序列,使用final修饰;底层使用char[]存储。
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储。
StringBuilder:可变的字符序列:jdk5.0新增。线程不安全,效率高;底层使用char[]存储;
String、StringBuffer与StringBuilder底层源码分析:
源码分析:
String源码分析:构造器中显式容量是多少容量,就是多少容量
String str = new String();//底层是:char[] value = new char[0];
String str1 = new String(“abc”);//底层char[] value = new char[]{‘a’,‘b’,‘c’};
而StringBuffer不一样:
StringBuffer sb1 = new StringBuffer();//底层char[] value = new char[16],底层创建了一个长度16容量。StringBuffer空参构造默认容量是16个。
println(sb1.length());
sb1.append(‘a’);//value[0] = ‘a’;
sb1.append(‘b’);//value [1] = ‘b’;
//带字面量的方式:此种方式容量是字面量的容量加上16
StringBuffer sb2 = new StringBuffer(“abc”);//char[] value = new char[’‘abc’.length()+16];
问题一:println(sb2.length());//3,底层是数组的有效元素的个数count.
问题二:扩容问题:如果要添加的数据底层数组放不下,那就需要扩容底层数组容量。默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组汇总。
指导意义:开发中减一大家使用StringBuffer(int capacity) 或者StringBuilder(int capacity) 来预测并制定大概容量。
String与StringBuffer/StringBuilder之间转换:
String–> StringBuffer/StringBuilder:调用StringBuffer/StringBuilder构造器StringBuffer(String str)
StringBuffer/StringBuilder–>String:(方式1)调用StringBuffer/StringBuilder的toString(),方式2:调用String的构造器String(StringBuffer buffer)。
代码演示:
@Test
public void test3(){
//String--> StringBuffer/StringBuilder:调用StringBuffer/StringBuilder构造器
String str = "hehe";
StringBuffer stringBuffer = new StringBuffer(str);
System.out.println(stringBuffer);
//StringBuffer/StringBuilder-->String:
StringBuilder sb = new StringBuilder("hello");
//方式一
String s = new String(sb);
//方式二
String s1 = sb.toString();
System.out.println(s1);
}
总结String与常用类型之间的转换:
StringBuffer/StringBuilder常用方法:
1.StringBuffer append(char c):添加参数到StringBuffer对象中
2.StringBuffer insert( int offset,String str):将字符串中的offset位置插人字符串str
3.StringBuffer deleteCharAt(int index):移除此序列指定位置的字符
4.StringBuffer delete(int start,int end):删除StringBuffer对象中指定范围的字符或字符串序列
5.StringBuffer replace( int start,int end,String s):在Stringuffer对象中替换指定的字符或字符串序列
6.void setCharAt(int index, char ch):修改指定位置index处的字符序列
7.String toString():返回StringBuffer缓冲区中的字符串
8.StringBuffer reverse():将此字符序列用其反转形式取代
常用方法总结:
增:append(xxx)
删:delete(int start ,int end)
改:setCharAt(int i,char ch)修改单个字符/replace(int start,int end ,String str):替换多个字符串
查:charAt(int i):查找制定索引处的字符
插:intsert(int offset ,xxx):将制定字符从哪里开始插入
长度:length();
遍历:for() + charAt(int i) /toString()
对比三者的效率:
从高到低排列:StringBuilder > StringBuffer > String