在C
语言中,是没有字符串类型的,但是有字符串
char* p = "hello";
在Java
中,是有字符串这种数据类型的,但是他不是所谓的以\0
为结尾的,是通过长度判断字符串是否结尾
使用常量串构造
public class TestDemo1 {
public static void main(String[] args) {
//使用常量串构造
String str1 = "hello";
System.out.println(str1);
}
}
直接new
String
对象
public class TestDemo1 {
public static void main(String[] args) {
//直接new String对象
String str2 = new String("hello2");
System.out.println(str2);
}
}
使用字符数组进行构造
public class TestDemo1 {
public static void main(String[] args) {
//使用字符数组进行构造
char[] array = {'h','e','l','l','o','3'};
String str3 = new String(array);
System.out.println(str3);
}
}
注意:
String
是引用类型,内部并不存储字符串本身,其实底层就是数组
内存分配图
public class TestDemo1 {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("world");
String str3 = str1;
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
两个方法
s1.length()
:获取字符串长度
注意:要带上后面的括号
public class TestDemo1 {
public static void main(String[] args) {
String str1 = new String("hello");
System.out.println(str1.isEmpty());
System.out.println("hello".length());
}
}
s1.isEmpty()
:如果字符串长度为0,返回true
,否则返回false
public class TestDemo1 {
public static void main(String[] args) {
String str1 = new String("hello");
System.out.println(str1.isEmpty());
}
}
比较是否引用同一个对象
对于内置类型,比较的是值是否相等
对于引用类型,比较的是引用中的地址是否相同
public class TestDemo2 {
public static void main(String[] args) {
//只要你进行new,就会开辟新的内存空间
String str1 = new String("hello");
String str2 = new String("hello");
String str3 = new String("world");
String str4 = str1;
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//false
System.out.println(str1 == str4);//true
}
}
比较两个字符串是否相等:按照字典序进行比较
字典序:就是按照字典中出现的先后顺序进行排序。
String
类重写了父类当中的equals
方法,以前equals
是按照地址进行比较的,被equals
重写之后按照以下规则进行比较
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
这个方法的使用:
public class TestDemo3 {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
String str3 = new String("Hello");
System.out.println(str1.equals(str2));//true
System.out.println(str1.equals(str3));//false
}
}
比较两个字符串的大小:按照字典序进行比较
k
个字符相等(k
为两个字符长度最小值),返回值两个字符串长度差值public class TestDemo4 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("ac");
String str3 = new String("abc");
String str4 = new String("abcdef");
System.out.println(str1.compareTo(str2));//-1 -> 不同输出字符差值-1
System.out.println(str1.compareTo(str3));//0 -> 相同输出 0
System.out.println(str1.compareTo(str4));//-3 -> 前k个字符完全相同,输出长度差值-3
}
}
与int compareTo(String s)
相同,但是这个忽略大小写
public class TestDemo4 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("ac");
String str3 = new String("abc");
String str4 = new String("abcdef");
System.out.println(str1.compareToIgnoreCase(str2));//-1 -> 不同输出字符差值-1
System.out.println(str1.compareToIgnoreCase(str3));//0 -> 相同输出 0
System.out.println(str1.compareToIgnoreCase(str4));//-3 -> 前k个字符完全相同,输出长度差值-3
}
}
返回index
位置上字符,如果index
为负数或者越界,抛出IndexOutOfBoundsException
异常
public class TestDemo1 {
public static void main(String[] args) {
String str = "hello";
char ch = str.charAt(1);
System.out.println(ch);//e
}
}
注意:下标必须合法
四种形式:
int indexOf(int ch)
:返回ch
第一次出现的位置,没有返回-1int indexOf(int ch,int fromIndex)
:从fromIndex
开始,返回ch
第一次出现的位置,没有返回-1int indexOf(String str)
:返回字符串str
第一次出现的位置,没有返回-1int indexOf(String str,int fromIndex)
:从fromIndex
开始,返回str
第一次出现的位置,没有返回-1public class TestDemo2 {
public static void main(String[] args) {
String str = "hello";
int index1 = str.indexOf('h');
System.out.println(index1);//0
int index2 = str.indexOf('o',2);
System.out.println(index2);//4
int index3 = str.indexOf("ll");
System.out.println(index3);//2
int index4 = str.indexOf("ll",1);
System.out.println(index4);//2
}
}
四种形式:
int lastIndexOf(int ch)
:从后往前找,返回ch
第一次出现的位置,没有返回-1int lastIndexOf(int ch,int fromIndex)
:从fromIndex
位置开始找,从后往前找ch
第一次出现的位置,没有返int lastIndexOf(String str)
:从后往前找,返回str
第一次出现的位置,没有返回-1int lastIndexOf(String str,int fromIndex)
:从fromIndex
位置开始找,从后往前找str
第一次出现的位置,没有返public class TestDemo3 {
public static void main(String[] args) {
String str = "hello";
int index1 = str.lastIndexOf('h');
System.out.println(index1);//0
int index2 = str.lastIndexOf('l',4);
System.out.println(index2);//3
int index3 = str.lastIndexOf("ll");
System.out.println(index3);//2
int index4 = str.lastIndexOf("ll",4);
System.out.println(index4);//2
int index5 = str.lastIndexOf('l',2);//从2下标往前找->找不到->返回-1
System.out.println(index5);//-1
}
}
public class TestDemo1 {
public static void main(String[] args) {
int a = 10;
String str1 = String.valueOf(a);
System.out.println(str1);//"10:
System.out.println(str1 + 1);//"101" -> 能证明str变成字符串了
System.out.println("---------------");
String str2 = "1234";
int num1 = Integer.valueOf(str2);
int num2 = Integer.parseInt(str2);//跟上面那种是等价的
double num3 = Double.valueOf(str2);//也可以转换成double类型的
System.out.println(num1);//1234
System.out.println(num2);//1234
System.out.println(num3);//1234.0
}
}
需要我们知道的是:大小写转换的操作的不是原数组,是把拷贝的数组进行大小写转换的
public class TestDemo2 {
public static void main(String[] args) {
String str1 = "hello";
String str2 = str1.toUpperCase();
System.out.println(str2);//HELLO
System.out.println("----------------");
String str3 = "HELLO";
String str4 = str3.toLowerCase();
System.out.println(str4);//hello
System.out.println("----------------");
String str5 = "H_e!L#l%O";
String str6 = str5.toLowerCase();//只会对字母起作用
System.out.println(str6);//h_e!l#l%o
}
}
import java.util.Arrays;
public class TestDemo3 {
public static void main(String[] args) {
String str1 = "hello";
char chars[] = str1.toCharArray();
System.out.println(Arrays.toString(chars));//[h, e, l, l, o]
}
}
public class TestDemo4 {
public static void main(String[] args) {
String str = String.format("%d-%d-%d",2022,6,6);
System.out.println(str);//2022-6-6
}
}
使用一个指定的新的字符串替换掉已有的字符串数据
把regex
替换成replacement
String replace(String oldChar,String newChar)
:把oldChar
替换成newChar
String replaceAll(String oldChar,String newChar)
:替换所有的指定内容String replaceFirst(String oldChar,String newChar)
:替换第一个为oldChar
的内容public class TestDemo5 {
public static void main(String[] args) {
String str1 = "abcdabcdabcd";
String str2 = str1.replace("ab","li");//其实跟replaceAll一样
System.out.println(str2);//licdlicdlicd
String str3 = str1.replaceAll("ab","kj");
System.out.println(str3);
String str4 = str1.replaceFirst("ab","op");
System.out.println(str4);
}
}
在这里,我们操作的也不是原数组.
在
Java
中,所有对字符串本身操作的函数,都不是在原来的字符串对象上进行的操作,因为字符串是不可变的
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
String[] split(String regex)
:将字符串全部拆分String[] split(String regex,int limit)
:将字符串以指定的格式,拆分为limit
组public class TestDemo6 {
public static void main(String[] args) {
String str1 = "abc de f g";
String[] strings = str1.split(" ");
for (String s : strings) {
System.out.println(s);
}
}
}
拆分ip
地址
public class TestDemo6 {
public static void main(String[] args) {
String str2 = "162.190.1.1";
String[] strings = str2.split("\\.",4);//最多分割为4组
for (String string : strings) {
System.out.println(string);
}
}
}
注意事项:
举栗子:
public class TestDemo6 {
public static void main(String[] args) {
String str3 = "Hello0606 english&888";
String[] strings = str3.split(" |&");
for (String string : strings) {
System.out.println(string);
}
}
}
public class TestDemo6 {
public static void main(String[] args) {
String str4 = "hello\\666";
String[] strings = str4.split("\\\\");//\->\\ \\->\\\\
for (String string : strings) {
System.out.println(string);
}
}
}
多次拆分:
public class TestDemo6 {
public static void main(String[] args) {
String str5 = "name=zhangsan&age=18";
String[] strings1 = str5.split("&");
for (String str : strings1) {
String[] strings2 = str.split("=");
for (String str2 : strings2) {
System.out.println(str2);
}
}
}
}
从一个完整的字符串之中截取出部分内容。
String substring(int beginIndex)
:从指定索引截取到结尾String substring(int beginIndex,int endIndex)
:从beginIndex
截取到endIndex
public class TestDemo7 {
public static void main(String[] args) {
String str1 = " abde sdfi ";
String ret1 = str1.substring(2,7);//from to -> 前闭后开 [2,7)
System.out.println(ret1);// abde
}
}
String trim()
:去掉字符串中的左右空格,保留中间空格
public class TestDemo8 {
public static void main(String[] args) {
String str1 = " abde sdfi ";
String ret2 = str1.trim();
System.out.println(ret2);//abde sdfi->去掉左右两边空格,中间的不去掉
System.out.println(ret1);// abde sdfi ->证明了操作字符串操作的不是本身
}
}
我们先看这段代码
public class demo_2_9 {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);//true
}
}
我们的猜想是:两个字符串,实际上不是新new
出来的吗?new
出来的不就是新的吗?那不应该是false
吗.但是答案是true
我们继续看例子
public class demo_2_9 {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
System.out.println(str1 == str2);//true
System.out.println(str1 == str3);//false
}
}
这时候,str1
和str3
就不相等了.这是怎么回事呢?
这一切都是字符串常量池搞的鬼.
字符串常量池一般都在堆上
特例:
public static void main(String[] args) {
String str1 = "hello";
String ret = "he" + "llo";//在编译的时候,这里就直接认为是hello了
System.out.println(str1 == ret);//true
}
public static void main(String[] args) {
String str1 = "hello";
String str2 = "he";
String str3 = "llo";
String str4 = str2 + str3;//str2 str3是变量,在编译的时候,还不知道里面是谁
System.out.println(str1 == str4);//false
}
记住,只要是new
的,就是一定有新对象产生的
public static void main(String[] args) {
char[] ch = new char[]{'a','b','c'};
String str = new String(ch);
String str2 = "abc";
System.out.println(str == str2);
}
运行结果为:false
图解:
加入intern
之后:
public static void main(String[] args) {
char[] ch = new char[]{'a','b','c'};
String str = new String(ch);
str.intern();
String str2 = "abc";
System.out.println(str == str2);
}
运行结果是true
str.intern()
的作用是把str
引用的对象手动入池(当常量池没有的时候)
public static void main(String[] args) {
String str = new String("hello");
}
我们ctrl+单击
右面的String
那么我们先来了解一下final
public static void main(String[] args) {
//String str = new String("hello");
int[] arr = {1,2,3};
arr = new int[]{1,2,3,4,5};
}
这样是不报错的,代表数组的指向可以改变
加了final
之后就报错了
public static void main(String[] args) {
//String str = new String("hello");
final int[] arr = {1,2,3};
arr = new int[]{1,2,3,4,5};
}
代表array
这个指向不能改变
但是我们讲了这么多,String
的不可变性跟这个没关.是因为数组是被private
修饰的,而官方也没设计出他的get set
方法,所以不能修改
网上有些人说:字符串不可变是因为其内部保存字符的数组被final
修饰了,因此不能改变。
这种说法是错误的,不是因为String
类自身,或者其内部value
被final
修饰而不能被修改。是因为被private
修饰了,根本拿不到字符串相关的函数来进行对字符串的操作,所以都是拷贝一个新数组来对新数组进行操作最后返回.
我们先来看一段代码
public class TestDemo {
public static void main(String[] args) {
String str = "hello";
str = str + "world";
System.out.println(str);//helloworld
}
}
//翻译如下
public static void main(String[] args) {
String str = "hello";
//str = str + "world";
//上面那行代码的翻译
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str);
stringBuilder.append("world");
str = stringBuilder.toString();
System.out.println(str);//helloworld
}
如果我们再加上个"!!!"呢
public class TestDemo {
public static void main(String[] args) {
String str = "hello";
str = str + "world";
str = str + "!!!";
System.out.println(str);//helloworld!!!
}
}
比如我们举个栗子:
public static void main(String[] args) {
String str = "hello";
for (int i = 0; i < 10; i++) {
str += i;
}
System.out.println(str);
}
这样就会产生许多许多临时对象,不推荐