1.String的特性
代表字符串,java中所有字符串字面值都作为此类的实现例实现。String是一个final类,不能被继承。String实现了Serialiable,表示字符串支持序列化,实现了Comarable,表示String可以比较大小。
1.1 String不可变性:减少大量的同步锁
String不可变性是指内部维护一个不可变的char数组,来向外输出的。上为jdk中的代码,类由final修饰表示是不可继承的;核心域value[]是private final的,final表示此引用指向的内存地址不会发生改变,但是内存地址中存储的值仍可能会发生改变。
为了解决这一问题jdk采用了“保护性拷贝”,使得内存地址中存储的值不会发生改变:
面试题:
public class StringTest {
private String str = "good";
private char[] ch = {'t', 'e', 's', 't'};
public void change(String str, char[] ch) {
str = "testGood";
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest stringTest = new StringTest();
stringTest.change(stringTest.str, stringTest.ch);
System.out.println(stringTest.str);
System.out.println(stringTest.ch);
//good
//best
}
}
Java引用型变量作为形参时,传递给方法的是变量的内存地址,str此时传递的是内存方法区的常量池中的“good”字符串的内存地址,属性str作为String类型指向的字符数组“good”内存地址不可变,而不是str这个string引用指向不可变。
1.2 String的定义方式
1.字面量的定义方式
String s = “abc”;字符串"abc"声明在内存方法区的字符串常量池中,并将字符串地址赋值给s。字符串常量池是不会存储两个相同的字符串。
2.new方式
两种方式的区别:字符串常量存储在方法区的常量池,非常量对象存储在堆中
String s1 = "javaEE";
String s2 = "javaEE";
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(s3 == s4);//false
String s = new String("abc");方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间的new结构,另一个是方法区常量池中的char[]数据"abc"
public static void main(String[] args) {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEE" + "hadoop";
String s4 = s1 + "hadoop";
String s5 = "javaEE" + s2;
String s6 = s1 + s2;
String s7 = "javaEEhadoop";
String s8 = (s1 + s2).intern();
String s9 = s1 + s2;
System.out.println(s3 == s4);//false
System.out.println(s5 == s4);//false
System.out.println(s5 == s6);//false
System.out.println(s7 == s3);//true
System.out.println("javaEEhadoop" == s8);//true
System.out.println(s9 == s6);//false
};//true
}
凡是涉及到对象名、数组名(new出来的结构)均声明在堆结构中,与字面量结构做连接运算也会在堆结构new新对象。(s1 + s2).intern()因为使用intern结果也存储于方法区常量池中。
1.3 String的常用方法
chatAt(int index) | |
length() | |
isEmpty() | |
toLowerCase() toUperCase() |
|
trim() | 忽略前后空白 |
equalsIgnoreCase() | |
concat() | + |
compareTo() | 比较字符串大小 |
substring(int startIndex) | |
substring(int startIndex. int endIndex) | |
boolean endsWith(String suffix) | |
boolean startsWith(String suffix) | |
boolean startsWith(String suffix, int index) | |
boolean contains(charSquence) | |
int indexOf(String str) | 返回子串第一次出现的索引 |
int indexOf(String str, int fromIndex) | 从指定索引开始 |
int lastIndexOf(String str) | 返回子串最后一次出现的索引 |
int lastIndexOf(String str, int fromIndex) | 从指定索引开始反向搜索 |
String replace(char oldChar, char newChar) | 替换全部的字符 |
String replaceAll(String regex, String new) | 正则替换 |
boolean matches(String regex) | |
String[] split(String regex) | 按照正则表达式拆分字符串 |
String[] split(String regex, int limit) | |
1.4 String与其它结构之间的转换
String -> 基本数据类型、包装类:Integer.parseInt(str);
基本数据类型、包装类 -> String: ①String.valueOf(****);
② +""
String -> char[]:str.tocharArray()
String -> byte[]:str.getBytes() 编码
byte[] -> String:Arrays.toString()
new String(bytes, "编码") 解码
1.5 StringBuffer和StringBuilder
StringBuffer:可变的字符序列,方法均为synchronized同步方法,线程安全但是效率偏低。底层数组创建初始长度为16方便修改,长度不足时进行扩容底层的数组,默认情况下扩容为原来容量的二倍 + 2,同时将原来数组的元素赋值到新数组中。
另外也可以在new的时候设置构造器参数为字符串长度。
StringBuffer sb = new StringBuffer(int strLength);
StringBuilder:可变的字符序列,线程不安全但是效率高一些。
StringBuffer 常用方法
append() | 增 |
delete() | 删 |
replace(int start, int end, String str),setCharAt(int index,char ch) | 改 |
subString(int start, int end)、charAt(int index) | 查 |
insert(int start, String str) | 插 |
length() | 长度 |
reverse() | 字符串翻转,String没有 |
for + charAt(int index) | 遍历 |
效率:StringBuilder > StringBuffer > String
一些注意点
append对于null的处理是转换为字符串“null”然后进行添加。
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
String str = null;
sb.append(str);
System.out.println(sb.length());//4
System.out.println(sb);//"null"
sb = new StringBuffer(str);//抛出异常
}
2.Date
System | |
---|---|
long System.currentTimeMillis() | 返回当前时间与1970年1月1日0时0分0秒之间以毫秒计数的时间差。一般称为时间戳。 |
java.uti.Date
两个构造器 | |
---|---|
Date date = new Date() | 创建一个当前时间的Date对象,toString()展示当前时间的年月日时间。 |
Date date = new Date(年月日、毫秒数) | 创建指定时间的Date对象。 |
date.getTime()也可以获取当前时间与1970年1月1日0时0分0秒之间以毫秒计数的时间差。
java.sql.Date
toString() 显示年-月-日
sqlDate对象 -> utilDate对象转换:子类转父类体现多态,父类转子类需要强转且声明的父类本来就是new的子类
java.util.Date date = new java.sql.Date(1991, 10, 1);//子类转父类体现了多态
java.sql.Date date1 = new java.sql.date(date.getTime());//父类转子类的解决方法
3.java.text.SimpleDateFormat
Date类不易于国家化,java.text.SimpleDateFormat是一个不与语言环境有关的方式来格式化和解析日期的具体类。它允许进行格式化和解析。
格式化:日期->文本 | |
---|---|
new SimpleDateFormat() | 默认构造器,结果为22-3-14 下午4:10的形式 |
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); | 2022-03-14 04:12:40 |
sdf.format(date) |
解析:文本->日期 | |
---|---|
sdf.parse(str) |
4 java.util.calendar 日历类的使用
实例化方法 | |
---|---|
Calendar calendar = Calendar.getInstance(); | 对象仍是Calendar的子类GregorianCalendar的对象 |
Calendar calendar = new GregorianCalendar(); |
常用方法 | |
---|---|
get(Calendar.DAY_OFMONTH) | 获取一些常用数据 |
set(date) | Date->Calendar |
add() | |
getTime() | 返回Date对象 |
setTime() |
5.jdk8新时间API java.time
原来存在的问题
1.日期时间应该是不可变的。(通过构造器创建Date对象年份需要-1990月份需要-1)
2.Date中的年份是从1900年开始,而月份是从0开始。
3.格式化只对Date有用,对Calendar没用。
4.它们线程不安全,不能处理闰秒。
实例化方式一:获取当前时间
LocalDate ld = LocalDate.now();
LocalTime lt = LocalTime.now();
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime of = LocalDateTime.of(2022, 10, 6, 19, 10, 0);
实例化方式二:获取设置时间
System.out.println(of.getDayOfMonth());
System.out.println(of.getDayOfWeek());
System.out.println(of.getYear());
System.out.println(of.getMonth());
with的"不可变性"
LocalDateTime of2 = of.withDayOfMonth(15);
System.out.println(of);//没有改变
System.out.println(of2);//发生改变
plus方法
LocalDateTime of2 = of.plusDays(1);
System.out.println(of)//没有改变;
System.out.println(of2//发生改变);
6.Instant 瞬时
面向机器的以毫秒计数记录应用时间的时间戳。
Instant.now() | 以本初子午线中时区为基准 |
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); | 东八区时间 |
7.java.date.format.DateTimeFormat
格式化解析LocalDate、LocalTime、LocalDateTime日期和时间,类似于SimpleDataFormat
初始化方式:
//1.预定义的标准格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
//2.本地相关的格式
//3.自定义的格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
8.System
成员方法 | |
---|---|
System.currentTimeMillis() | |
void exit(int status) | 退出程序,0代表正常退出,非0代表异常退出 |
void gc() | 请求系统进行垃圾回收 |
String System.getProperty("") |
9.Math
10.BigInteger与BigDecimal
BigInteger
Integer最大231-1,Long最大263-1,BigInteger可表示不可变的任意精度的整数。
BigInteger构造器
BigInteger(String val):根据字符串构建BigInteger对象。
常用方法 | |
---|---|
BigInteger abs() | |
BigInteger add(BigInteger val) | + |
BigInteger subtract(BigInteger val) | - |
BigInteger multiply(BigInteger val) | |
BigInteger divide(BigInteger val) | / |
BigInteger remainder(BigInteger val) | % |
BigInteger[] divideAndRemainder(BigInteger val) | 返回包含(this/val)和(this%val)的BigInteger数组 |
BigInteger pow(int exponent) |
“不变性”
BigInteger b = new BigInteger("111111111111111111111111111111111111111111111111111111");
BigInteger c = b;
b.add(c);
System.out.println(b);//不发生改变
System.out.println(c);//不发生改变
BigInteger b = new BigInteger("111111111111111111111111111111111111111111111111111111");
BigInteger c = b;
b = b.add(c);
System.out.println(b);//发生改变
System.out.println(c);//不变
BigDecimal
BigDecimal构造器
BigDecimal bigDecimal = new BigDecimal(double val);
BigDecimal bigDecimal = new BigDecimal(String val);
通过BigDecimal实现保留小数点
public BigDecimal setScale(int newScale,int roundingMode)
newScale表示保留的位数
roundingMode表示要保留的类型
roundingMode类型 | |
---|---|
BigDecimal.ROUND_HALF_UP | 四舍五入 |
BigDecimal.ROUND_HALF_DOWN | 四舍五入 |
ROUND_UP | 只要弃位非0就进一位 |
ROUND_DOWN | 不管如何都不会进位 |