Java基础类库
本章思维导图
用户互动
使用Scanner获取键盘输入
- Scanner主要提供了两个方法来扫描输入
hasNextXxx();
- 是否还有下一个输入项,其中
Xxx
可以是int
、long
等代表基本数据类型的字符串。
- 是否还有下一个输入项,其中
nextXxx();
- 获取下一个输入项。
Xxx
的含义与前一个方法中的Xxx
相同。
- 获取下一个输入项。
默认情况下,Scanner使用空白(空格
、Tab
、回车
)作为多个输入项之间的分隔符。
如果希望改变Scanner的分隔符,使用方法useDelimiter(String pattern);
Scanner的读取操作可能被阻塞,Scanner的hasNext();
和next();
方法都有可能阻塞,hasNext();
方法是否阻塞与和其相关的next();
方法是否阻塞无关
为Scanenr设置分隔符使用useDelimiter(String pattern);
方法即可,该方法的参数应该是一个正则表达式
-
Scanner提供了两个简单的方法来逐行读取
boolean hasNextLine();
- 返回输入源中是否还有下一行
String nextLine();
- 返回输入源中下一行的字符串
-
Scanner不仅能读取用户的键盘输入,还可以读取文件输入。
- 只要在创建Scanner对象时传入一个
File
对象作为参数,就可以让Scanner读取该文件的内容。
- 只要在创建Scanner对象时传入一个
系统相关
System类
System类代表当前Java程序的运行平台,程序不能创建System类的对象,System类提供了一些类变量和类方法,允许直接通过System类来调用这些类变量和类方法。
- System类提供了代表标准输入、标准输出和错误输出的类变量,并提供了一些静态方法用于访问环境变量、系统属性的方法,还提供了加载文件和动态链接库的方法。
- 加载文件和动态链接库主要对
native
方法有用,对于一些特殊的功能(如访问操作系统底层硬件设备等)Java程序无法实现,必须借助C语言来完成,此时需要C语言为Java方法提供实现。-
- Java程序中声明native修饰的方法,类似于
abstract
方法,只有方法签名,没有实现。编译该Java程序,生产一个class
文件。
- Java程序中声明native修饰的方法,类似于
-
- 用
javah
编译第1步生产的class
文件,将生产一个.h
文件。
- 用
-
- 写一个
cpp
文件实现native方法,这一步需要包含第2步产生的.h
文件(这个.h
文件中包含了JDK带的jni.h
文件)。
- 写一个
-
- 将第3步的
.cpp
文件编译成动态链接库文件。
- 将第3步的
-
- 在Java中用System类活动
loadLibrary..()
方法或Runtime类的loadLibrary()
方法加载第4步产生的动态链接库文件,Java程序中就可以调用这个native方法了。
- 在Java中用System类活动
-
- 加载文件和动态链接库主要对
调用System类的getenv()
、getProperties()
、getProperty()
等方法来访问程序所在平台的环境变量和系统属性。
System类提供了通知系统进行垃圾回收的gc()
方法,以及通知系统进行资源清理的runFinalization()
方法。
- System类还有两个获取系统当前时间的方法
currentTimeMillis();
nanoTime();
- 它们都返回一个
long
型整数;实际上它们都返回当前时间与UTC1970年1月1日午夜的时间差,前者以毫秒作为单位,后者以纳秒作为单位。 - 这两个方法返回的时间粒度取决于底层的操作系统,可能所在的操作系统根本不支持以毫秒、纳秒作为计时单位。
- 许多操作系统以几十毫秒为单位测量时间,
currentTimeMillis()
方法不可能返回精确的毫秒数;而nanoTime()
方法很少用,因为大部分操作系统都不支持使用纳秒作为计时单位。
System类的in
、out
、err
分别代表系统的标准输入(通常是键盘输入)、标准输出(通常是显示器)和错误输出流,并提供了setIn()
、setOut()
和setErr()
方法来改变系统的标准输入、标准输出和标准错误输出流。
System类还提供了一个identityHashCode(Object x);
方法,该方法返回指定对象的精确hashCode
值,根据该对象的地址计算得到的hashCode
值。
Runtime类与java9的ProcessHandle
Runtime类代表Java程序运行时的环境,每个Java程序都有一个与之对应的Runtime实例,应用程序通过该对象与其运行时环境相连。
应用程序不能创建自己的Runtime实例,但可以通过getRuntime()
方法获取与之关联的Runtime对象。
Runtime类也提供了gc()
方法或runFinalization()
方法来通知系统进行垃圾回收、清理系统资源,并提供了load(String filename)
和loadLibrary(String libname)
方法来加载文件和动态链接库。
- Runtime类部分方法
availableProcessors();
freeMemory();
totalMemory();
maxMemory();
exec();
通过exec启动平台上的命令之后,它就变成了一个进程,Java使用Process来代表进程。
Java9新增了一个ProcessorHandle
接口,通过该接口可获取进程的ID、父进程和后代进程;通过该接口的onExit()
方法可在进程结束时完成某些行为。
ProcessorHandle
还提供了一个ProcessorHandle.Info
类,用于获取进程的命令、参数、启动时间、累计运行时间、用户等信息。
常用类
Object类
- 常用方法
boolean equals(Object obj);
- 判断指定对象与该对象是否相等。
protected void finalize();
- 当系统中没有引用变量引用到该对象时,垃圾回收器调用此方法来清理该对象的资源。
Class<?> getClass();
- 返回该对象的运行时类。
int hashCode();
- 返回该对象的hashCode值。
String toString();
- 返回该对象的字符串表示。
Java还提供了一个protected
修饰的clone()
方法,该方法用于帮助其他对象实现自我克隆,就是得到一个当前对象的副本,而且二者之间完全隔离。
- 自定义类实现克隆的步骤
-
- 自定义类实现
Cloneable
接口。这是一个标记行性的接口,实现接口的对象可以实现自我克隆,接口里没有定义任何方法。
- 自定义类实现
-
- 自定义类实现自己的
clone()
方法。
- 自定义类实现自己的
-
- 实现
clone()
方法时通过super.clone();
调用Object
实现的clone()
方法来得到该对象的副本,并返回副本。
- 实现
-
Object类提供的Clone机制只对对象里各实例变量进行简单复制,如果实例变量的类型是引用类型,Object的Clone机制也只是简单地复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例。
Object类的clone()
方法只是一种浅克隆,只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行克隆。
如果需要对对象进行深克隆,则需要进行递归克隆,保证所有引用类型的成员变量值所引用的对象都被复制了。
Objects类
Java7新增的一个类,提供了一些工具方法来操作对象,这些工具方法大多是空指针安全的。
Java为工具类的命名习惯是添加一个字母s
,比如操作数组的工具类是Arrays
,操作集合的工具类是Collections
。
Java9改进的String、StringBuffer和StringBuilder类
Java提供了String
、StringBuffer
和StringBuilder
三个类来封装字符串,并提供了一系列方法来操作字符串对象。
String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象的字符序列是不可改变的,直至这个对象被销毁。
StringBuffer
对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()
、insert()
、reverse()
、setCharAt()
、setLength()
等方法改变这个字符串对象的字符序列。一旦通过StringBuffer生产了最终想要的字符串,就可以调用它的toString()
方法将其转换为一个String对象。
StringBuilder
类是JDK1.5新增的类,它也代表可变字符串对象。StringBuffer和StringBuilder基本相似,两个类的构造器和方法也基本相同。不同的是,StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。
String、StringBuffer、StringBuilder都实现了CharSequence
接口,因此CharSequence
可认为是一个字符串的协议接口。
-
String类提供了大量构造器来创建String对象
String()
:创建了一个包含0个的字符串序列的String对象。String(byte[] bytes, Charset charset)
:使用指定的字符集将指定的byte[]
数组解码成一个新的String对象。String(byte[] bytes, int offset, int length)
:使用平台默认的字符集将指定的byte[]
数组从offset
开始、长度为length
的子数组解码成一个新的String对象。String(byte[] bytes, int offset, int length, String charsetName)
:使用指定的字符集将指定的byte[]
数组从offset
开始、长度为length
的子数组解码成一个新的String对象。String(byte[] bytes, String charsetName)
:使用指定的字符集将指定的byte[]
数组解码成一个新的String对象。String(char[] value, int offset, int count)
:将指定的字符数组从offset
开始、长度为count
的字符元素连缀成字符串。String(String original)
:根据字符串直接量来创建一个String对象。String(StringBuffer buffer)
:根据StringBuffer
对象来创建对应的String对象。String(StringBuilder builder)
:根据StringBuilder
对象来创建对应的String对象。
-
String类也提供了大量方法来操作字符串对象
char charAt(int index)
:获取字符串中指定位置的字符。int compareTo(String anotherString)
:比较两个字符串的大小。如果两个字符串的字符序列相等,则返回0;不相等时,从两个字符串第0个字符开始比较,返回第一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。String concat(String str)
:将该String对象和str连接在一起。boolean contentEquals(StringBuffer sb)
:将该对象与StringBuffer对象sb进行比较,当它们包含的字符序列相同时返回true。static String copy ValueOf(char[] data)
:将字数组连缀成字符串。static String copyValueOf(char[] data, int offset, int count)
:将char数组的子数组中的元素连缀成字符串。boolean endsWith(String suffix)
:返回该String对象是否以suffix
结尾。boolean equals(Object anObject)
:将字符串与指定对象比较,如果二者包含的字符序列相等,则返回true,否则返回false。boolean equalsIgnoreCase(String str)
:将字符串与str
忽略大小写比较。byte[] getBytes()
:将该String对象转换成byte
数组。void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
:该方法将字符串中从srcBegin
开始,到srcEnd
结束的字符复制到dst
字符数组中,其中dstBegin
为目标字符数组的起始复制位置。int indexOf(int ch, int fromIndex)
:找出ch
字符在该字符串中从fromIndex
开始第一次出现的位置。int indexOf(String str)
:找出str
子字符串在该字符串中第一次出现的位置。int indexOf(String str, int fromIndex)
:找出str
子字符串在该字符串中从fromIndex
开始第一次出现的位置。int lastIndexOf(int ch)
:找出ch
字符在该字符串中最后一次出现的位置。int lastIndexOf(int ch, int fromIndex)
:找出ch
字符中从fronIndex
在该字符串中最后一次出现的位置。int lastIndexOf(String str)
:找出str
子字符串在该字符串中最后一次出现的位置。int lastIndexOf(String str, int fromIndex)
:找出str
子字符串在该字符串中从fromIndex
开始后最后一次出现的位置。int length()
:返回当前字符串长度。String replace(char oldChar, char newChar)
:将字符串中第一个oldChar
替换成newChar
。boolean startsWith(String prefix)
:该String对象是否以prefix
开始。boolean startsWith(String prefix, int toffset)
:该String对象从toffset
位置算起,是否以prefix
开始。String substring(int beginIndex)
:获取从beginIndex
位置开始到结束的字符串。String substring(int beginIndex, int endIndex)
:获取从beginIndex
位置开始到endIndex
位置的子字符串。char[] toCharArray()
:将该String对象转换成char数组。String toLowerCase()
:将字符串转换成小写。String toUpeprCase()
:将字符串转换成大写。static String valueOf(X x)
:一系列用于将基本类型值转换为String对象的方法。
-
StringBuffer、StringBuilder有两个属性:
length
和capacity
。- 其中
length
属性表示其包含的字符串序列的长度。与String对象不同的是,StringBuffer、StringBuilder的length是可以改变的,可以通过length()
、setLength(int len)
方法来访问和修改其字符序列的长度。 capacity
属性表示StringBuilder的容量,capacity
通常比length
大,程序通常无需关心capacity
属性。
- 其中
Math类
Math类是一个工具类,它的构造器被定义成private
的,因此无法创建Math类的对象;Math类中的所有方法都是类方法;还提供了的两个类变量PI
和E
。
ThreadLocalRandom与Random
Random
类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子(以当前时间作为种子),另一个构造器需要显式传入一个long
型整数的种子。
ThreadLocalRandom
类是Java7新增的一个类,它是Random
的增强版。在并发访问的环境下,使用ThreadLocalRandom
来代替Random
可以减少多线程资源竞争,最终保证系统具有更好的线程安全性。
ThreadLocalRandom
类的用法和Random
类的用法基本相似,它提供了一个静态的current()
方法来获取ThreadLocalRandom
对象,获取该对象之后即可调用各种nextXxx()
方法来获取伪随机数。
Random使用一个48位的种子,如果这个类的两个实例都是用同一个种子创建的,对它们以同样的顺序调用方法,则它们会产生相同的数字序列。
为避免两个Random对象产生相同的数字序列,通常推荐使用当前时间作为Random对象的种子:System.currentTimeMillis();
BigDecimal类
float
、double
两种基本浮点类型的浮点数容易引起精度丢失。
为了精确表示、计算浮点数,Java提供了BigDecimal
类,该类提供了大量的构造器用于创建BigDecimal对象,包括把所有的基本数值类型变量转换成一个BigDecimal对象,包括利用数字字符串、数字字符数组来创建BigDecimal对象。
不推荐使用BigDecimal(double val);
构造器来创建对象,而是BigDecimal(String val);
或BigDecimal.valueOf(double value);
静态方法来创建BigDecimal对象。
BigDecimal类提供了add()
、subtract()
、multiply()
、divide()
、pow()
等方法对精确浮点数进行常规算术运算。
日期、时间类
Date类
Java提供了Date
类来处理日期、时间,Date对象既包含日期,也包含时间。
Date类从JDK1.0起就开始存在了,但正因为它历史悠久,所以它的大部分构造器、方法都已经过时,不在推荐使用了。
Date类提供了6个构造器,其中4个已经Deprecated
(Java不在推荐使用,使用不再推荐的构造器时编译会提出警告信息,并导致程序性能、安全性能等方面的问题),剩下的两个构造器:
Date()
:生成一个代表当前日期时间的Date对象。该构造器在底层调用System.currentMillis()
获得long
整数作为日期参数。Date(long date)
:根据指定的long
型整数来生成一个Date对象。该构造器的参数表示创建的Date对象和GMT1970年1月1日00:00:00之间的时间差,以毫秒作为计时单位。
Date对象的大部分方法也Deprecated
了,剩下为数不多的几个方法:
boolean after(Date when)
:测试该日期是否在指定日期when之后。boolean before(Date when)
:测试该日期是否在指定日期when之前。long getTime()
:返回该时间对应的long型整数,即从GMT1970-01-01 00:00:00到该Date对象之间的时间差,以毫秒作为计时单位。void setTime(long time)
:设置Date对象的时间。
总体来说,Date是一个设计相当糟糕的类,Java官方推荐尽量少用Date的构造器和方法。
Calendar类
由于Date
类在设计上存在一些缺陷,所以Java提供了Calendar
类来更好地处理日期和时间。
Calendar
类本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法;但它本身不能直接实例化,程序只能创建Calendar
子类的实例,Java本身提供了一个GregorianCalendar
类,一个代表格里高利日历的子类,它代表了通常所说的公历。
Calendar
类是一个抽象类,所以不能使用构造器来创建Calendar对象。但它提供了几个静态getInstance()
方法来获取Calendar
对象,这些方法根据TimeZone
、Locale
类来获取特定的Calendar
,如果不指定TimeZone
、Locale
,则使用默认的TimeZone
、Locale
来创建Calendar
。
Calendar
和Date
都是表示日期的工具类,他们直接可以自由转换。
Calendar类提供了大量访问、修改日期时间的方法:
void add(int field, int amount)
:根据日历的规则,为给定的日历字段添加或减去指定的时间量。int get(int field)
:返回指定日历字段的值。int getActualMaximum(int field)
:返回指定日历字段可能拥有的最大值。int getActualMinimum(int field)
:返回指定日历字段可能拥有的最小值。void set(int field, int value)
:为给定的日历字段设置为给定值。void set(int year, int month, int date)
:设置Calendar对象的年、月、日三个字段的值。void set(int year, int month, int date, int hourOfDay, int minute, int second)
:设置Calendar对象的年、月、日、时、分、秒6个字段的值。
上面的很多方法都需要一个int
类型的field
参数,field
是Cakendar
类的类变量,如Calendar.YEAR
、Calendar.MONTH
等分别代表了年、月、日、小时、分钟、秒等时间字段。
Calendar.MONTH
字段代表月份,月份的起始值不是1,而是0。
Calendar类的注意点:
add
与roll
的区别add(int field, int amount)
的功能非常强大,add
主要用于改变Calendar
的特定字段的值。有两条规则:- 当被修改的字段超出它允许的范围时,会发生进位,即上一级字段也会增大。
- 如果下一级字段也需要改变,那么该字段会修正到变化最小的值。
roll()
的规则与add()
的处理规则不同:当被修改的字段超出它允许的范围时,上一级字段不会增大;下一级字段的处理规则与add()
相似。
- 设置
Calendar
的容错性- Calendar有两种解释日历字段的模式:
lenient
模式和non-lenient
模式。当处于lenient
模式时,每个时间字段可接受超过它允许范围的值;当处于non-lenient
模式时,如果为某个时间字段设置的值超出了它允许的取值范围,程序将会抛出异常。
- Calendar有两种解释日历字段的模式:
set()
方法延迟修改set(f, value)
方法将日历字段f
更改为value
,此处它还设置了一个内部成员变量,以指示日历字段f
已经被更改。尽管日历字段f
是立即更改的,但该Calendar
所代表的时间不会立即修改,直到下次调用get()
、getTime()
、getTimeInMillis()
、add()
或roll()
时才会重新计算日历的时间。
Java8新增的日期、时间包
Java8新增了一个java.time包,该包包含如下常用类:
Clock
:该类用于获取指定时区的当前日期、时间。该类可取代System类的currentTimeMillis()方法,而且提供了更多方法来获取当前日期、时间。该类提供了大量静态方法来获取Clock
对象。Duration
:该类代表持续时间。该类可以非常方便地获取一段时间。Instant
:代表一个具体的时刻,可以精确到纳秒。该类提供了静态的now()
方法来获取当前时刻,也提供了静态的now(Clock clock)
方法来获取clock
对应的时刻。除此之外,它还提供了一系列minusXxx()
方法在当前时刻基础上减去一段时间,也提供了plusXxx()
方法在当前时刻基础上加上一段时间。LocalDate
:该类代表不带时区的日期,例如1999-10-30。该类提供了静态的now()
方法来获取当前日期,也提供了静态的now(Clock clock)
方法来获取当前clock
对应的日期。除此之外,它还提供了一系列minusXxx()
方法在当前年份基础上减去几年、几月、几周或几日,也提供了plusXxx()
方法在当前年份基础上加上几年、几月、几周或几日。LocalTime
:该类代表不带时区的时间,例如10:30:13。该类提供了静态的now()
方法来获取当前时间,也提供了静态的now(Clock clock)
方法来获取clock
对应的时间。除此之外,它还提供了一系列minusXxx()
方法在当前年份基础上减去几小时、几分、几秒等,也提供了plusXxx()
方法在当前年份基础上加上加几小时、几分、几秒等。LocalDateTime
:该类代表不带时区的日期、时间,例如1999-10-30T10:30:13。该类提供了静态的now()
方法来获取当前日期、时间,也提供了静态的now(Clock clock)
方法来获取clock
对应的日期、时间。除此之外,它还提供了一系列minusXxx()
方法在当前年份基础上减去几年、几月、几日几小时、几分、几秒等,也提供了plusXxx()
方法在当前年份基础上加上几年、几月、几日几小时、几分、几秒等。MonthDay
:该类仅代表月日,例如–10-30。该类提供了静态的now()
方法来获取当前月日,也提供了静态的now(Clock clock)
方法来获取clock
对应的月日。Year
:该类仅代表年,例如1999。该类提供了静态的now()
方法来获取当前年份,也提供了静态的now(Clock clock)
方法来获取clock
对应的年份。除此之外,它还提供了minusYears()
方法在当前年份基础上减去几年,也提供了plusYear()
方法在当前年份基础上加上几年。YearMonth
:该类仅代表年月,例如1999-10。该类提供了静态的now()
方法来获取当前年月,也提供了静态的now(Clock clock)
方法来获取clock
对应的年月。除此之外,它还提供了minusXxx()
方法在当前年月基础上减去几年、几月,也提供了plusXxx()
方法在当前年月基础上加上几年、几月。ZonedDateTime
:该类代表一个时区化的日期、时间。ZoneId
:该类代表一个时区。DayOfWeek
:这是一个枚举类,定义了周日到周六的枚举值。Month
:这是一个枚举类,定义了一月到十二月的枚举值。
正则表达式
正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。
String
类里也提供了如下几个特殊方法:
boolean matches(String regex)
:判断该字符串是否匹配指定的正则表达式。String replaceAll(String regex, String replacement)
:将该字符串中所有匹配regex
的字串替换成replacement
。String repalceFirst(String regex, String replacement)
:将该字符串中第一个匹配regex
的字串替换成replacement
。String[] split(String regex)
:以regex
作为分隔符,把该字符串分割成多个字串。
上面这些特殊的方法都依赖于Java提供的正则表达式支持,除此之外,Java还提供了Pattern
和Matches
两个类专门用于提供正则表达式支持。
创建正则表达式
正则表达式所支持的合法字符:
x
:字符x(x可代表任何合法的字符)