1.String
1.1概述
String特性:
String底层是char 数组 private final char value[]
所以字符串很多特性就是数组的特性
- 字符串一旦创建不可更改
- 为了提升字符串的访问效率,Java中提出了字符串常量池,相当于是一个缓存区, 引用类型对象应该保存在堆内存,但是字符串不同,保存在静态区的字符串常量池中
- 在程序的执行过程中,如果程序要用到某个字符串,如"abc",虚拟机会先去常量池中搜索,有没有这个字符串 如果已经有了,就直接指向该字符串即可,如果没有就新建一个字符串对象,并指向它
4.String是一个final类,代表不可变的字符序列。
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
1.2 基本使用
1.String s1 = “abc”;
这里没有改变abc的值, 它只是在常量池新建了一个字符串, 让s1指向它
2.
创建两个对象,abc和Abc
String s2 = “abc”;
String s3 = “abc”;
String s4 = "Abc";
== 比较基本类型比较值,比较引用类型比较内存地址
//返回true, 说明他俩指向的地址是相同的,并没有新建字符串
3.new的方式,一new就会开辟堆空间 s5不再指向常量池,而是指向堆内存对象,堆内存中保存常量池的地址
String s5 = new String(“123”);
示例代码:
public class _01_String {
public static void main(String[] args) {
//第一部分
String s1 = "abc";
//这里没有改变abc的值, 它只是在常量池新建了一个字符串, 让s1指向它
s1= "a2";
System.out.println(s1);
//二
// 创建两个对象,abc和Abc
String s2 = "abc";
String s3 = "abc";
String s4 = "Abc";
//== 比较基本类型比较值,比较引用类型比较内存地址
//返回true, 说明他俩指向的地址是相同的,并没有新建字符串
System.out.println(s2 == s3);
// true 比较的是值
System.out.println(s2.equals(s3));
// 三
// new的方式,一new就会开辟堆空间 s5不再指向常量池,而是指向堆内存对象,堆内存中保存常量池的地址
String s5 = new String("123");
String s6 = new String("123");
// false
System.out.println(s5 == s6);
// 以上两句 : 创建三个对象(堆内存两个,常量池一个),占用5块空间(栈内存两个 s5 s6,堆内存两个,常量池一个)
// == 就是在比较 堆内存地址,而不是常量池中 123的地址了,因为new了两次,所以不一致
// equals比的是值的大小true所以一直
System.out.println(s5.equals(s6));
}
}
1.3不要频繁拼接
String一旦创建不可更改,所以使用的时候,要注意,不要频繁拼接字符串, 因为效率比较低,还浪费空间,并且垃圾回收也会有一定问题,
public class _02_String {
public static void main(String[] args) {
String[] strs = {“a”,“b”,“c”,“d”};
String tmp = “”;
for (String string : strs) {
tmp+=string;
}
//abcd 过程中会有创建: a ab abc abcd对象, 但是要abcd , 所以效率比较慢
System.out.println(tmp);
}
}
1.41.4 构造方法
代码示例
package _01_String;
public class _03_String {
//数组声明3种方式
// 静态声明,知道具体内容 大小时声明方法
// int[] a = {123};
// 静态声明 用于方法调用 参数传递
// int[] a = new int[] {1,2,3,};
//动态声明
//int[] a = new int[5];
//于方法调用 参数传递
//比如
//
// public static void main(String[] args) {
// int[] arr = new int[] {1,2,3,};
// m1(arr);
// }
//
//
// public static void m1(int[] arr){
//
// }
public static void main(String[] args) {
//1
String s1 = "abc";
//2
String s2 = new String("1wqe");
//3
byte[] aaa ={97, 98, 99};
String s3 = new String(aaa);
String s4 = new String(new byte[] { 97, 98, 99 });
//s3 s4 两种声明方式 其实本质一样
//abc 把数字转换 成char 所以就是abc
System.out.println(s3);
//abc 把数字转换 成char 所以就是abc
System.out.println(s4);
// 4 字节数组 , 截取一部分
// 从下标 1 开始(包含),取两个 , 用逗号隔开
// 输出bc
String s5 = new String(aaa, 1, 2);
System.out.println(s5);
// 5 字符数组
char[] chars = {'a','b','c','d'};
String s6 = new String(chars);
//abcd
System.out.println(s6);
// 6 截取一部分 从2 开始取2个
String s7 = new String(chars,2,2);
//cd , 数组下
System.out.println(s7);
// 7 无参 空字符串
String s8 = new String();
// 输出空
System.out.println(s8);
}
1.5常用方法
1.5.1方法的学习方法
String常用方法
1 方法是谁的(这里肯定是String)
2 什么方法,静态还是成员,知道是什么方法,就知道应该如何调用
3 方法名是什么,入参和出参是什么
4 方法功能是什么
1.5.2常用方法举例
int length():返回字符串的长度: return value.length
char charAt(int index): 返回某索引处的字符return value[index]
boolean isEmpty():判断是否是空字符串:return value.length == 0
String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
String trim():返回字符串的副本,忽略前导空白和尾部空白
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大
小写
String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex): 返回一个新的字符串, 它是此字符串的从
beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字 符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的
子字符串是否以指定前缀开始
boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列 时,返回 true
int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出 现处的索引,从指定的索引开始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后 一次出现处的索引,从指定的索引开始反向搜索
注:indexOf和lastIndexOf方法如果未找到都是返回-1
String replace(char oldChar, char newChar):返回一个新的字符串,它是
通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement): 使 用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement) : 使 用 给 定 的
replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement) : 使用给定的
replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此 字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中
代码示例:
package _01_String;
/**String常用方法
*
- 学习方法需要掌握的:(步骤)
- 1 方法是谁的
- 2 什么方法,静态还是成员,知道是什么方法,就知道应该如何调用
- 3 方法名是什么,入参和出参是什么
- 4 方法功能是什么
- @author prisident
*/
public class _04_String {
public static void main(String[] args) {
// 1 返回int类型 length() : 返回该字符串长度
String s1 = “asdt!”;
System.out.println(s1.length());// 6
// 2 char charAt(int index) : 获取字符串某个位置上的字符
char c1 = s1.charAt(2);
System.out.println(c1); //d
// 3 boolean endsWith(String suffix) : 判断字符串是否以指定字符串结尾
// boolean startsWith(String prefix) : 判断字符串是否以指定自己开始
System.out.println("qwer".endsWith("r"));// true
System.out.println("qwer".endsWith("1"));// false
System.out.println("a".endsWith("a "));// false 有空格
// 4 boolean equalsIgnoreCase(String anotherString) : 不区分大小写比较两个字符串是否相等
System.out.println("abc".equals("AbC")); // false
System.out.println("abc".equalsIgnoreCase("AbC")); // true
// 5 byte[] getBytes() : 把字符串转换为字节数组
byte[] byteArr = "abc".getBytes();
for (byte b : byteArr) {
//输出97 98 99
System.out.println(b);
}
System.out.println("---第6 个以后-------");
// 6 int indexOf(String str) :
//获取指定字符串的起始索引值,找不到返回-1,如果有多个 ,找到第一个就不找了
// 输出2
System.out.println(“abcdsde”.indexOf(“cd”));
// 7 int indexOf(String str,int fromIndex) : 从指定位置开始找(包含),找不到返回-1
// 输出5
System.out.println("abcdeabc".indexOf("a",1));
// 8 int lastIndexOf(String str) :
//获取最后一次出现的位置,找不到返回-1(倒着遍历,第一次出现,就是最后一次)
// int lastIndexOf(String str,int fromIndex) :
//输出0
System.out.println("abcdeabc".lastIndexOf("a",4));
//获取最后一次出现的位置,找不到返回-1,从指定位置反向搜索,第一次出现的位置
//输出5
System.out.println("abcdeabc".lastIndexOf("a"));
// 9 String replaceAll(String regex, String replacement) : 把一个字符串替换为指定字符串
// 一个类似的 replace : 这两个功能是一样的,只不过 replace 不支持正则表达式
System.out.println("123321".replace("1", "a")); // a2332a replace 不支持正则表达式
System.out.println("123321".replaceAll("1", "a")); // a2332a 支持正则表达式
// 正则表达式中 可以通过 \ 把 . 转义为无意义字符,但是在java中 \ 是转义符,
//所以 要写 \\ 对\进行转义才可以
System.out.println("1.2.3".replaceAll("\\.", "-")); //1-2-3
System.out.println("1.2.3".replace("\\.", "-")); // 1.2.3, 因为不支持正则表达式,所以 . 就是 .
// 10 String[] split(String regex) : 分割字符串,通过指定分隔符,来分割字符串,返回分割后的新字符串数组,支持正则表达式
String myTime = "2021-1-20";
String[] myTimes = myTime.split("-");
for (String string : myTimes) {
//2021
// 1
// 20
System.out.println(string);
}
System.out.println("____11以后_____");
// 11 String substring(int begin) : 获取该字符从某个下标开始到结尾的子字符串(包含)
//cde
System.out.println("abcde".substring(2));
// 12 String substring(int beginIndex,int endIndex) :
//获取该字符从某个下标开始(包含) 到某个下标结束的子字符串(不包含)
System.out.println("wqeqwfjn".substring(2, 6));//eqwf
// 13 char[] toCharArray() : 转换为字符数组
char[] c2 = "abc".toCharArray();
System.out.println(c2); //abc
for (char c : c2) {
System.out.println(c);
//a
// b
//c
}
System.out.println("-----------14---------");
// 14 String toUpperCase() : 转为大写
System.out.println("asd".toUpperCase());
//ASD
// 15 String toLowerCase() : 转为小写
System.out.println("ASD".toLowerCase()); //asd
// 16 String trim() : 删除字符串首位空格
System.out.println(" a b ");
System.out.println(" a b ".trim());
// 17 static String valueOf(Object obj) : 调用指定对象的toString方法,并且 避免了空指针异常
// (obj == null) ? "null" : obj.toString();
_04_String ss = null;
System.out.println(ss); // null
}
}
2.String ,StringBuilder和StringBuffer
2.1 概述
java.lang.StringBuffer
java.lang.StringBuilder
-
StringBuffer和StringBuilder是一个可变的字符串缓冲区
2 原理
预先在内存中申请一块空间,可以容纳字符序列(字符数组)
如果 预留空间不够,会进行自动扩容
底层都是char[] ,并且默认初始化容量是16个字符
3 String,StringBuffer,StringBuilder最大的区别1 String不可变字符序列,而StringBuilder和StringBuffer是可变字符序列
2 StringBuffer是线程安全,在多线程环境下,不会出现问题,所以效率低,一般常用于类中
3 StringBuilder是非线程安全,在多线程环境下可能出现问题,效率高,一般用于方法中
String 有final修饰 ,StringBuffer,StringBuilder没有
,StringBuffer,StringBuilder 两个用法一模一样
4 如何选择StringBuilder和StringBuffer
多线程环境下,是否有可能出现多个线程同时操作同一个数据 的可能(增,删,改)
2.2常用方法
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx StringBuffer reverse() :把当前字符序列逆转
public int indexOf(String str)
public String substring(int start,int end)
public int length()
public char charAt(int n )
public void setCharAt(int n ,char ch)
2.3 StringBuilder类
StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
StringBuffer():初始容量为16的字符串缓冲区
StringBuffer(int size):构造指定容量的字符串缓冲区
StringBuffer(String str):将内容初始化为指定字符串内容
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且 提供相关功能的方法也一样
面试题:对比String、StringBuffer、StringBuilder
String(JDK1.0):不可变字符序列
StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder 会改变其值。
2.3 使用
代码示例:public class _05_String {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
String[] strs = {“a”,“b”,“c”,“d”};
//字符串拼接使用append
for (String string : strs) {
//append(string+"1").append("1")效果一样
sb.append(string+“1”).append(“1”);
}
// 引用类型转成String 调用toString方法 两个操作方式一样
String str = sb.toString();
System.out.println(str);
StringBuilder sbr = new StringBuilder();
for (String string : strs) {
sbr.append("12");
}
System.out.println(sbr.toString());
//反转
System.out.println(sbr.reverse());
}
}
3 包装类
3.1概述
包装类 : 封装了基本类型的操作,更方便我们使用
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
boolean – java.lang.Boolean
使用包装类的好处
1 方便
2 为了理论上的完整(面向对象)
想要创建一个方法,该方法可以接收任何类型
Object ,因为Object是所有类的祖类,由于多态的原因,可以接收任何对象
基本类型并不是Object的子类,怎么接收?
包装类 可以把基本类型转换为对应的包装类类型,
包装类也是个类,也是Object的子类
3.2使用
public class Integer01 {
public static void main(String[] args) {
// 基本类型
byte b1 = 2;
// 引用类型 因为 包装类是一个类 所以可以null
Byte b2 = null;
// 把 b1 基本类型封装到b2引用类型中
b2 = new Byte(b1);
// 可以把b2 传入 接收Object的方法中,发生多态, 参数表使用父类声明, 子类传入
m1(b2);
//输出2
}
public static void m1(Object obj){
// 由于封装类重写了toString方法就可以直接打印 2 ,而不是内存地址
System.out.println(obj);
}
}
3.3 Integer
3.3.1基本使用
3.3.2常用方法
package Integer;
/**
- 常用方法
- @author prisident
*/
public class Integer03 {
public static void main(String[] args) {
// 1 int 转 Integer
Integer i1 = new Integer(22);
// 2 Integer 转 int
int i2 = i1.intValue();
// 3 parseInt(String s) 把字符串转换为int
//static int parseInt(String s)
// String转 int
int i3 = Integer.parseInt("123");
System.out.println(i3);
// 4Double 包装转double
double d1 = Double.parseDouble("12.3");
System.out.println(d1);
// 5
//把指定int值转换为二进制的字符串toBinaryString
//static String toBinaryString(int value) :
String s1 = Integer.toBinaryString(10);
System.out.println(s1);//1010
// 6 十六进制toHexString
System.out.println(Integer.toHexString(30));
// 7 八进制展示toOctalString
System.out.println(Integer.toOctalString(10));
// 8 int转 Integer Integer.valueOf
Integer i31 = Integer.valueOf(28);
// String转Integer
Integer i32 = Integer.valueOf("123");
// 9 Integer转String 用 toString
String s2 = i31.toString();
System.out.println(i31);
System.out.println(s2);
}
}
3.3.3类型转换
/**
- Integer , int , String 三者之间 相互转换
- @author prisident
*/
public class Integer04 {
public static void main(String[] args) {
// 一 int 转 Integer
Integer i1 = new Integer(222);
Integer i2 = Integer.valueOf(222);
// 二 Integer 转int
int i3 = i2.intValue();
// 三 String 转 Integer
Integer i4 = Integer.valueOf("1233");
Integer i5 = new Integer("11423");
// 四 Integer 转 String
String s1 = i5.toString();
// 五 String 转int
int i6 = Integer.parseInt("115611");
// 六 int 转 String
String s2 = 123+"";
}
}
3.3.4自动装箱和自动拆箱
java1.5之后的特性
自动装箱:把 基本数据类型 自动转换为 对应的包装类
自动拆箱:把 包装类 自动转换为 基本数据类型
自动装箱和自动拆箱是编译时 完成的
public class Integer05 {
public static void main(String[] args) {
//1.5之前 自动装箱的转换方式 把 基本数据类型 自动转换为 对应的包装类
Integer i1 = new Integer(123);
// 自动拆箱之前的转换方式 把 包装类 自动转换为 基本数据类型
int i2 = i1.intValue();
// 1.5 之后
// 自动装箱之后的转换方式 int转Integer
// 编译完后相当于 : Integer i3 = Integer.vlaueOf(222);
Integer i3 = 222;
// 自动拆箱之后的转换方式 拆箱 ,包装类转基本类型
int i4 = i1;
//或者
int i5 = new Integer(123);
//2 是基本类型,会先自动装箱转换为Integer类型
//然后再向上转型(多态) 转换为Object
m1(2);
}
public static void m1(Object obj){
System.out.println(obj);
}
}
3.3.5扩展之整型常量池
深入理解自动装箱和自动拆箱
1 都是编译时的概念,和运行时无关
2 装箱的时候,会在编译时 自动把赋值 操作 变成 Integer.valueOf(15616)
String , Integer,Double 等 八种包装类 和String 都覆写了toString(),equals() , hashCode() 方法
valueOf : 把基本类型转换为Integer类型
里面初始化了一个整型常量池,值的范围是在 -128~127之间
其实 就是一个Integer[] 数组 有 256个对象,对象中的int值 分别为 -128,-127…126,127 下标 是 0~ 255
在 private static class IntegerCache 类中 是 Integer中的一个静态内部类
类中有三个变量 :
static final int low = -128;
static final int high;
static final Integer cache[];
并且在 static 代码块中 对这个数组进行了初始化操作
如果 值 在 -128~127之间 就直接去这个缓存数组中找对应的对象即可,不用再重新创建Integer对象
public class Integer06 {
public static void main(String[] args) {
// 自动装箱 Integer i1 = Integer.valueOf(12);
Integer i1 = 12;
Integer i2 = 12;
//true, 说明在常量池中地址一样
System.out.println(i1 == i2);
//等于 Integer i3 = Integer.valueOf(128) 不符合常量池值的大小,所以是要new 地址为堆空间,不相等
Integer i3 = 128;
Integer i4 = 128;
//false
System.out.println(i3 == i4);
// 换种方式来实现验证是否该理论正确, 跟上边一样没区别
Integer i5 = Integer.valueOf(12);
Integer i6 = Integer.valueOf(12);
System.out.println(i5 == i6);
Integer i7 = Integer.valueOf(128);
Integer i8 = Integer.valueOf(128);
System.out.println(i7 == i8);
// new 开辟堆空间,new了两次,对象内存地址不同,
// == 比较内存地址,肯是false, 使用equals 比较值true,因为都是1
Integer i9 = new Integer(1);
Integer i10 = new Integer(1);
System.out.println(i9 == i10);
System.out.println(i9.equals(i10));
}
}