常用类
String
String的定义与特性
String的定义
string内部使用char型数组存储String的数据,属于顺序表
private final char[] value
由于时final定义的,所以String型变量在初次定义后就不能更改,即String具有不可变性。
String实现了Serizeable接口、故其是可序列化的,即可以作为对象进行传输(IO或网络传输)
其也实现了Compareable接口,即可以比较大小
注:String作为对象,可以不new对象直接进行赋值。
String型变量的内存存储结构:
若新建两个String型变量其值相同,则会使用方法区中字符串常量池中的同一个地址上的数据,若改变其值不会在原有的基础上改变,而是会在字符串常量池中新增一个数据,并使其指向新数据。
无论对String内容进行任何修改,都会重新创建,不会在原有内存上修改。
通过字面量定义的String型变量,其都存放在字符串常量池中。String str = "a"
String str = new String("abc")
创建了两个对象,一个是new的str在堆空间中、另一个是在字符串常量池中的char[]型数组,
字符串的拼接
拼接中只有右边有String型变量的变量名,该拼接完的String就会存在堆空间中。
String s1 = "Java" + "hadoop"; //s1直接指向字符串常量池中的的地址
Strhins3 = "Java";
String s2 = s3 + "hadoop"; //s2指向堆空间中的地址,堆空间中存有具体的char[]型数组。
sout("s1 == s2"); //false
String s4 = s2.intern();
sout("s4 == s1"); //true
注:.intern()方法会将无论在哪里的字符串,返回为一个在堆空间中的字符串。
注:final 修饰的字符串属于常量,其与类似"JavaEE"的字面量进行拼接时仍然存储在常量池中
String的常用方法
常用方法一
- .length()输出String的长度,即底层char[]的长度。
@Test
public void test1(){
String s1 = "Hello World!";
System.out.println(s1.length());
}
}
- .charAt(int),返回指定位置的索引,从0开始
System.out.println(s1.charAt(0)); //输出索引位置0号位置的元素
- .isEmpty()判断字符串是否为空,根据value.length()是否为0
System.out.println(s1.isEmpty());
//false
- .toLowerCase();将字符串中所有字符变为小写,由另一个字符接收
.toUpperCase();全部转换为大写由另一个字符接收 - .trim();祛除字符串首尾两端的所有空格,由另一个字符接受,本身不改变
String s1 = " He l lo Wo rl d! ";
String s2 = s1.trim();
System.out.println("---------" + s1 + "----------")
System.out.println("---------" + s2 + "----------");
/*
--------- He l lo Wo rl d! ----------
---------He l lo Wo rl d!----------
*/
- .equals(),比较是否相等
.equalsIgnoreCase();在忽略大小写的情况下比较是否相等 - .cancat(String);拼接,一般使用"+"
- a.compareTo(String b);ASCII码比较,从左往右第一个不相同的字符,a - b;
- .substring(int BeginIndex, int EndIndex);切片、从BeginIndex索引到EndIndex索引钱一个位置的切片,也可以指传入BeginIndex代表切片从索引BeginIndex直接到字符串末尾
常用方法二
- .endWith(String); 是否以指定字符串结尾
- .startWith(String a, int toffSet); 若只传入一个变量,则判断是否以字符串a为开始,若传入两个变量,则判断从索引位置toffSet开始,是否以a为开始。
- .contains(String a);判断a是否在字符串中(模式匹配)
- .IndexOf(String a, int fromIndex); 判断a是否在字符串中,且返回a在字符串中起始位置的索引,若不在,则返回-1,若添加了int型的形参,则从fromIndex索引位置开始找。
- .lastIndexOf(String a, int fromIndex); 从后往前找,并返回其顺序的索引位置。
常用方法三
- .replace(String OldChar, String NewChar);将原字符串中的OldChar一样的字符串全部更换成NexChar内容的字符串。
正则表达式。。。
String与Char[]、byte[]之间的转换
String与char[]的转换
String -> char[]调用.toCharArray()方法
String str1 = "123";
char[] c = str1.toCharArray();
char[] -> String 调用String的构造器
char[] arr = new char[]{'Q','W','E','R'};
String str2 = new String(arr);
String与Byte[]的转换
在字节流中会经常使用
String -> Byte[] 调用String的getBytes()方法,会相应的返回ASCII码
编码:从字符串信息编写成字节码。
解码:从字节码转换成可以看懂的字符串信息。
@Test
public void Test2() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes(); //默认使用UTF-8编码集编写汉字
System.out.println(Arrays.toString(bytes));
/*
* [97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67]
* */
byte[] gbks = str1.getBytes("GBK"); //给getBytes()方法传入具体的字符集,使其按照规定字符集进行编码
System.out.println(Arrays.toString(gbks));
/*
* [97, 98, 99, 49, 50, 51, -42, -48, -71, -6]
* */
}
byte[] -> String 调用String的构造器。
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();
String s = new String(bytes);
System.out.println(s);
/*
abc123中国
*/
StringBuffer与StringBuilder
String:不可变的字符序列
StringBuffer:可变的字符序列,线程安全、效率偏低
StringBuilder:可变的字符序列,线程不安全,效率较高
三者的底层存储都是char[]型数组
直接在原字符串的基础上可以进行修改,StringBuffer的可变性。
@Test
public void test(){
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0, 'm');
System.out.println(sb1);
/*
mbc
*/
}
StringBuffer底层:
- 在创建时,会默认创建字符串多16个位置的char[]。例如创建
StringBuffer str = new StringBuffer("abc");
则会创建一个3+16位的char型数组。 - StringBuffer可以通过.append()方法一点点往字符串中压入字符,且压入在原字符串中。(可变性)
/*可变性的体现*/
StringBuffer sb1 = new StringBuffer("abc");
sb1.setCharAt(0, 'm');
System.out.println(sb1);
/*
mbc
*/
- 若底层char型数组满,则会创建一个原有数组容量两倍+2的容量的数组,并将原数组复制给新数组,若扩容后还不够,则直接以需要的容量作为大小新建数组。
注:若String频繁修改则优先使用StringBuffer或StringBuilder方法。
注:建议使用new StringBuffer(int);
的构造器直接指定底层char型数组的容量。
StringBuffer常用方法
-
sb.append();向字符串中添加字符或其他数据类型的元素,有很多重载的方法,可以添加很多类型的数据。
StringBuffer sb1 = new StringBuffer("abc"); sb1.append(1); //可以添加int sb1.append("1"); //也可以添加String sb1.sout; /* abc11 */
-
sb.delete(int start, int end);左闭右开的删除对应位置的元素,例如删除(2, 4)位置的元素会对应删除2,3位置上的元素,4处属于开区间,不被删除。
StringBuffer sb1 = new StringBuffer("abc"); sb1.setCharAt(0, 'm'); System.out.println(sb1); sb1.append(1); sb1.append("1"); sb1.delete(2, 4); System.out.println(sb1); /* mb1 */
-
sb.replace(int start, int end, String str);左闭右开的选择start到end的元素,并替换为str字符串
sb1.replace(2, 4, "hello"); System.out.println(sb1); /* mbhello1 */
-
sb.insert(int offset, Xxx);在索引为offset位置上插入Xxx,其类型被重载。
sb1.insert(2, 888); System.out.println(sb1); /* mb888hello1 */
日期与时间
System中提供的API
System.currentTimeMillis()返回一个long型数据,表示时间戳(1970.1.0,00:00:00到现在的毫秒数)
long l = System.currentTimeMillis();
System.out.println(l);
/*
1661651529984
*/
Java中Date类的使用
Java.util.Date
构造器一:
Date date = new Date(); //创建对应当前时间的Date对象
方法:
date.toString(); //返回具体信息
date.getTime(); //返回时间戳
Date date = new Date(); //创建对应当前时间的Date对象
System.out.println(date.toString()); //返回具体信息
System.out.println(date.getTime()); //返回时间戳
/*
Sun Aug 28 10:01:03 CST 2022
1661652063244
*/
构造器二:
Date date1 = new Date(1661652063244L); //根据时间戳创建任意时间点的Date对象。
Date date1 = new Date(1661652063244L);
System.out.println(date1.toString());
/*
Sun Aug 28 10:01:03 CST 2022
*/
Java.sql.Date
sql.Date专门为数据库中的date提供的对象,其可以保存数据库中的Date对象。其可以通过时间戳来赋值,利用util.Date中的getTime()获取时间戳再赋值给sql.Date的构造器来达成util.Date与sql.Date之间的转换。
java.sql.Date date2 = new java.sql.Date(date.getTime());
SimpleDateFormat
创建SimpleDateFormat对象并将其转换为字符串(日期—>字符串)。调用.format()方法。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
Date date = new Date();
//转换为字符串。
String format = simpleDateFormat.format(date);
System.out.println(format);
/*
22-8-28 上午10:39
*/
字符串转化为日期对象:
.parse(String)方法
//字符串转换为Date对象
String format1 = "22-11-25 下午6:38";
Date parse = simpleDateFormat.parse(format1);
System.out.println(parse);
/*
Fri Nov 25 18:38:00 CST 2022
*/
按照指定格式进行格式化:
要求格式化的字符串以SimpleDateFormat的指定格式输出,则也可以用该方式进行解析。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String f1 = sdf.format(date);
System.out.println(f1);
/*
2022-08-28 10:52:15
*/
Calender日历类
Calender 是一个抽象类。不能直接调用构造器,一般使用getInstance()静态方法创建Calender的实现类.
以及get(),set(),getTime(),setTime()四个常用方法。
public void test3(){
Calendar c = Calendar.getInstance();
// get()方法用于获取一些常用数据。
//例如获取一年的第几天、一周的第几天等等
int i = c.get(Calendar.DAY_OF_MONTH);
System.out.println(i);
//set()方法可以更改c中的属性,例如下面面就更改了月中的信息
c.set(Calendar.DAY_OF_MONTH, 20);
//相当于该月加了三天
c.add(Calendar.DAY_OF_MONTH, 3);
//.getTime()将Calendar对象转换为Date对象
Date d = c.getTime();
//.setTime()将Date类的对象转化为Calendar类的对象
Date d1 = new Date();
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
}
Calander类的缺点
- 日期作为不可变量,定义之后应该是不可修改的,但Calander仍提供了可以更改日期的方法。
- 其有偏移量,若要显示真实日期还需要年份-1900以及月份-1的操作来纠正偏移量
- Calander没有提供格式化的方法,若要格式化只能转换为Date再进行格式化。
- 无法处理闰秒
Java 8中的新增API(强大)
LocalDate、LocalTime、LocalDateTime
初始化,调用.now()方法创建现在。
LocalDate l1 = LocalDate.now();
LocalTime l2 = LocalTime.now();
LocalDateTime l3 = LocalDateTime.now();
System.out.println(l1);
System.out.println(l2);
System.out.println(l3);
/*
2022-08-28
12:57:44.571
2022-08-28T12:57:44.571
*/
调用.of()方法声明某时刻,没有偏移量
LocalDateTime l4 = LocalDateTime.of(2023, 02, 10, 23, 50, 58);
System.out.println(l4);
/*
2023-02-10T23:50:58
*/
一些常用方法
//一些get方法
System.out.println(l3.getDayOfMonth()); //月中的日期
System.out.println(l3.getDayOfWeek()); //一周的第几天
System.out.println(l3.getMonth()); //String类型的月
System.out.println(l3.getMonthValue()); //int类型的月
System.out.println(l3.getMinute()); //获得分钟
/*
28
SUNDAY
AUGUST
8
6
*/
日期的更改,需要进行接收返回值,因为Local具有不可变性,其本身的日期是不会更改的。.withXxx()
LocalDateTime l5 = l4.withMonth(12); //设置月份
System.out.println(l5);
/*
2023-12-10T23:50:58v
*/
.plusXxx()时间的增加,或也可以减少等
LocalDateTime l6 = l3.plusMonths(3);
System.out.println(l6);
/*
2022-11-28T13:13:13.680
*/
Instant(瞬时点)
调用.now()方法进行创建,但默认不在本时区,则应该调用atOffset()方法调整时区。
Instant instant = Instant.now();
System.out.println(instant); //本初子午线时区、差八个小时
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); //调整时区
System.out.println(offsetDateTime);
/*
* 2022-08-28T05:22:44.723Z
2022-08-28T13:22:44.723+08:0
* */
使用.toEpochMilli()方法获取时间戳
System.out.println(instant.toEpochMilli()); // 获取时间戳
DateTimeFormatter
用来格式化或解析时间的工具,创建方式以及格式化如下:(不常用)
DateTimeFormatter d1 = DateTimeFormatter.ISO_DATE_TIME; //创建一个d1用来进行格式化,其仅仅是一个工具
LocalDateTime l1 = LocalDateTime.now();
String str = d1.format(l1);
/*
2022-08-28T13:33:13.334
*/
自定义的时间格式(常用),使用.ofPattern(“”)方法。
以及,格式化与解码
DateTimeFormatter D = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
System.out.println(D.format(LocalDateTime.now()));
/*
* 2022-08-28 01-44-12
* */
TemporalAccessor t = D.parse("1999-05-10 10:30:55");
System.out.println(t);
/*
{NanoOfSecond=0, MicroOfSecond=0, SecondOfMinute=55, MilliOfSecond=0, HourOfAmPm=10, MinuteOfHour=30},ISO resolved to 1999-05-10
*/
对象的比较
Comparable接口(自然排序)
实现了Comparable或Comparator接口的类可以对对象进行比较
Array.sort()方法中的比较是因为String类实现了Comparable接口,进而重写了Comparable接口中的compareTo()方法,所以可以对对象进行比较并且排序。
String[] str = new String[]{"AA", "BB", "KK", "GG", "CC"};
Arrays.sort(str);
System.out.println(Arrays.toString(str));
/*
[AA, BB, CC, GG, KK]
*/
若自定义类要进行排序,则需要在自定义类中实现Comparable接口并重写CompareTo()方法。
其实现大致为:若调用方法的对象大于传入形参的对应对象,则返回1,若小于则返回-1,若等于则返回0;
public int compareTo(Object o) {
if(o instanceof Goods){
Goods g = (Goods)o;
if(this.price > g.price) {return 1;}
else if(this.price < g.price){ return -1;}
else{ return 0;}
// return Double.compare(this.price, g.price);
}
throw new RuntimeException("数据类型不一致");
}
重写CompareTo()方法之后就可以在主方法中调用sort()方法进行对象的排序了
Comparator接口(自定义排序)
当不方便修改代码中的CompareTo()方法或其排序方法不合适时、可以实现CompareTo()接口,进而重写Compare()方法对其进行自定义排序
Compare(Object o1, Object o2);若o1大于o2,则返回一个正整数,若o1小于o2则返回一个负整数,相等则返回0;
一个举例:
String[] str = new String[]{"AA", "BB", "KK", "GG", "CC"};
Arrays.sort(str, new Comparator(){
@Override
public int compare(Object o1, Object o2){
if(o1 instanceof String && o2 instanceof String){
String str1 = (String)o1;
String str2 = (String)o2;
return -str1.compareTo(str2);
}
throw new RuntimeException("输入的类型不正确");
}
});
System.out.println(Arrays.toString(str));
Comparator更倾向于一个临时性的比较,一般只使用一次。