1.字符串相关的类:String
1.1String的特性
- String类:代表字符串。Java程序中的所有字符串字面值(如“abc”)都作为此类的实例实现。
- String是一个final类,代表不可变的字符序列。
- 字符串是常量,用双引号引用起来表示。他们的值在创建之后不能更改。
- String对象的字符内容是存储在一个字符数组value[]中的。
1.2理解String的不可变性
package com.liu.javaDemo; import org.testng.annotations.Test; /** * String 的使用 * */ public class StringTest { /** * * String :字符串,使用一对”“引起来使用 * 1.String 声明为final的,不可被继承的。 * 2.String 实现了Serializable接口:表示字符串是支持序列化的。 * 实现了Comparable接口:表示String可以比较大小。 * 3.String 内部定义了final char[] value 用于存储字符串数据。 * 4.String 代表不可变的字符序列。 简称:不可变性。 * 体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不饿能使用原有的value进行赋值。 * 2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用现有的value进行赋值。 * 3.当调用String的replace()方法修改指定字符或字符串时也需要重新指定内区域赋值、 * 5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。 * 6.字符串常量池中是不会存储相同内容的字符串的。 */ @Test public void test1(){ String s1 = "abc"; //字面量的方式定义 String s2 = "abc"; s1 = "hello"; System.out.println(s1==s2);//比较s1和s2的地址值。 System.out.println(s1); System.out.println(s2); System.out.println("***************"); String s3 = "abc"; s3+="def"; System.out.println(s3); System.out.println("***************"); String s4 = "abc"; String s5 = s4.replace('a', 'b'); System.out.println(s4); System.out.println(s5); } }
1.3 String对象的创建
String 实例化的方式:
方式一:通过字面量定义的方式。
方式二:通过new + 构造器的方式。
String str = "hello"; //字面量方式在常量池。
//本质上this.value = new char[0];
String s1 = new String(); //new 的都在堆
//this.value = original.value;
String s2 = new String(String original);
//this.value = Arrays.copyOf(value,value.length);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count);
字面量和new +构造器的区别:
三种JVM:
- Sun公司的HotSpot(默认)
- BEA公司的JRockit
- IBM公司的J9 VM
细分堆:
Heap堆:
一个JVM实例只存在一个堆内存,堆内存的大小是可以刁姐的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分:
- Young Generation Space 新生区 Young
- Tenure generation space 养老区 Old
- Permanent Space 永久存储区 Perm
总结:
package com.liu.javaDemo;
import org.junit.jupiter.api.Test;
/**
* String 的使用
*
*/
public class StringTest {
/**
* 结论:
* 1。常量与常量的拼接在常量池。且常量池中不会存在系统内容的常量。
* 2.只要其中有一个是变量,结果就在堆中。相当于new
* 3.如果拼接的结果调用intern()方法,返回值就在常量池中。
*/
@Test
public void test4(){
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);
final String s4 = "javaEE"; //加final就是常量。
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);
}
@Test
public void test3(){
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE"+"hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s5.intern(); //返回值得到的s8使用的是常量池中已存在的”javaEEhadoop“;
System.out.println(s3 == s8); //true
}
/**
* String 实例化的方式:
* 方式一:通过字面量定义的方式
* 方式二:通过new + 构造器的方式
*
* 面试题:String s = new String("abc); 方式创建对象,在内存中创建了几个对象?
* 两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:”abc“
*
*/
@Test
public void test2(){
//通过字面量定义的方式:此时的s1和s2的数据Java EE声明在方法区中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通过new + 构造器的方式: 此时的s3和s4 保存的地址值,是数据在堆空间中开辟空间以后
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1==s2); //true
System.out.println(s1==s3); //false
System.out.println(s1==s4); //false
System.out.println(s3==s4); //false
System.out.println("*****************");
Person p1 = new Person("tom", 19);
Person p2 = new Person("tom", 19);
System.out.println(p1.name.equals(p2.name)); //true
System.out.println(p1.name == p2.name); //true,因为name是字面量定义的,在常量池中,他们的name属性都指向了tom;
p1.name = "jerry";
System.out.println(p2.name); //jerry
}
/**
*
* String :字符串,使用一对”“引起来使用
* 1.String 声明为final的,不可被继承的。
* 2.String 实现了Serializable接口:表示字符串是支持序列化的。
* 实现了Comparable接口:表示String可以比较大小。
* 3.String 内部定义了final char[] value 用于存储字符串数据。
* 4.String 代表不可变的字符序列。 简称:不可变性。
* 体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不饿能使用原有的value进行赋值。
* 2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用现有的value进行赋值。
* 3.当调用String的replace()方法修改指定字符或字符串时也需要重新指定内区域赋值、
* 5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
* 6.字符串常量池中是不会存储相同内容的字符串的。
*/
@Test
public void test1(){
String s1 = "abc"; //字面量的方式定义
String s2 = "abc";
s1 = "hello";
System.out.println(s1==s2);//比较s1和s2的地址值。
System.out.println(s1);
System.out.println(s2);
System.out.println("***************");
String s3 = "abc";
s3+="def";
System.out.println(s3);
System.out.println("***************");
String s4 = "abc";
String s5 = s4.replace('a', 'b');
System.out.println(s4);
System.out.println(s5);
}
}
class Person{
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
String常用方法1:
- 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(不包含)的一个子字符串。
package com.liu.javaDemo;
import org.testng.annotations.Test;
import java.util.Locale;
/**
*
*/
public class StringMethodTest {
/**
* 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(不包含)的一个子字符串。
*/
public void test2(){
String s1 = "helloworld";
String s2 = "HelloWorld";
System.out.println(s1.equals(s2)); //false 区别大小写
System.out.println(s1.equalsIgnoreCase(s2)); //true 忽略大小写
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);
String s5 = "abc";
String s6 = new String("abe");
System.out.println(s5.compareTo(s6)); //-2
//涉及到字符串排序
String s7 = "唯独刺客";
String s8 = s7.substring(2);
System.out.println(s7);
System.out.println(s8);
String s9 = s7.substring(2, 4); //[begin,end)
System.out.println(s9);
}
@Test
public void test1(){
String s1 = "HelloWorld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.isEmpty());
String s2 = s1.toLowerCase();
System.out.println(s1);//s1不可变,仍然为原来的字符串
System.out.println(s2);//改变小写以后的字符串
String s3 = " h ell o wor l d ";
String s4 = s3.trim();
System.out.println("++++++++"+s3+"+++++++");
System.out.println("++++++++"+s4+"+++++++");//取出首尾的空格
}
}
String常用方法2:
- 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):返回指定字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
注:index和lastIndexOf方法如果未找到都是返回-1
/**
* 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):返回指定字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
*/
@Test
public void test3(){
String str1 = "helloworld";
boolean b1 = str1.endsWith("ld");
System.out.println(b1);
boolean b2 = str1.startsWith("He");
System.out.println(b2);
boolean b3 = str1.startsWith("ll", 2);
System.out.println(b3);
String str2 = "wor";
System.out.println(str1.contains(str2));
System.out.println(str1.indexOf("lo"));
System.out.println(str1.indexOf("lo", 5));
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or"));
System.out.println(str3.lastIndexOf("or", 6));
//什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?
//情况一:存在唯一的一个str.情况二:不存在str.
}
String常用方法3:
- 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个,如果超过了,剩下的全部都放到最后一个元素中。
/**
* 替换
* 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个,如果超过了,剩下的全部都放到最后一个元素中。
*
*/
@Test
public void test4(){
String str1 = "beijinghuanyinni";
String str2 = str1.replace('i', 'I');
System.out.println(str1);
System.out.println(str2);
String str3 = str1.replace("in", "IN");
System.out.println(str3);
System.out.println("**************");
String str = "12hello34world56java567mysql324";
//把字符串中的数字替换成, 如果结果中开头和结尾有,的话去掉
String string = str.replaceAll("\\d+",",").replaceAll("^,|,$","");
System.out.println(string);
str = "12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str.matches("\\d+");
String tel = "0571-45344289";
//判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result);
System.out.println("**************");
str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
System.out.println();
str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]);
}
}
String与基本数据类型转换
复习
package com.liu.javaDemo; import org.junit.jupiter.api.Test; /** * 涉及到String类与其他类之间的转换 * */ public class StringTest1 { /** * String与char[] 之间的转换 * String --> char[]:调用String的toCharArray() * char[] --> String:调用String的构造器。 * */ @Test public void test2(){ String str1 = "abc123"; //题目:a21cb3 char[] charArray = str1.toCharArray(); for (int i = 0; i < charArray.length; i++) { System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l','l','o'}; String str2 = new String(arr); System.out.println(str2); } /** * 复习: * String 与基本数据类型、包装类之间的转换。 * String --> 基本数据类型、包装类:调用包装类的静态方法:parseXXX(str) * 基本数据类型、包装类 -->String:调用String重载的valueOf(XXX) * * */ @Test public void test1(){ String str1 = "123"; //int num = (int)str1; //错误的,子父类关系才可以强转。 int num = Integer.parseInt(str1); String str2 = String.valueOf(num); String str3 = num + ""; System.out.println(str1 == str3); //false } }
String与字节数组转换
- 字节数组->字符串
- String(byte[]):通过使用平台的默认字符集解码指定的byte数组,构造一个新的String。
- String(byte[], int offset, int length):用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。
- 字符串->字节数组
- public byte[] getBytes():使用平台的默认字符集将此String编码为byte序列,并将结果存储到一个新的byte数组中。
- public byte[] getBytes(String charsetName):使用指定的字符集将此String编码到byte序列,并将结果存储到新的byte数组。
package com.liu.javaDemo; import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; import java.util.Arrays; /** * 涉及到String类与其他类之间的转换 * */ public class StringTest1 { /** * String 与byte[]之间的转换 *编码:String --> byte[]:调用String 的getBytes() *解码:byte[] --> String:调用String的构造器。 * * 编码:字符串 -> 字节(看得懂-->看不懂的二进制数据) * 解码:编码的逆过程,字节 -> 字符串(看不懂的二进制数据--->看得懂的) * * 说明:解码时,要求解码使用的字符集必须和编码时使用的字符集一致,否则会出现乱码。 * */ @Test public void test3() throws UnsupportedEncodingException { String str1 = "abc123中国"; byte[] bytes = str1.getBytes();//使用默认的字符集,进行转换,编码 System.out.println(Arrays.toString(bytes)); byte[] gbks = str1.getBytes("gbk"); //使用gbk字符集进行编码 System.out.println(Arrays.toString(gbks)); System.out.println("*****************************"); String str2 = new String(bytes); System.out.println(str2); String str3 = new String(gbks); System.out.println(str3);//乱码 String str4 = new String(gbks, "gbk"); System.out.println(str4); } /** * String与char[] 之间的转换 * String --> char[]:调用String的toCharArray() * char[] --> String:调用String的构造器。 * */ @Test public void test2(){ String str1 = "abc123"; //题目:a21cb3 char[] charArray = str1.toCharArray(); for (int i = 0; i < charArray.length; i++) { System.out.println(charArray[i]); } char[] arr = new char[]{'h','e','l','l','o'}; String str2 = new String(arr); System.out.println(str2); } /** * 复习: * String 与基本数据类型、包装类之间的转换。 * String --> 基本数据类型、包装类:调用包装类的静态方法:parseXXX(str) * 基本数据类型、包装类 -->String:调用String重载的valueOf(XXX) * * */ @Test public void test1(){ String str1 = "123"; //int num = (int)str1; //错误的,子父类关系才可以强转。 int num = Integer.parseInt(str1); String str2 = String.valueOf(num); String str3 = num + ""; System.out.println(str1 == str3); //false } }
练习5:常见算法题目
1.模拟一个trim方法,去除字符串两端的空格。
2.将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为“abfedcg”
3.获取一个字符串在另一个字符串中出现的次数。
比如:获取“ab”在“abkkcadkabkebfkadkskab”中出现的次数。
4.获取两个字符串中最大相同子串。比如:
str1 = 'abcwerthelloyuiidef';str2 = 'cvhellobnm'
提示:将短的那个串进行长度一次递减的子串与建厂的串比较。
5.堆字符串中字符进行自然顺序排序。
提示:
1)字符串变成字符数组。
2)对数组排序,选择,冒泡,Arrays.sort();
3)将排序后的数组变成字符串。
1.2 StringBuffer、StringBuilder
String、StringBuffer、StringBuilder三者的异同? * String:不可变的字符序列。底层结构使用char[]进行存储。 * StringBuffer:可变的字符序列。线程安全,效率低;底层结构使用char[]进行存储。 * StringBuilder:可变的字符序列。jdk5.0新增,线程不安全,效率高;底层结构使用char[]进行存储。
* //问题1: * sout(sb2.length()); //3 * 因为length()方法底层是输出的是count,也就是你append了几个字符。 * * //问题2:扩容问题 * 如果要添加的数据底层数组放不下了,那就需要扩容底层的数组。 * 默认情况下,扩容为原来容量的2倍+2,提示将原有的数组中的元素复制到新的数组中。 * 指导意义:开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity) * 直接带参数,避免后期扩容影响效率。
1.2.1StringBuffer类的常用方法
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():把当前字符串序列逆转。
- 当append和insert使,如果原来value数组长度不够,可扩容。
- 如上这些方法支持方法链操作。
- 方法链的原理:
@Override
public StringBuilder append(String str){
super.append(str);
return this;
}
此外,还定义了如下的方法:
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)
由于append方法重载了很多类型:所以可以实现很多类型的拼接。
package com.liu.javaDemo;
import org.junit.jupiter.api.Test;
/**
* 关于StringBuffer 和 StringBuilder的使用
*/
public class StringBufferBuilderTest {
/**
* StringBuffer的常用方法: *
* 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):返回str在当前字符串首次出现的位置。
* public String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串。
* public int length()
* public char charAt(int n)
* public void setCharAt(int n, char ch)
*
* 总结:
* 增:append(xxx)
* 删:delete(int start,int end)
* 改:setCharAt(int n,char ch) / replace(int start,int end, String str)
* 查:charAt(int n)
* 插:insert(int offset, xxx)
* 长度:length()
* *遍历:for() + charAt() /toString() 看内容
*
*/
@Test
public void test2(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(1);
s1.append('1');
System.out.println(s1); //abc11
// s1.delete(2,4);//ab1
// s1.replace(2,4,"hello");//abhello1
// s1.insert(2,"false");//abfalsec11
// s1.reverse();
String s2 = s1.substring(1, 3);
System.out.println(s1);
System.out.println(s1.length());
System.out.println(s2);
}
/**
* String、StringBuffer、StringBuilder三者的异同?
* String:不可变的字符序列。底层结构使用char[]进行存储。
* StringBuffer:可变的字符序列。线程安全,效率低;底层结构使用char[]进行存储。
* StringBuilder:可变的字符序列。jdk5.0新增,线程不安全,效率高;底层结构使用char[]进行存储。
*
* 源码分析:
* String str = new String();//new char[0];
* String str1 = new String("abc");//new char[]{'a','b','c'};
*
* StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的字符数组。
* sb1.append('a'); //value[0] = 'a';
* sb1.append('b');//value[1] = 'b';
*
* StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length()+16];
*
* //问题1:
* sout(sb2.length()); //3
* 因为length()方法底层是输出的是count,也就是你append了几个字符。
*
* //问题2:扩容问题
* 如果要添加的数据底层数组放不下了,那就需要扩容底层的数组。
* 默认情况下,扩容为原来容量的2倍+2,提示将原有的数组中的元素复制到新的数组中。
* 指导意义:开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
* 直接带参数,避免后期扩容影响效率。
*
*
*/
@Test
public void test1(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0,'m');
System.out.println(sb1);
}
}
对比String、StringBuffer、StringBuilder三者的效率?
从高到低排列:StringBuilder > StringBuffer >String
2.JDK 8之前的日期时间API
2.1 java.lang.System类
System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。(此方法适于计算时间差)
- 计算世界时间的主要标准有:
- UTC(Coordinated Universal Time)
- GMT(Greenwich Mean Time)
- CST(Central Standard Time)
/**
* JDK 8 之前日期和时间的API 测试
*/
public class DateTimeTest {
//1. System类的currentTimeMillis()
@Test
public void test1(){
long time = System.currentTimeMillis();
//用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
//成为时间戳
System.out.println(time);
}
}
2.2 java.util.Date类
表示特定的瞬间,精确到毫秒
- 构造器
- Date():使用无参构造器创建的对象可以获取本地当前时间。
- Date(long date):
- 常用方法:
- getTime():返回自1970年1月1日00:00:00 GMT 以来此Date对象表示的毫秒数。
- toString():把此Date对象转换成以下形式的String:dow mon dd hh:mm:ss zzz yyyy其中:dow是一周中的某一天(Sun,Mon,Tue,Wed,Thu,Fri,Sat),zzz是时间标准。
- 其他很多方法都过时了。
/**
* java.util.Date类
* |----java.sql.Date类
* 1.两个构造器的使用
* >构造器一:Date():创建一个对应当前时间的Date()对象。
* >构造器二:创建指定毫秒数的Date对象
* 2.两个方法的使用
* >toString():显示当前的年,月,日,时,分,秒
* >getTime():获取当前Date对象对应的毫秒数。(时间戳)
*
* 3.java.sql.Date类 对应数据库中的日期类型的变量。
* >如何实例化?
* >如何将java.util.Date对象 --->java.sql.Date对象
*/
@Test
public void test2(){
//构造器一:Date():创建一个对应当前时间的Date()对象。
Date date1 = new Date();
System.out.println(date1);//Tue May 24 00:00:44 CST 2022
System.out.println(date1.getTime());//1653321644081
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(1653321644081L);
System.out.println(date2.toString());
//创建java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(1653321644081L);
System.out.println(date3);
//如何将java.util.Date对象 --->java.sql.Date对象
//情况一:
// Date date4 = new java.sql.Date(1653321644081L);
// java.sql.Date date5 = (java.sql.Date) date4;
//情况二:
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
}
复习:
1.画出如下几行代码的内容结构?
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
s1+="world";
2.如何理解String的不可变性?
无论进行任何操作都需要返回一个新值。当多个变量指向同一个字符串时,当一个改了之后为了避免其他变量的所指向的常量也跟着改变,就让改的变量再新造一个常量放到常量池中。
3.String类是否可以被继承?为什么?
不可以,因为底层用了final关键字,意味着不能重新赋值。
String s = new String("hello");在内存中创建了几个对象?请说明。
2个。一个是通过字面量的方式在常量池中,一个是在堆当中存放了在常量池中的地址。
4.String、StringBuffer、StringBuilder三者的对比。
5.String的常用方法有哪些?(至少七个)
length()/charAt()/equals/compareTo()/startsWith()/endsWith()/contains()/indexOf()
/lastIndexOf()/getBytes() / toCharArray() / valueOf /…
2.3java.text.SimpleDateFormat类
3.JDK 8中新日期的时间API
4.Java比较器
- 在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。
- Java实现对象排序的方式有两种:
- 自然排序:java.lang.Comparable
- 定制排序:java.util.Comparator
package com.liu.javaDemo;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
/**
* 一、说明:Java中的对象,正常情况下,只能进行比较:== 或 !=。不能使用 > 或 < 的。
* 但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
* 如何实现?使用两个接口中的任何一个:Comparable 和 Comparator
*
* 二、Comparable接口的使用
* 1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
* 2.像String、包装类重写compareTo()方法以后,进行了从小到大的排列。
* 3.重写compareTo(obj)的规则:
* 如果当前对象this大于形参对象obj,则返回正整数,
* 如果当前对象this小于形参对象obj,则返回负整数。
* 如果当前对象this等于形参对象obj,则返回0。
*
*/
public class CompareTest {
@Test
public void test1(){
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD","KK"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
package com.liu.javaDemo;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Comparator;
/**
* 一、说明:Java中的对象,正常情况下,只能进行比较:== 或 !=。不能使用 > 或 < 的。
* 但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。
* 如何实现?使用两个接口中的任何一个:Comparable 和 Comparator
*
* 二、Comparable接口的使用:自然排序
* 1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
* 2.像String、包装类重写compareTo()方法以后,进行了从小到大的排列。
* 3.重写compareTo(obj)的规则:
* 如果当前对象this大于形参对象obj,则返回正整数,
* 如果当前对象this小于形参对象obj,则返回负整数。
* 如果当前对象this等于形参对象obj,则返回0。
* 4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo()。
* 在compareTo(obj)方法中知名如何排序。
*
* Comparable接口与Comparator接口的使用相比:
* Comparable接口的方式一旦一定,保证Compara接口实现类的对象在任何位置都可以比较大小。
* Comparator接口属于临时性的比较。
*
*/
public class CompareTest {
@Test
public void test1(){
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD","KK"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
@Test
public void test2(){
Goods[] arr = new Goods[4];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",23);
arr[2] = new Goods("XiaomiMouse",35);
arr[3] = new Goods("HuaweiMouse",12);
arr[4] = new Goods("mircrosoftMouse",12);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* Comparator接口的使用:定制排序
* 1.背景:
* 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
* 或者实现了java.lang.Comparable接口的排序规则不适合当前的操作。
* 那么可以考虑使用Comparator 的对象来排序。
* 2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小;
* 如果方法返回正整数,则表示o1大于o2;
* 如果方法返回负整数,则表示o1小于o2;
* 如果返回0,表示相等;
*
*
*/
@Test
public void test3(){
String[] arr = new String[]{"AA","CC","MM","GG","JJ","DD","KK"};
Arrays.sort(arr,new Comparator(){
//按照字符串从大到小的顺序排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
}
@Test
public void test4(){
Goods[] arr = new Goods[4];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",23);
arr[2] = new Goods("XiaomiMouse",35);
arr[3] = new Goods("HuaweiMouse",12);
arr[4] = new Goods("mircrosoftMouse",12);
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Goods && o2 instanceof Goods){
Goods g1 = (Goods) o1;
Goods g2 = (Goods) o2;
if(g1.getName().equals(g2.getName())){
return -Double.compare(g1.getPrice(),g2.getPrice());
}else{
return g1.getName().compareTo(g2.getName());
}
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
}
}
5.System类
6.Math类
BigInteger类的常用方法: