5.1 包装类
5.1.1 来源原因
- Java定义了8种数据类型对应的引用类型(包装类、封装类),使得可以调用类中的方法。
5.1.2 分类
5.1.3 基本数据类型、包装类、String类型的相互转换:
- 基本数据类型转换为包装类:
- 装箱:基本数据类型包装成包装类的实例。
- 使用包装类的构造器:
new Integer()
。
- 可传入基本数据类型。
- 可传入字符串。
- 使用包装类的方法:
Integer.valueOf();
- 包装类转换为基本数据类型:
- 拆箱:获得包装类对象中包装的基本类型变量。
- 调用包装类的
.intValue()
方法。
- 基本数据类型转换为字符串:
- 调用字符串重载的
valueOf()
方法。 - 使用
+
拼接""
空字符串。
- 字符串转换为基本数据类型:
- 使用包装类的构造器:
new Integer()
,传入字符串。 - 使用包装类的
parseInteger(String s)
静态方法。
- 字符串转换为包装类:
- 调用包装类的构造器:
new Integer()
。
- 包装类转换为字符串:
- 调用包装类的
tostring()
方法。
- JDK1.5之后支持自动装箱、自动拆箱,但类型必须匹配
- Integer a = 10; 自动封箱
- int b = a; 自动拆箱
- 基本数据类型和包装类型使用功能
==
号比较时,比较的是数值值。
5.2 String类
5.2.1 String对象的特点
- 继承自Object
- 使用双引号包裹。
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母和汉字)占用2个字节。
- 常见创建方式(常用构造器):
new String()
:空参new String(String str)
:字符串字面量new String(char[] a)
:字符型数组new String(byte[] b)
:btye型数字(一个byte数占1个字节)new String()
:
- String由final修饰,不可被继承。源码
public final class String{}
- String内定义了
private final char value[]
,用于存放字符串内容。
- 由于value数组被final修饰,所以不能改变value的地址值。
- 如果改变字符串变量的字面量值,如将
String str = s;
改为String str = str;
则表示str指向常量池中新的地址。而不是对常量池中s所在的地址空间重新填充内容。 - 体现:
- 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。 - 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
5.2.2 创建String对象细节
- 比较对象:
- 字面量方式:
String str = "string";
- 构造器方式:
String str = new String(string);
- 字面量方式:
- 从常量池检查是否已有该字符串
- 常量池中有,str指向常量池中该字符串的地址
- 常量池中没有,先创建该字符串,然后str指向该字符串在常量池中的地址
- 构造器方式:
- new String在堆空间创建了地址空间,str指向该地址
- new String开辟的内存空间中的属性value数组,在常量池中查找字符串
- 常量池中有,value指向常量池中该字符串的地址
- 常量池中没有,先创建该字符串,然后value指向该字符串在常量池中的地址
- 字面方式创建注意点:
String d = "helloabc";
与String e = "hello" + "abc";
等价,指向常量池同一地址。String a = "hello";String b = "abc";String c = a + b;
与String e = "hello" + "abc";
不等价。
String c = a + b;
底层会先进行StringBuilder c = new StringBuilder()
,然后调用append()方法将a和b添加进去,此时创建的StringBuilder()对象在堆内存中,所以c保存的是堆空间的地址。- 如果再执行
c.intern();
则与String e = "hello" + "abc";
等价。
- 原因为intern()方法会在常量池中查找是否存在该字符串,存在时返回常量池中的对象(含地址),不存在则创建。
String a = "hello";String b = "abc" + a;
只要有变量参与,就会调用StringBuilder()创建对象。
- 但假如
final String a = "hello"
,则结果仍在常量池,因为此时a变成了常量
- 结论:
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 只要其中有一个是变量,结果就在堆中。
- 如果拼接的结果调用intern()方法,返回值就在常量池中
5.2.3 JVM中涉及字符串的存放位置
【参见JVM虚拟机】
- jdk 1.6:字符串常量池存储在方法区(永久区)
- jdk 1.7:字符串常量池存储在堆空间
- jdk 1.8:字符串常量池存储在方法区(元空间)
5.2.4 String常见方法
- 操作:
int length()
:返回字符串的长度: return value.lengthchar charAt(int index)
: 返回某索引处的字符return value[index]boolean isEmpty()
:判断是否是空字符串:return value.length == 0String toLowerCase()
:使用默认语言环境,将 String 中的所有字符转换为小写String toUpperCase()
:使用默认语言环境,将 String 中的所有字符转换为大写String trim()
:返回字符串的副本,忽略前导空白和尾部空白boolean equals(Object obj)
:比较字符串的内容是否相同boolean equalsIgnoreCase(String anotherString)
:与equals方法类似,忽略大小写String concat(String str)
:将指定字符串连接到此字符串的结尾。 等价于用“+”int compareTo(String anotherString)
:比较两个字符串的大小
- 查找:
boolean endsWith(String suffix)
:测试此字符串是否以指定的后缀结束boolean startsWith(String prefix)
:测试此字符串是否以指定的前缀开始boolean startsWith(String prefix, int toffset)
:测试此字符串从指定索引开始的子字符串是否以指定前缀开始boolean contains(CharSequence s)
:当且仅当此字符串包含指定的 char 值序列时,返回 trueint indexOf(String str)
:返回指定子字符串在此字符串中第一次出现处的索引int indexOf(String str, int fromIndex)
:返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
- 如果
fromIndex
为负数,表示从尾部开始,到头部的顺序查找,仍然是正序查找。
int lastIndexOf(String str)
:返回指定子字符串在此字符串中最右边出现处的索引int lastIndexOf(String str, int fromIndex)
:返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
- 替换:
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 substring(int beginIndex)
:返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。String substring(int beginIndex, int endIndex)
:返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
- String 与 char[]之间的转换
- String --> char[]:调用String的toCharArray()
- char[] --> String:调用String的构造器
- String 与 byte[]之间的转换
- 编码:String --> byte[]:调用String的getBytes()
- 解码:byte[] --> String:调用String的构造器
- 解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
- String 与基本数据类型、包装类之间的转换。
- String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
- 基本数据类型、包装类 --> String:调用String重载的valueOf(xxx)
- 注意:由于字符串是不可变的,所以操作字符串的方法基本都有返回值,而原字符串不会发生改变。
5.2.5 StringBuffer
- 特性:
- 可变的字符序列,对字符串进行增删,不会产生新的对象
- 作为参数传递时,方法内部可以改变值。
- 构造器:
StringBuffer()
:初始容量为16的char型字符串数组StringBuffer(int size)
:指定size容量的字符串StringBuffer(String str)
:将内容初始化为指定字符串内容。
- 常用方法:
- 增:
StringBuffer append(xxx)
: - 删:
StringBuffer delete(int start,int end)
: - 改:
StringBuffer replace(int start, int end, String str)
:public void setCharAt(int n ,char ch)
:
- 查:
public char charAt(int n)
: - 插:
StringBuffer insert(int offset, xxx)
: - 遍历:
for() + charAt()
或者toString()
- 其他:
StringBuffer reverse()
:把当前字符序列逆转public int indexOf(String str)
public String substring(int start,int end)
:public int length()
:
- 注意点:返回值类型为StringBuffer的方法会对原数据进行修改,返回值类型为String类型的方法不会对元数据进行修改。
- 底层原理:StringBuffer的方法底层返回了this,既是对当前数据的返回,也表明支持链式操作
5.2.6 StringBuilder
- 同StringBuffer,JDK5.0新增,只是线程不安全,效率优于StringBuffer。
- 开发中建议使用:
StringBuffer(int capacity)
或StringBuilder(int capacity)
。
5.3 时间API
- JDK8之前:
- java.lang.System类:
currentTimeMillis()
,获取当前时间距离1970年1月1日0时0分0秒的毫秒数 - java.util.Date类 :
- 构造器:
Date()
Date(long date)
- 方法:
getTime()
:获取当前时间距离1970年1月1日0时0分0秒的毫秒数toString()
:【重写方法】按照down mon dd hh:mm:ss zzz yyy的格式输出
- down:星期几
- zzz:时间标准
- java.sql.Date类:
- java.util.Date类的子类
- 创建时使用全包名:即
new java.sql.Date()
- 相互转换:
- 方式一:创建Date对象的多态java.sql.Date对象;创建java.sql.Date对象,使用向上转型(强转)——注意:强转的前提是Date对象是由java.sql.Date创建的。
- 方式二:通过共有方法
getTime()
获取时间戳
- java.text.SimpleDataFormat类:
- 用于对Date类的格式化和解析
- 创建指定格式的对象:
SimpleDateFormat()
:默认格式SimpleDateFormat("yyyy-MM-dd")
:指定格式
- 格式化:将日期输出为字符串
- 调用
foramt(Date date)
方法:
- 解析:将字符串转换为日期
- 调用
parse(String sourse)
方法:
- 这里sourse的格式必须与创建
SimpleDateFormat()
对象的格式一致 - 有异常问题
- java.util.Calendar(日历)类 :
- 用于日期字段(fileld)间的相互操作
- field:Calendar类的静态属性:YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、 MINUTE、SECOND
- 获取Calendar实例:
Calendar calendar = Calendar.getInstance();
- Calendar时抽象类,无法实例化,调用静态方法
getInstance()
实际上会调用其子类GregorianCalendar
创建对象。
- 常用方法:
int get(int field,int value)
void set(int field,int value)
void add(int field,int amount)
Date getTime()
:日历类转换Date类void setTime(Date date)
:Date类转换日历类
- 日期时间API的迭代:
- 第一代:jdk 1.0 Date类
- 第二代:jdk 1.1 Calendar类,一定程度上替换Date类
- 第三代:jdk 1.8 提出了新的一套API
- 前两代存在的问题举例:
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
- 格式化:格式化只对Date用,Calendar则不行。
- 此外,它们也不是线程安全的;不能处理闰秒等。
- JDK8新增API
- java.time – 包含值对象的基础包
- java.time.chrono – 提供对不同的日历系统的访问
- java.time.format – 格式化和解析时间和日期
- java.time.temporal – 包括底层框架和扩展特性
- java.time.zone – 包含时区支持的类
- JDK8新增时间类(构造方法私有的,不能实例化):
- LocalDate:获取ISO格式(yyyy-MM-dd)的日期
- LocalTime:获取时间
- LocalDateTime:获取日期和时间
- 常用方法:
now()
(静态方法):获取当前的日期、时间、日期+时间,创建类对象of()
:设置指定的年、月、日、时、分、秒。没有偏移量getXxx()
:获取相关的属性withXxx()
:设置相关的属性
- Instant(类似于Calendar,不可实例化):
now()
(静态方法):获取本初子午线对应的标准时间。Instant instant = Instant.now()
atOffset()
:添加时间的偏移量toEpochMilli()
:获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数ofEpochMilli()
:通过给定的毫秒数,获取Instant实例
- DateTimeFormatter:格式化或解析日期、时间
- 预定义的标准格式:
DateTimeFormatter.ISO_LOCAL_DATE_TIME
DateTimeFormatter.ISO_LOCAL_DATE
DateTimeFormatter.ISO_LOCAL_TIME
- 本地化相关格式:
DateTimeFormatter.ofLocalizedDateTime(FFormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT)
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT)
- 自定义格式:
DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")
- 格式化:
时间格式.format(时间)
,返回字符串 - 解析:
时间格式.parse(符合时间格式的字符串)
,返回TemporalAccessor类型日期
5.4 其他类
- Math类:
- 常用方法:
double floor(double a)
:——向坐标轴左侧取整,如1.2、1.6得1.0;-1.2、-1.6得-2.0。int round(double a)
:——本质是(int)Math.floor(a + 0.5f)
。
- 正数四舍五入;负数不可记按正数四舍五入加负号,因为
round(-1.5)
得-1
- System类
- 构造器是private的,无法创建该类的对象,内部的成员变量和成员方法都是static的,可以直接进行调用。
- 方法:
native long currentTimeMillis()
void exit(int status)
:退出当前程序
- status:0表示正常状态。
arrayCopy()
:
- 参数1:源数组
- 参数2:源数组开始索引(包含)
- 参数3:目标数组
- 参数4:目标数组位置开始索引(包含)
- 参数5:源数组拷贝数量
void gc()
String getProperty(String key)
- BigInteger类
- BigInteger可以表示不可变的任意精度的整数
- 不能使用
+、-、*、/
,需要使用相应的方法。
- BigDecimal类
- Array类:
toString()
:重写Object方法,默认调用,输出数组元素
- 对象数组时,输出的时数组内每个对象的地址,如果还要显示每个对象的内容,就需要重写类的toString方法。
sort()
:默认从小到大排序binarySearch()
:通过二分法查找指定数,返回索引,要求必须排好序,无序数组不能使用。如果不存在,返回-(low+1)
copyOf()
:拷贝指定数量的数组元素。
- 新数组比就数组长,最后几位为null
- 拷贝长度小于0,抛出异常,等于0,新数组为空
fill()
:替换数组的全部元素equals()
:比较数组元素是否一致asList()
:将括号内数据转换为List集合。
- Scanner类:
next()
:接收数据,输入空格、回车、英文引号表示结束
5.5 比较器
- 作用:比较两个对象,用于对象数组排序。
- 自然排序:
java.lang.Comparable
包中的Comparable
接口- String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
- 像String、包装类重写compareTo()方法以后,进行了从小到大的排列
- 重写compareTo(obj)的规则:
- 如果当前对象this大于形参对象obj,则返回正整数
- 如果当前对象this小于形参对象obj,则返回负整数
- 如果当前对象this等于形参对象obj,则返回零
- 对于自定义类来说,如果需要排序,可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序
- 定制排序:
- 当元素的类型没实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 匿名的Comparator 的对象来排序
- 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
- 如果方法返回正整数,则表示o1大于o2;
- 如果返回0,表示相等;
- 返回负整数,表示o1小于o2。
- 补充:
- 包装类具有
compare
、compareTo
两个方法,其中compareTo
是静态方法。 - String具有
compareTo
、conpareToIngoreCase
方法
- 比较:
- Comparable 位于 java.lang 包, Comparator 位于java.util 包。
- 实现Comparable接口需要重写compareTo()方法,实现Comparator方法需要重写compare()方法,这两个方法的类型都是int
- Comparable是排序接口,相当于内部比较器,称为自然排序,Comparator是比较器,相当于外部比较器,称为比较器排序,外部比较器可以对内部比较器进行扩充。
- int test = s1.compareTo(s2); result = 0 , 则 s1=s2 ; result < 0, 则 s1 0 , 则 s1 > s2 。
- int test= compare(T o1, T o2); 结果同上。 (若是 o2-o1,则反之。)
- 如果对象的排序需要基于自然顺序,使用 Comparable比较合适,如果需要按照对象的不同属性进行排序,使用 Comparator比较合适。