string类
概述:
-
String类被final关键字修饰,意味着String类不能被继承,并且它的成员方法都默认为final方法;
-
String实例的值是通过字符数组实现字符串存储的。
-
字符串一旦创建就不能再修改,具有不可变性
-
String类实现了Serializable接口:表示字符串是支持序列化的
CharSequence接口
Comparable接口:表示string可以比较大小
-
字符串赋值:通过字面量的方式(区别于new)来给字符串赋值,此时字符串值声明在字符串常量池中
-
字符串常量池中不会存储相同内容的字符串。(即如果对于不同的字符串变量赋相同的值,实际上是栈区的不同地址指向字符串常量池的同一个存储内容)
-
不可变性的体现:当对字符串进行修改,链接,重新赋值时,实际上都是重新在字符串常量池中存储新的字符串,而对于原先的存储的内容没有任何改变。
字符串的初始化及内存结构
String的两种实例化方式
方式一:通过字面量定义
方式二:通过new+构造器
/*String的实例化方式
方式一:通过字面量定义
方式二:通过new+构造器
*/
import org.junit.Test;
public class StringTest2 {
@Test
public void test(){
//1,通过字面量定义:此时s1和s2的数据javaEE声明在字符串常量池中
String s1="javaEE";
String s2="javaEE";
//2,通过new+构造器定义:此时的s3和s4保存的值,是堆空间开辟的地址值
String s3 = new String("javaEE");
String s4 = new String("javaEE");
//比较运算符==,判断引用是否指向堆内存的同一块地址
System.out.println(s1 == s2); //true
System.out.println(s3 == s4); //false
//3,其他情况:实例对象中的字符串属性赋值
Person p1 = new Person(20,"xiaohu");
Person p2 = new Person(20,"xiaohu");
//s1 s2 s3 s4 p1 p2都是栈区创建的变量,保存了所创建的对象的地址。对象创建在堆区
System.out.println(p1.name == p2.name); //true
}
}
public class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
三种情况的内存结构如下:
字符串的拼接
public class StringPinjie {
public static void main(String[] args) {
String s1="hello";
String s2="world";
String s3="hello"+"world";
String s6="helloworld";
String s4=s1+"world";
String s5=s1+s2;
String s7=(s1+s2).intern();
System.out.println(s3==s6); //true
System.out.println(s3==s4); //false
System.out.println(s4==s5); //false
System.out.println(s3==s7); //true
final String s8="hello";//此时s8是常量
String s9=s8+"world";//常量之间的拼接,在常量池中
System.out.println(s3==s9);//true
}
}
结论:常量与常量的拼接发生在常量池
如果涉及变量的拼接,就发生在堆中
调用intern方法,返回的结果会在常量池中
字符串常用方法
String的转换
String与包装类的转换
见L4面向对象
String与char[ ]、Byte[]的转换
package L7;
import org.junit.Test;
import java.lang.reflect.Array;
import java.util.Arrays;
public class StringTrans {
@Test
public void test01(){
//String与char[]的转换
//String--->char[]:调用String的toCharArray()方法
//char[]--->String:调用String的构造器
String str1="1234abcd";
char[] c1=str1.toCharArray();
for (int i = 0; i < c1.length; i++) {
System.out.println(c1[i]);
}
char[] c2=new char[]{'h','e','l','l','o'};
String s1 = new String(c2);
System.out.println(s1);
//String与byte[]的转换
//编码:字符串-->字节(看得懂的-->看不懂的二进制数据)
//解码:字节-->字符串(看不懂的二进制数据-->看得懂的)
String str2="asd123葛强";
//编码 String--->byte[]:调用String的getBytes()方法
byte[] b1=str2.getBytes();
System.out.println(Arrays.toString(b1));
//解码 byte[]--->String:调用String的的构造器
String s2 = new String(b1);
System.out.println(s2);
}
}
String,StringBuffer,StringBuilder
String:不可变的字符序列,底层使用char[]存储
StringBuffer:可变的字符序列,线程安全,效率低,底层使用char[]存储
StringBuilder:可变的字符序列,线程不安全,效率高,底层使用char[]存储
三者概述:
- String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。
- 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
- 由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
StringBuffer
- 源码及特性
- 构造器和使用
- 常用方法
JDK8之前的日期时间API
1. java.lang.System类
System类提供的**public static long currentTimeMillis()**用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
此方法适于计算时间差。
2. java.util.Date类
表示特定的瞬间,精确到毫秒
- 构造器:
构造器一:Date():使创建一个对应当前时间的对象
构造器二:Date(long date):创建指定毫秒数的date对象
-
方法:
getTime( ): 等同于System.currentTimeMillis()
toString( ): 按一定格式返回当前的日期时间
package L7;
import org.junit.Test;
import java.util.Date;
public class DateTimeTest {
//1,System.currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
//通常用作一个时间戳,订单编号等等,避免重复。
@Test
public void test01(){
long time1=System.currentTimeMillis();
System.out.println(time1);
}
//2, java.util.Date类:表示特定的瞬间,精确到毫秒
/*构造器一:Date():使创建一个对应当前时间的对象
构造器二:Date(long date):创建指定毫秒数的date对象
方法: getTime():等同于System.currentTimeMillis()
toString():按一定格式返回当前的日期时间
*/
@Test
public void test02(){
Date date1 = new Date();
System.out.println(date1.toString()); //Tue Apr 20 17:14:24 CST 2021
Date date2 = new Date(1321);
System.out.println(date2.toString()); //Thu Jan 01 08:00:01 CST 1970
}
}
3.java.text.SimpleDateFormat类
- java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
- java.text.SimpleDateFormat类是一个非静态的,所以要使用它的方法需要先实例化一个对象
- 格式化:日期—>文本
- 解析:文本—>日期
package L7;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTimeTest02
{
@Test
public void TestSimpleDateFormat() throws ParseException {
//实例化SimpleDateFormat类
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化:日期--->字符串。并创建一个字符串变量接收返回值
Date D1 = new Date();
String F1 = sdf.format(D1);
System.out.println(F1);
//解析:字符串--->日期
String str="2021-4-23 下午13:28";
Date p1 = sdf.parse(str);
System.out.println(p1);
}
}
4. java.util.Calendar类
-
1,实例化Calendar类
-
2,常用方法:
get():获取相关时间信息
set():修改所调用对象的属性
add():修改所调用对象的属性,进行添加操作
getTime():日历类对象—>Date类对象
setTime():Date类对象—>日历类对象
//Calendar的使用
@Test
public void testCalendar(){
//1,实例化Calendar类
//方式一:调用它的子类GregorianCalendar的构造器
//方式二:使用其静态方法Calendar.getInstance()方法
Calendar c1 = Calendar.getInstance();
System.out.println(c1.getClass()); //说明c1是class java.util.GregorianCalendar的实例化
//2,常用方法
//get():获取相关时间信息
System.out.println(c1.get(Calendar.DAY_OF_MONTH)); //今天是本月的第几天
System.out.println(c1.get(Calendar.DAY_OF_YEAR)); //今天是本年的第几天
//set():修改所调用对象的属性
c1.set(Calendar.DAY_OF_MONTH,1);
System.out.println(c1.get(Calendar.DAY_OF_MONTH)); //今天是本月的第1天
c1.set(Calendar.DAY_OF_YEAR,360);
System.out.println(c1.get(Calendar.DAY_OF_YEAR)); //今天是本年的第360天
//add():修改所调用对象的属性,进行添加操作
c1.add(Calendar.DAY_OF_YEAR,5);
System.out.println(c1.get(Calendar.DAY_OF_YEAR)); //今天是本年的第365天
//getTime():日历类对象--->Date类对象
Date d1 = c1.getTime();
System.out.println(d1); // Fri Dec 31 14:31:31 CST 2021 (日历类对象对应的Date类对象)
//setTime():Date类对象--->日历类对象
Date d2 = new Date();
c1.setTime(d2); //将一个新的Date对象转化为日历类对象。所以这个日历类对象又对应了现在的时间
System.out.println(c1.get(Calendar.DAY_OF_MONTH)); //今天是本月的第27天
}
5,LocalDate、LocalTime、LocalDateTime类
**概述:**LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统(公历)的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
-
LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
-
LocalTime表示一个时间,而不是日期。
-
LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一
@Test
public void test01(){
//LocalDate、LocalTime、LocalDateTime类的方法
//1,now():静态方法。根据当前时间创建对象
LocalDate localDate1 = LocalDate.now();
LocalTime localtime1 = LocalTime.now();
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDate1); //2021-04-27
System.out.println(localtime1); //15:36:29.412
System.out.println(localDateTime1); //2021-04-27T15:36:29.412
//2,of():静态方法,根据指定日期/时间创建对象
LocalDateTime localDateTime2 = LocalDateTime.of(2022, 12, 3, 12, 22, 59);
System.out.println(localDateTime2);
}
对象排序
1,自然排序:java.lang.Comparable
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。主要用于自定义类的对象排序。
重写compareTo(Object obj)规则:
- 如果当前对象this大 于形参对象obj,则返回正整数。
- 如果当前对象this小于形参对象obj,则返回负整数
- 如果当前对象this等于形参对象obj,则返回零。
package L7;
import org.junit.Test;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Compare {
@Test
public void compareTest(){
Goods[] arr = new Goods[4];
arr[0]=new Goods("雷蛇",100);
arr[1]=new Goods("罗技",80);
arr[2]=new Goods("联想",50);
arr[3]=new Goods("小米",10);
Arrays.sort(arr);
//Goods是自定义类,必须要重写toString,不然对象调用toString的话,返回的是内存地址
System.out.println(Arrays.toString(arr));
}
}
package L7;
public class Goods implements Comparable{
private String name;
private double price;
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
@Override
//指明按照什么方式进行排序
public int compareTo(Object o) {
//instanceof测试左边的对象是否是右边类或者该类的子类创建的实例对象
if(o instanceof Goods){ //如果o是Goods类或者Goods类的子类所创建的对象
Goods g1=(Goods) o; //就把o转换为Goods类型
if(this.price>g1.price){
return 1;
}
else if (this.price<g1.price) {
return -1;
}else return 0;
}
throw new RuntimeException("传入的数据类型不一致!");
}
//必须要重写toString,不然对象调用toString的话,返回的是内存地址
@Override
public String toString(){
return name+price;
}
}
2,定制排序:java.util.Comparator
-
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码
-
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使Comparator 的对象来排序
重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
-
如果方法返回正整数,则表示o1大于o2;
-
如果返回0,表示相等;
-
返回负整数,表示o1小于o2。
//实现java.util.Comparator接口:定制排序
@Test
public void compareTest2(){
String[] arr=new String[]{"vv","ss","ff","ww","aa","uu","mm","ll"};
Arrays.sort(arr, new Comparator(){ //此处是用匿名内部类实现接口
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1=(String)o1; //object没有string的方法,所以向下强转为string
String s2=(String)o2;
return -s1.compareTo(s2); //加个负号,变成了从大到小排序
}
throw new RuntimeException("输入的数据类型不一致!");
}
});
System.out.println(Arrays.toString(arr)); //[ww, vv, uu, ss, mm, ll, ff, aa]
}
System类