String
是一个类,属于引用类型。
Java
程序中一切使用
""
引起来的内容,都是这个类的实例,称为字符串对象。
字符串定义后是一个常量
,值不可更改。字符串
实际是一个字符数组
如何创建一个字符串对象
1.
使用
""
赋值创建
2.
通过构造方法创建
不同方式创建字符串的过程
使用
""
赋值的形式创建
使用构造方法
String(String str)
创建
使用
+
拼接
""
和
new出来的字符串对象
使用
+
拼接
""
和
new
出来的字符串对象
总结:
在使用字符串时,如果要比较其值是否相同,不要使用
==
判断,因为
==
判断的是内存地址。
所以
在比较字符串是否相同时,要使用
String
重写的
equals
方法进行判断。
String
中
equals
方法判断的原理,大致为:将两个字符串保存到字符数组中,再对每个字符逐一比较,
如果全部一致则返回。
在使用
equals
方法时,通常要将已知的非空字符串作为调用者。
可变字符串
String
字符串对象是一个常量,在定义后其值不可改变。
如果使用
String
类的对象,对其频繁更新时,就会不停地创建新的对象,重新引用。
所以如果要执行
1000
次重新赋值的过程,就要创建
1000
个字符串对象,花费很多时间和内存空间,所以
效率很低。这时就需要使用可变字符串类。
StringBuilder
类
用于表示可变字符串的一个类,是
非线程安全
的,建议在单线程环境下使用,效率略高于
StringBuffer
。
StringBuffer
类
用于表示可变字符串的一个类,是
线程安全
的,建议在多线程环境下使用,效率略低于
StringBuilder
。
StringBuilder
和
StringBuffer
中的方法作用都一致,只不过
StringBuffer
中的方法使用了
synchronized
关
键字修饰,表示一个同步方法,在多线程环境下不会出现问题。
可变字符串与不可变字符串之间的转换
有些方法如
indexOf()
、
charAt()
等,在
String
和
StringBuilder
中都存在,可以不用转换。
但有些方法如
getBytes()
、
contains()
等,只能通过
String
调用,这时就需要进行转换。
不可变字符串转换为可变字符串
通过创建一个可变字符串对象,将不可变字符串作为参数实现转换
可变字符串转换为不可变字符串
通过调用可变字符串的
toString()
方法实现转换
可变字符串面试题
比较
String
、
StringBuilder
、
StringBuffer
这三个类的区
别
相同点
这三个类都可以用于表示或操作一个字符串
这三个类中有公共的方法,如
indexOf()
、
charAt()
等、
这三个类都是被
final
修饰的类,不能被继承
不同点
String
定义的字符串是一个常量,不可变;
StringBuilder
和
StringBuffer
定义的字符串是一个变
量,可以改变。
String
类中的方法调用后,会创建字符串副本,不会影响原字符串;可变字符串对象调用的方法,
直接操作原字符串,会影响。
StringBuilder
是非线程安全的,
StringBuffer
是线程安全的,其中的方法使用
synchronized
修饰为
同步方法。在多线程情景下,需要使用
StringBuffer
。
StringBuilder
效率略高于
StringBuffer
。
包装类
Java
是纯面向对象语言,宗旨是将一切事物视为对象处理。
但原始类型不属于对象,不满足面向对象的思想,但原始类型使用时无需创建对象,保存在栈中,效率
更改。
为了让原始类型也有对象的类类型,达到
"
万物皆对象
"
的思想,所以就有了包装类的概念。
包装类就是原始类型对应的类类型。
包装类通常用于将字符串转换为对应的原始类型。
在
web
应用中,从浏览器中获取到后台的数据,全是
String
类型,一定要使用转换的方法。
特点
八个原始类型中,除了
int
和
char
之外,其余类型的包装类,都是将首字母改为大写。
int
为
Integer
,
char
为
Character
。
除了
Character
类之外,其余类都有至少两个构造方法
:
参数为原始类型或字符串的构造方法。
Character
的构造方法只有一个,参数为
char
变量。
除了
Character
类之外,其余类都有静态方法
parse
原始类型
(String str)
,用于将字符串转换为相
应的原始类型
数值型的包装类的
parseXXX()
方法,如果不是一个真正的对应类型的数,转换时会抛出
NumberFormatException
异常。如
"123abc"
、
"123.456"
都不能使用
Integer.parseInt()
转换
Boolean
类型中的
parseBoolean()
方法,参数如果是
"true"
这个单词,无论大小写,都能转换
为真正的
boolean
值的
true
,只要不是
"true"
这个单词,转换结果都为
false
除了
Boolean
类之外,其余类都有
MAX_VALUE
和
MIN_VALUE
这两个静态属性,用于获取对应原
始类型支持的最大最小范围
所有包装类中都有一个
compareTo(
参数
1,
参数
2)
方法
,
用于比较两个参数
如果是数值型,参数
1>
参数
2
返回
1
,参数
1<
参数
2
返回
-1
,相同返回
0
如果是
Boolean
型,两个参数相同返回
0
,不同时,如果参数
1
为
true
返回
1
,否则返回
-1
如果是
Character
型,返回参数
1-
参数
2
的值。
所有包装类中都有
toString()
方法,用于将包装类对象转换为
String
字符串对象
Date
类
用于表示日期时间的类,位于
java.util
包下
构造方法
常用构造方法 说明
Date() 创建当前瞬间的日期对象
Date(long l) 创建指定毫秒数对应的日期对象。
(
从
1970.1.1
起经过了的毫秒数
)
Date(int year,int 该构造方法已过时
。创建指定年月日的日期对象。
(
年从1900年起 month,int date) 的年数,月用0-11
表示
1-12月经过)
常用方法
getTime() 得到对应
Date
对象指定的毫秒数。
setTime(long l) 设置毫秒数
after(Date when) 判断调用日期对象是否在
when
之后
before(Date when) 判断调用日期对象是否在
when
之前
Calendar
类
用于表示日历的类。包含了很多日历相关的信息。
是一个抽象类,无法直接创建对象,可以通过该类的
静态方法
getInstance()
获取该类的实例
。
异常
当程序没有按程序员的意愿正常执行,中途出错导致程序中断,出现这种情况,就称为异常。
学习异常就是认识异常的种类和如何避免异常出现。
为了让程序能正常执行,就需要学会解决异常。
异常的产生
异常在程序中以对象的形式存在。当代码执行时出现异常,虚拟机会自动创建一个相应的
异常对象
,如
果没有对该异常进行处理,就会导致程序中断。
异常的分类
异常在程序中以对象的形式存在,所以异常有对应的类。
"
异常家族
"
Throwable
是异常类的根类,通常所说的异常,其实指的是
Exception
子类
Error
错误
如果出现
XXXXXError
,如
StackOverflowError
栈空间溢出时,无法通过额外的代码去解决,只能修改源
码。
Exception
异常
如果出现
XXXXException
,如
NullPointerException
空指针异常时,可以通过额外代码去避免。
运行时异常和非运行时异常
如果一个异常属于
RuntimeException
异常类的子类,称为运行时异常,可以通过编译,运行时可能抛出
异常对象。
如果一个异常属于
Exception
异常类的子类,称为非运行时异常,无法通过编译,只有处理后才能编译运
行。
处理异常
Exception
只要处理
Exception
异常类的子类时,都称为处理异常。处理异常的目的就是为了保证程序正常运行,不
要中断。
方式一:
try-catch-finally
语句
这种方式能成功地处理异常,无论会不会抛出异常,都能让程序保证正常执行。
执行流程:先执行
try
中的内容,当出现异常,与后续的
catch
进行匹配,如果匹配对应的异常类型或异
常父类型,则执行大括号中的内容,最终一定执行
finally
中的内容
try-catch
注意
执行
try
中的内容时,当某行代码抛出异常后,不再执行
try
中该行代码后续的内容。
无论
try
中是否会抛出异常,
finally
中的内容一定执行。通常
finally
用于释放资源。
如果有多个
catch
,需要将异常子类放在最前,异常父类放在最后
try
、
catch
、
finally
都不能单独使用,
try
需要配合
catch
或
finally
或
catch
和
finally
一起使用
try
中定义的内容,无法在
try
之外的地方使用
try
中如果有
return
,不影响
finally
的执行,并且
finally
优先于
return
执行
方式二:
throws
关键字
这种方式,可以让非运行时异常通过编译,定义方法的时候,声明可能抛出的异常。
用法:方法的参数小括号之后,添加
"
throws
异常类型
1
,异常类型
2...
"
自定义异常
可以自定义异常,在满足某种条件下,手动通过
throw
关键字抛出异常,人为中断程序。
自定义异常步骤
定义一个类,继承某个异常类。
如果继承的是
RuntimeException
,表示自定义的异常类属于运行时异常,该异常对象可以不用
处理。
如果继承的是非
RuntimeException
,表示自定义的异常类属于非运行时异常,该异常对象必须
要处理。
[
可选操作
]
定义一个无参数的构造方法,调用父类中无参的构造方法,定义一个带字符串参数的构
造方法,调用父类带字符串参数的构造方法。
数组的特点
数组中保存的元素都是有序的,可以通过下标快速访问
数组中保存的数据都是同一种类型
数组的长度在定义后,无法改变
数组无法获取其中保存的实际元素数量
集合
能保存一组数据,可以有序也可以无序
集合的容量可变
集合中可以保存不同类型的数据
可以获取集合中实际的元素数量
集合框架
(
集合家族
)
Iterator
接口并不算严格意义上的集合的
"
根
",
它称为迭代器,用于遍历集合元素的一个工具接口。
所以集合的根接口为:
Collection
接口
和
Map
接口
,
位于
java.util
包中
Collection
接口
核心的两个子接口:
Set
和
List
。
这两个接口都可以保存一组数据,
Set
接口保存数据时,是
无序不重复
的
;
List
接口保存数据时,是
有序
可重复
的。
List
接口
(
有序可重复
)
有序集合,元素可以重复,允许保存
null
,可以通过索引获取对应位置上的元素。
在接口中定义了一些操作元素的方法,如获取元素数量、添加、删除、替换、截取等。
ArrayList
实现类
(
掌握
)
采用数组实现的集合
可以通过索引访问元素、可以改变集合大小。如果要在其中插入或删除元素时,会影响其余元素。
该集合查询效率高、增删中间元素效率低。
该集合对象中保存的元素,都是引用类型
(
对象的内存地址
)
。即使保存了
123
,其实不是保存的
int
类型的
123
,而是
Integer
类型的
123.
数组与集合
数组的特点
数组中保存的元素都是有序的,可以通过下标快速访问
数组中保存的数据都是同一种类型
数组的长度在定义后,无法改变
数组无法获取其中保存的实际元素数量
集合的特点
能保存一组数据,可以有序也可以无序
集合的容量可变
集合中可以保存不同类型的数据
可以获取集合中实际的元素数量
LinkedList
实现类
采用
双向链表
实现的集合
集合中保存的每个元素也称为节点,除首尾节点外,每个节点即保存了自己的数据,也保存了其前
一个和后一个节点的地址
如果在其中进行插入和删除的操作时,不影响其他元素的位置,只需要重新定义新节点的前后节点
位置即可。
如果要查询某个节点的索引,需要从头结点或尾结点开始一步步得到目标节点位置
所以中间进行插入和删除的效率高,随机读取的效率低
ArrayList
和
LinkedList
的区别
两者都是
List
接口的实现类,保存的元素有序可重复,允许保存
null
,拥有一些公共的方法,如
size()
,
isEmpty()
,
subList(int from,int to)
等
ArrayList
采用数组实现,对于随机读取效率更高,通常用于查询;
LinkedList
采用双向链表实现,
插入删除不影响其他元素位置,通常用于中间插入删除。
Set
接口
(
无序不重复
)
无序集合,元素不可以重复,允许保存
null
,没有索引。
在接口中定义了一些操作元素的方法,如获取元素数量、添加、删除、替换、截取等。
哈希表
hash table
哈希表,也称为散列表,是一种数据结构,能更快地访问数据。
要保存的数据称为原始值,这个原始值通过一个函数得到一个新的数据,这个函数称为
哈希函数
,这个
新数据称为
哈希码
,哈希码和原始值之间有一个映射关系,这个关系称为
哈希映射
,可以构建一张映射
表,称为
哈希表
。在哈希表中,可以通过哈希码快速访问对应的原始值。
哈希码的特点
如果两个对象的
hashCode
不同,这两个对象一定不同
如果两个对象的
hashCode
相同,这两个对象不一定相同
如
"
通话
"
和
"
重地
"
这两个字符串的
hashCode
相同,但是两个对象
hashCode
相同,对象不同,称为哈希冲突
HashSet
实现类
采用哈希表实现
元素不能重复,无序保存,允许保存
null
常用构造方法
说明
HashSet()
创建一个默认的集合对象,实际是创建了一个大小为
16
,加载因子
为
0.75
的
HashMap
对象
HashSet(int capacity)
创建一个指定容量的集合对象,实际是创建了一个指定大小,加载
因子为
0.75
的
HashMap
对象
HashSet(int capacity,float
loadFactor)
创建一个指定容量和指定加载因子的集合对象。
本质是一个
HashMap
对象,调用
add()
方法,实际调用的也是
HashMap
中的
put()
方法,参数作为
put()
方法的键,
new Obejct()
作为
put()
方法的值
HashSet
添加数据的原理
if(
两个对象
hashCode
相同
&&
两个对象
equals
相同
){
视为同一对象,不能添加
}
每次向集合中添加元素时,先判断该元素的
hashCode
是否存在,
如果不存在,视为不同对象,直接添加
如果存在,再判断
equals
方法的结果
如果为
false
,视为不同对象,直接添加
如果为
true
,视为同一对象,不能添加
可见不能添加的条件是两个对象的
hashCode
相同并且
equals
结果为
true
。
如果每次都只判断
equals
的话,过程可能会很久,效率不高,
如果每次只判断
hashCode
的话,有可能会有哈希冲突,
所以先判断
hashCode
,再判断
equals
,既能保证效率又能保证添加进去的元素都是不相同的元素。
equals
方法和
hashCode
的关系
如果两个对象的
equlas
方法比较结果为
true
,在没有重写
equals
方法的前提下,
hashcode
相同
吗?
相同
如果两个对象的
hashCode
不同,在没有重写
equals
方法的前提下,
equals
方法比较结果为
?
false
如果两个对象的
hashCode
相同,
equals
方法比较结果为
?
可能为
true
也可能是
false
TreeSet
实现类
特殊的
Set
实现类,数据可以有序保存,可以重复,不能添加
null
元素
采用红黑树
(
自平衡二叉树
)
实现的集合
二叉树表示某个节点最多有两个子节点
某个节点右侧的节点值都大于左侧节点值
只能添加
同一种类型
的对象且
实现了
Comparable
接口
的对象
实现
Comparable
接口后必须要重写
compareTo
方法
每次调用添加时,参数会自动调用该方法
添加的元素可以自动排序
compareTo
方法的返回值决定了能否添加新元素和新元素的位置
如果返回
0
,视为每次添加的是同一个对象,不能重复添加
如果返回正数,将新元素添加到现有元素之后
如果返回负数,将新元素添加到现有元素之前
HashMap
实现类
(
掌握
)
JDK1.8
之后,
HashMap
的数据结构采用
"
数组
+
链表
+
红黑树
"
实现
当没有哈希冲突时,元素保存到数组中
如果哈希冲突,在对应的位置上创建链表,元素保存到链表中
当链表元素数量大于
8
,转换为红黑树
数据采用
"
键值对
"
的形式保存,键称为
key
,值称为
value
,键不能重复,允许
null
,值没有限
制,键和值都是引用类型
在哈希表中,哈希码就是键,保存的数据就是值,可以通过键得到相应的值。
File
文件
Java
中可以将本地硬盘中的文件
(
文件和目录
)
以对象的形式表示。
就能通过
Java
代码对本地文件进行读取或操作。
流
在
Java
中,
流用于表示计算机硬盘与内存之间传输数据的通道
。
将
内存
中的数据存入
到硬盘
中,称为
写
write
,也称为
输出
将
硬盘
中的数据存入
到内存
中,称为
读
read
,也称为
输入
流的分类
Java
中将流定义成了类,以对象的形式保存。流有
"
四大家族
"
,是所有流的父类。
InputStream
字节输入流
FileInputStream ObjectInputStream
OutputStream
字节输出流
FileOutputStream ObjectOutputStream
Writer
字符输出流
FileWriter BufferedWriter
Reader
字符输入流
FileReader BuffedredReader
按方向分类
输入流:
InputStream
、
Reader
作用:将硬盘中的数据读取到内存中
输出流:
OutputStream
、
Wrtiter
作用:将内存中的数据写入到硬盘中
按类型分
字节流:
InputStream
、
OutputStream
作用:适用于非文本类型,如图片、文件等的读写
字符流:
Reader
、
Writer
作用:适用于文本类型,尤值
txt
格式文件的读写
如要将硬盘中某个
txt
文件中的字符读取到程序中,使用
Reader
常用构造方法
说明
FileInputStream(String pathName)
根据文件名创建文件字节输入流对象
FileInputStream(File file)
根据文件对象创建文件字节输入流对象
常用方法
作用
read()
读取一个字节。返回读取到的字节本身。
read(byte[] b)
按字节数组读取。返回读取到的字节数量。读取到的内容保存在了字节数组中
close()
关闭流对象
如要将硬盘中的某个图片读取到程序中,使用
InputStream
流的四个父类的特点
以上四个类都在
java.io
包下,都是抽象类,不能直接创建其对象,要使用其子类
这四个类都有
close()
方法,用于关闭流对象释放资源
输出流
(OutputStream
和
Write)
都有
flush()
方法,用于将流中的数据到冲刷到硬盘中
在使用输出流对象时,一定要调用
flush()
或
close()
方法后,才能真正将数据写到硬盘中
输入流
(InputStream
和
Reader)
都有
read()
方法读取数据到内存中,输出流都有
write()
方法写入数
据到硬盘中
所有的流类中,以
Stream
结尾的,都是字节流,以
Reader
或
Writer
结尾的都是字符流
读取硬盘中的数据时,使用输入流;将数据写入到硬盘中时,使用输出流
读取或写入文本文件时,使用字符流;读取或写入非文本文件时,使用字节流
File
文件
Java
中可以将本地硬盘中的文件
(
文件和目录
)
以对象的形式表示。
就能通过
Java
代码对本地文件进行读取或操作。
构造方法
常用构造方法
说明
File(String pathName) 根据文件的完整路径创建对象
File(String parent,String name) 根据文件所在的父目录路径和自身文件名创建对象
File(File parent,String name) 根据文件所在父目录文件对象和自身文件夹创建对象
流
在
Java
中,
流用于表示计算机硬盘与内存之间传输数据的通道
。
将
内存
中的数据存入
到硬盘
中,称为
写
write
,也称为
输出
将
硬盘
中的数据存入
到内存
中,称为
读
read
,也称为
输入
流的分类
Java
中将流定义成了类,以对象的形式保存。流有
"
四大家族
"
,是所有流的父类。
InputStream
字节输入流
FileInputStream
文件字节输入流
ObjectInputStream
对象字节输入流
(
序列化
)
OutputStream
字节输出流
FileOutputStream
文件字节输出流
ObjectOutputStream
对象字节输出流
(
反序列化
)
Writer
字符输出流
FileWriter
文件字符输出流
BufferedWriter
缓冲字符输出流
(
包装流
)
OutputStreamWriter
字节输出
流转换为字符输出流
(
转换流
)
Reader
字符输入流
FileReader
文件字符输入流
BuffedredReader
缓冲字符输入流
(
包装流
)
InputStreamReader
字节输入
流转换为字符输入流
(
转换流
)
按方向分类
输入流:
InputStream
、
Reader
作用:将硬盘中的数据读取到内存中
输出流:
OutputStream
、
Wrtiter
作用:将内存中的数据写入到硬盘中
按类型分
字节流:
InputStream
、
OutputStream
作用:适用于非文本类型,如图片、文件等的读写
常用构造方法
说明
FileInputStream(String pathName)
根据文件名创建文件字节输入流对象
FileInputStream(File file)
根据文件对象创建文件字节输入流对象
常用方法
作用
read()
读取一个字节。返回读取到的字节本身。
read(byte[] b)
按字节数组读取。返回读取到的字节数量。读取到的内容保存在了字节数组中
close()
关闭流对象
字符流:
Reader
、
Writer
作用:适用于文本类型,尤值
txt
格式文件的读写
如要将硬盘中某个
txt
文件中的字符读取到程序中,使用
Reader
如要将硬盘中的某个图片读取到程序中,使用
InputStream
流的四个父类的特点
以上四个类都在
java.io
包下,都是抽象类,不能直接创建其对象,要使用其子类
这四个类都有
close()
方法,用于关闭流对象释放资源
输出流
(OutputStream
和
Write)
都有
flush()
方法,用于将流中的数据到冲刷到硬盘中
在使用输出流对象时,一定要调用
flush()
或
close()
方法后,才能真正将数据写到硬盘中
输入流
(InputStream
和
Reader)
都有
read()
方法读取数据到内存中,输出流都有
write()
方法写入数
据到硬盘中
所有的流类中,以
Stream
结尾的,都是字节流,以
Reader
或
Writer
结尾的都是字符流
读取硬盘中的数据时,使用输入流;将数据写入到硬盘中时,使用输出流
读取或写入文本文件时,使用字符流;读取或写入非文本文件时,使用字节流