7.1.2 使用Scanner获取键盘输入

使用Scanner类可以很方便地获取用户的键盘输入, Scanner是一个基于正则表达式的文本扫描器,它可以从文件输入流字符串中解析出基本类型值和字符串值。
Scanner类提供了多个构造器,不同的构造器可以接收文件、输入流、字符串作为数据源,用于从文件、输入流、字符串中解析数据。

Scanner主要方法

Scanner主要提供了两个方法来扫描输入。

方法 描述
hasNextXxx() 是否还有下一个输入项,其中Xxx可以是intLong等代表基本数据类型的字符串。如果只是判断是否包含下一个字符串,则直接使用hasNext()
nextXxx() 获取下一个输入项。

Scanner分隔符

在默认情况下, Scanner使用空白(包括空格Tab键、回车)作为多个输入项之间的分隔符。

Scanner的读取操作可能被阻塞来等待信息的输入。如果输入源没有结束,Scanner又读不到更多输入项时(尤其在键盘输入时比较常见), ScannerhasNext()next()方法都有可能阻塞, hasNext()方法是否阻塞与和其相关的next()方法是否阻塞无关。

逐行读取方法

Scanner提供了两个简单的方法来逐行读取。

方法 描述
boolean hasNextLine() 判断输入源中是否还有下一行。
String nextLine() 返回输入源中下一行的字符串。

Scanner获取基本类型的输入项。

读取文件输入

Scanner不仅能读取用户的键盘输入,还可以读取文件输入。只要在创建Scanner对象时传入一个File对象作为参数,就可以让读取该文件的内容。

7.1 与用户互动

绝大部分程序都需要处理用户动作,包括接收用户的键盘输入、鼠标动作等。因为现在还未涉及图形用户接口(GUI)编程,故本节主要介绍程序如何获得用户的键盘输入

7.1.1 运行Java程序的参数

main()方法的方法签名

public static void main(String[] args){ }

main方法修饰符详解

下面详细讲解main()方法为什么采用这个方法签名。

  1. public修饰符:Java类由JVM调用,为了让JVM可以自由调用这个main()方法,所以需要使用public修饰符把这个方法暴露出来。
  2. static修饰符:JVM直接通过该类来调用主方法,因此使用static修饰该主方法。
  3. void返回值:因为主方法被JVM调用,该方法的返回值将返回给JVM,不会返回给当前类,因此main()方法没有返回值。

main方法的形参由JVM赋值

根据方法调用的规则:谁调用方法,谁负责为形参赋值也就是说, main()方法由JVM调用,即main方法的字符串数组形参args应该由JVM负责赋值。

JVM根据命令行参数给main方法的字符串形参赋值

  • 如果没有运行程序是没有给出命令行参数,则main方法的字符串数组形参的长度为0是个空数组.
  • 命令行参数以空格作为参数的分隔符
    • 如果某个参数本身有空格,则需要用双引号将这个参数包裹起来.
    • 否则JVM会把这个空格当成参数分隔符.

第7章 Java基础类库

本章要点

  • Java程序的参数
  • 程序运行过程中接收用户输入
  • System类相关用法
  • RuntimeProcessHandle类的相关用法
  • ObjectObjects
  • 使用StringStringBufferStringBuilder
  • 使用Math类进行数学计算
  • 使用BigDecimal保存精确浮点数
  • 使用Random类生成各种伪随机数
  • DateCalendar的用法及之间的联系
  • Java8新增的日期、时间API的功能和用法
  • 创建正则表达式
  • 通过PatternMatcher使用正则表达式
  • 通过String类使用正则表达式
  • 程序国际化的思路程序国际化
  • 程序国际化
  • Java9新增的日志API
  • 使用NumberFormat格式化数字
  • 使用DateTimeFormatter解析日期、时间字符串
  • 使用DateTime Formatter格式化日期、时间
  • 使用DateFormatSimpleDateFormat格式化日期

字符串处理

Java提供了StringString BufferStringbuilder来处理字符串,它们之间存在少许差别,本章会详细介绍它们之间的差别,以及如何选择合适的字符串类。

日期时间处理

Java还提供了DateCalendar来处理日期时间,其中Date是一个已经过时的API,通常推荐使用Calendar来处理日期、时间。

正则表达式

正则表达式是一个强大的文本处理工具,通过正则表达式可以对文本内容进行查找、替换、分割等操作。从JDK14以后,Java也增加了对正则表达式的支持,包括新增的PatternMatcher两个类,并改写了String类,让String类增加了正则表达式支持,增加了正则表达式功能后的String类更加强大。

国际化

Java还提供了非常简单的国际化支持,Java使用Locale对象封装一个国家、语言环境,再使用ResourceBundle根据Locale加载语言资源包,当ResourceBundle加载了指定Locale对应的语言资源文件后, ResourceBundle对象就可调用getString()方法来取出指定key所对应的消息字符串。

6.13 本章小结

本章主要介绍了Java面向对象的深入部分,包括Java里8个基本类型的包装类,以及系统直接输出一个对象时的处理方式,比较了对象相等时所用的==equals方法的区别。本章详细介绍了使用fnal修饰符修饰变量、方法和类的用法,讲解了抽象类和接口的用法,并深入比较了接口和抽象类之间的联系和区别,以便读者能掌握接口和抽象类在用法上的区别。
本章还介绍了内部类的概念和用法,包括静态内部类非静态内部类局部内部类匿名内部类等,并深入讲解了内部类的作用。枚举类是Java新提供的一个功能,这也是本章讲解的知识点,本章详细讲解了如何手动定义枚举类,以及通过enum来定义枚举类的各种相关知识。本章还重点介绍了Java8新增的Lambda表达式,包括Lambda表达式的用法和本质,以及如何在Lambda表达式中使用方法引用构造器引用
本章最后介绍了对象的几种引用方式,以及系统垃圾回收的各种相关知识,还总结了Java所有修饰符的适用总表.

6.12.3 关于JAR包的技巧

JAR文件实际上就是ZIP文件,所以可以使用一些常见的解压缩工具来解压缩JAR文件,如Windows下的WinRARWinZip等,以及Linux下的unzip等。使用WinRARWinZip等工具比使用JAR命令更加直观、方便;而使用unzip则可通过d选项来指定目标目录。

解压缩一个JAR文件时不能使用jar-C选项来指定解压的目标目录,因为-C选项只在创建或者更新包时可用。

jar命令只能解压到当前目录下

如果需要将文件解压缩到指定目录下,则需要先将该JAR文件拷贝到目标目录下,再使用jar命令进行解压缩

Linux中使用unzip解压jar包到指定目录

如果使用unzip,只需要指定一个-d选项即可指定解压目录。例如:
unzip test.jar -d dest/

Windows中通过压缩工具手动创建jar包

如果不喜欢jar命令的字符界面,也可以使用WinRAR工具来创建JAR包。因为WinRAR工具创建压缩文件时不会自动添加清单文件,所以需要手动添加清单文件,即需要手动建立META-INF路径,并在该路径下建立一个MANIFEST.MF文件,该文件中至少需要如下两行:

1
2
3
4
Manifest-Version: 1.0
Created-By: 9 (Oracle Corporation)
Main-Class: test.Test

上面的MANIFEST.MF文件是一个格式敏感的文件,该文件的格式要求与前面自定义清单的格式要求完全一样。
接下来选中需要被压缩的文件、文件夹和META-INF文件夹,单击右键弹出右键菜单,单击”添加到压缩文件(A)”,
然后选择压缩成ZIP格式,并输入压缩后的文件名Test.jar,然后单击”确定”按钮,即可生成一个JAR包,与使用jar命令生成的JAR包没有区别。

java中的其他压缩包

除此之外,Java还可能生成两种压缩包:WAR包和EAR包。其中WAR文件是Web Archive File,它对应一个Web应用文档;而EAR文件就是Enterprise Archive File,它对应于一个企业应用文档(通常由Web应用和EJB两个部分组成)。实际上,WAR包和EAR包的压缩格式及压缩方式与JAR包完全一样,只是改变了文件后缀而已。

6.12.2 创建可执行的JAR包

当一个应用程序开发成功后,大致有如下三种发布方式

1. 编译成平台相关的可执行性文件

使用平台相关的编译器将整个应用编译成平台相关的可执行性文件。
这种方式常常需要第三方编译器的支持,而且编译生成的可执行性文件丧失了跨平台特性,甚至可能有一定的性能下降。

2. 为应用编辑一个批处理文件

Windows操作系统为例,批处理文件中只需要定义如下命令:java package.MainClass
当用户单击上面的批处理文件时,系统将执行批处理文件的java命令,从而运行程序的主类。

运行Java程序时不带CMD控制台

如果不想保留运行Java程序的命令行窗口,也可在批处理文件中定义如下命令:
start javaw package.MainClass

3. 做成可执行JAR包

把应用程序压缩成JAR包来发布是比较典型的做法,如果开发者把整个应用制作成一个可执行的JAR包交给用户,那么用户使用起来就方便了。在Windows下安装JRE时,安装文件会将*.jar文件映射成由javaw.exe打开。对于一个可执行的JAR包,用户只需要双击它就可以运行程序了,

下面介绍如何制作可执行的JAR包。

创建可执行JAR包的关键

创建可执行的JAR包的关键在于:让javaw命令知道JAR包中哪个类是主类, 这样javaw命令可以通过运行该主类来运行程序

创建JAR包时通过jar命令的e选项指定主类

jar命令有一个-e选项,该选项指定JAR包中作为程序入口的主类的类名。因此,制作一个可执行的JAR包只要增加-e选项即可。例如如下命令:

jar cvfe test.jar test.Test test
上面命令把test目录下的所有文件都压缩到test.jar包中,并指定使用test.Test类作为程序的入口.

运行jar包的方法

运行上面的JAR包有两种方式。

  • 使用java命令,使用java运行时的语法是:java -jar test.jar
  • 使用javaw命令,使用javaw运行时的语法是:javaw test.jar

当创建JAR包时,所有的类都必须放在与包结构对应的目录结构中,就像上面-e选项指定的Test类,表明入口类为Test因此,必须在JAR包下包含Test.class文件。

实例

下面来演示如何将下面的java文件打包成可执行jar包:

目录结构

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\打包成可执行jar
└─Test.java

Test.java

这里测试的java源码如下:

1
2
3
4
5
6
7
8
9
package test;

public class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}

带包编译 字节码文件生成在当前路径下

使用命令:javac -d . Test.java编译java源文件,指定在当前路径下生成.class文件。

编译后的目录结构

1
2
3
4
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\打包成可执行jar
├─test\
│ └─Test.class
└─Test.java

打包成jar包时指定主类

使用命令:jar -cvfe Test.jar test.Test ./test将编译后的.class文件打包到jar包中

1
2
3
4
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\打包成可执行jar>jar -cvfe Test.jar test.Test ./test
已添加清单
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 290)(压缩了 30%)

命令解释

  • -c表示要创建一个JAR
  • -v表示输出创建JAR包时的具体信息
  • -f对应后面的第1个参数:Test.jar,表示要打包到Test.jar
  • -e对应后面的第2个参数test.Test,表示程序的主类
  • 最后的./test表示存放字节码文件的目录,也就是上面javac生成的目录

查看打包后的JAR包结构是否正确

1
2
3
4
5
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\打包成可执行jar>jar -tf Test.jar
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class

注意.class文件要放在正确的包下,如果Test.class没有放在test包下,则说明上述打包有问题.

运行jar包

使用命令:java -jar Test.jar即可运行这个可执行jar包。

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\打包成可执行jar>java -jar Test.jar
Hello World!

6.12.1 jar命令详解

jar是随JDK自动安装的,在JDK安装目录下的bin目录中,Windows下文件名为jar.exe, Linux下文件名为jar

查看jar帮助文档

在CMD中输入jar,可以看到jar命令的帮助文档.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
C:\Users\lan>jar
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
-c 创建新档案
-t 列出档案目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有档案
-i 为指定的 jar 文件生成索引信息

-v 在标准输出中生成详细输出
-f 指定档案文件名
-m 包含指定清单文件中的清单信息
-n 创建新档案后执行 Pack200 规范化
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不创建条目的清单文件
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点

-C 更改为指定的目录并包含以下文件
如果任何文件为目录, 则对其进行递归处理。
清单文件名, 档案文件名和入口点名称的指定顺序与 'm', 'f' 和 'e' 标记的指定顺序相同。

示例 1: 将两个类文件归档到一个名为 classes.jar 的档案中:
jar cvf classes.jar Foo.class Bar.class
示例 2: 使用现有的清单文件 'mymanifest' 并
foo/ 目录中的所有文件归档到 'classes.jar' 中:
jar cvfm classes.jar mymanifest -C foo/ .

1. 创建JAR文件

命令:jar cf test.jar -C dist/ .

1
2
3
4
-c  创建新档案
-f 指定档案文件名

-C 更改为指定的目录并包含以下文件

将当前路径下的dist路径下的全部内容生成一个test.jar文件。如果当前目录中已经存在test.jar文件,那么该test.jar文件将被覆盖。

2. 创建JAR文件 并显示压缩过程

命令:jar cvf test.jar -C dist/ .

1
2
3
4
5
-c  创建新档案
-v 在标准输出中生成详细输出
-f 指定档案文件名

-C 更改为指定的目录并包含以下文件
1
2
3
4
5
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvf test.jar -C dist/ .
已添加清单
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 421) (输出 = 320)(压缩了 23%)

3. 不使用清单文件

命令:jar cvfM test.jar -C dist/ .

1
2
3
4
5
6
-c  创建新档案
-v 在标准输出中生成详细输出
-f 指定档案文件名
-M 不创建条目的清单文件

-C 更改为指定的目录并包含以下文件
1
2
3
4
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvfM test.jar  -C dist/ .
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 130) (输出 = 118)(压缩了 9%)

该命令的结果与第2个命令类似,其中M选项表明不生成清单文件。因此生成的test.jar中没有包含清单文件(META-INF/MANIFEST.MF),打包过程的信息也略有差别。

4. 自定义清单文件内容

命令格式:jar cvfm JAR保存路径 清单文件路径 -C 目录 文件
运行结果与第2个命令相似,显示信息也相同,其中小写的m选项用于指定读取用户清单文件信息。因此在生成的JAR包中清单文件META-INF/MANIFEST.MF的内容有所不同,它会在原有清单文件基础上增加MANIFEST.MF文件的内容。

当开发者向MANIFEST.MF清单文件中增加自己的内容时,就需要借助于自己的清单文件了,清单文件只是一个普通的文本文件,使用记事本编辑即可。清单文件的内容由如下格式的多个key-value对组成。格式如下:
key:空格value

清单文件的内容格式

  1. 每行只能定义一个key-value对,每行的key-value对之前不能有空格,即key-value对必须顶格写。
  2. 每组key-value对之间以英文冒号后紧跟一个英文空格分隔,少写了冒号或者空格都是错误的.
  3. 文件开头不能有空行。
  4. 文件必须以一个空行结束。

可以将上面文件保存在任意位置,以任意文件名存放。例如将上面文件保存在当前路径下,文件名为a.txt。使用如下命令即可将清单文件中的key-value对提取到META- INF/MANIFEST.MF文件中。
jar cvfm test.jar a.txt -C dist/ .

实例

目录结构

1
2
3
4
5
6
7
8
9
10
11
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12
├─a.txt
├─dist\
│ └─test\
│ ├─Test.class
│ └─Test.java
├─dist7\
│ └─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

a.txt文件内容:

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>type a.txt
Hello: HelloWorld

a.txt中的内容添加到清单文件中:

1
2
3
4
5
6
7
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar cvfm test.jar a.txt -C dist/ .
已添加清单
正在添加: test/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: test/Test.class(输入 = 419) (输出 = 291)(压缩了 30%)
正在添加: test/Test.java(输入 = 130) (输出 = 118)(压缩了 9%)

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>

生成的清单文件内容:

1
2
3
Manifest-Version: 1.0
Hello: HelloWorld
Created-By: 1.8.0_131 (Oracle Corporation)

5. 查看JAR包内容

命令:jar tf test.jar

1
2
-t  列出档案目录
-f 指定档案文件名
1
2
3
4
5
6
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tf test.jar
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class
test/Test.java

JAR包中的文件路径和文件非常多时,因为命令行窗口能显示的行数有限,所以直接执行该命令,可能无法看到包的全部内容,此时可利用重定向将显示结果保存到文件中。例如,采用如下命令:jar tf test.jar > test.txt

1
2
3
4
5
6
7
8
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tf test.jar > test.txt

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>type test.txt
META-INF/
META-INF/MANIFEST.MF
test/
test/Test.class
test/Test.java

6. 查看JAR包详细内容

命令:jar tvf test.jar

1
2
3
4
5
6
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>jar tvf test.jar
0 Sun Sep 29 16:36:50 CST 2019 META-INF/
88 Sun Sep 29 16:36:50 CST 2019 META-INF/MANIFEST.MF
0 Sat Sep 28 23:11:18 CST 2019 test/
419 Sat Sep 28 23:11:18 CST 2019 test/Test.class
130 Sat Sep 28 23:10:28 CST 2019 test/Test.java

7. 解压缩

命令:jar xf test.jar,这个命令会解压到当前目录下。

1
2
-x  从档案中提取指定的 (或所有) 文件
-f 指定档案文件名

示例

jar xf JAR包默认解压在当前路径下,为了观察明显,先把test.jar复制到其他地方.

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>copy test.jar Copy
已复制 1 个文件。

然后再解压

1
2
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12>cd Copy
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>jar xf test.jar

解压后的效果如下:

1
2
3
4
5
6
7
8
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>mytree f
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy
├─META-INF\
│ └─MANIFEST.MF
├─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

8. 带提示信息解压缩

命令:jar xvf test.jar
这个命令的解压缩效果与第7个命令相同,但系统会显示解压过程的详细信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>jar xvf test.jar
已创建: META-INF/
已解压: META-INF/MANIFEST.MF
已创建: test/
已解压: test/Test.class
已解压: test/Test.java

G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy>mytree f
G:\Desktop\随书源码\疯狂Java讲义(第4版)光盘\codes\06\6.12\Copy
├─META-INF\
│ └─MANIFEST.MF
├─test\
│ ├─Test.class
│ └─Test.java
└─test.jar

9. 更新JAR文件

命令:jar uf test.jar Hello.class,这个命令会更新test.jar中的Hello.class文件。如果test.jar中已有Hello.class件,则使用新的Hello.class文件替换原来的Hello.class文件;如果test.jar中没有Helo.class文件,则把新的Hello.class文件添加到test.jar文件中。

10.更新时显示详细信息

命令:jar uvf test.jar Hello.class

1.11 创建多版本JAR包

多版本JAR包是JDK9新增的功能,它允许在同一个JAR包中包含针对多个Java版本的cass文件。JDK9jar命令增加了一个 --release选项,用于创建多版本JAR包,注意,只有Java9之后才支持多版本JAR包。

如何使用指定版本的Java进行编译

在使用多版本JAR包之前,可以使用Javac--release选项针对指定Java版本进行编译。比如命令:
javac --release 7 Test java
上面命令代表使用Java7的语法来编译Test java。如果你的Test java中使用了Java8Java9的语法,程序将会编译失败。

如果创建多版本JAR包

假如将针对Java7编译的所有class文件放在dist7目录下,针对Java9编译的所有class文件放在dist目录下。接下来可用如下命令来创建多版本JAR包:
jar cvf test.jar -C dist7/ . --release 9 -C dist/ .

特定版本在JAR包中的位置

这样就创建了一个多版本JAR包,在该多版本JAR包内,特定版本的文件位于META-INF/versions/N目录下,其中N代表版本号。

6.12 Java9的多版本JAR包

JAR文件的全称是Java Archive File,意思就是Java档案文件。通常JAR文件是一种压缩文件,与常见的ZIP压缩文件兼容,通常也被称为JAR包。

JAR文件和ZIP文件的区别

JAR文件与ZIP文件的区别就是在JAR文件中默认包含了一个名为META-INF/MANIFEST.MF的清单文件,这个清单文件是在生成JAR文件时由系统自动创建的。

将类文件打包成JAR包在其他地方使用

当开发了一个应用程序后,这个应用程序包含了很多类,如果需要把这个应用程序提供给别人使用,通常会将这些类文件打包成一个JAR文件,把这个JAR文件提供给别人使用。

Java虚拟机会自动解压JAR包

只要别人在系统的CLASSPATH环境变量中添加这个JAR文件,则Java虚拟机就可以自动在内存中解压这个JAR包,把这个JAR文件当成一个路径,在这个路径中查找所需要的类或包层次对应的路径结构。

使用JAR文件的优点

使用JAR文件有以下好处。

  1. 安全。能够对JAR文件进行数字签名,只让能够识别数字签名的用户使用里面的东西。
  2. 加快下载速度。在网上使用Applet时,如果存在多个文件而不打包,为了能够把每个文件都下载到客户端,需要为每个文件单独建立一个HTTP连接,这是非常耗时的工作。将这些文件压缩成一个JAR包,只要建立一次HTP连接就能够一次下载所有的文件
  3. 压缩。使文件变小,JAR的压缩机制和ZIP完全相同。
  4. 包封装。能够让JAR包里面的文件依赖于统一版本的类文件。
  5. 可移植性JAR包作为内嵌在Java平台内部处理的标准,能够在各种平台上直接使用。

把一个JAR文件添加到系统的CLASSPATH环境变量中后,Java会把JAR文件当成一个路径来处理。实际上JAR文件就是一个路径,JAR文件通常使用jar命令压缩而成,当使用jar命令压缩生成JAR文件时,可以把一个或多个路径全部压缩成一个JAR文件。

6.10 修饰符的适用范围

表6.3 Java修饰符适用范围总表

这里有一张图片
在表6.3中,包访问控制符是一个特殊的修饰符,不用任何访问控制符的就是包访问控制。
对于初始化块局部成员而言,它们不能使用任何访问控制符,所以看起来像是使用了包访问控制符。

strictfp关键字

strictfp关键字的含义是FP-strict,也就是精确浮点的意思。在Java虚拟机进行浮点运算时,如果没有指定strictfp关键字,Java的编译器和运行时环境在浮点运算上不一定令人满意。一旦使用了strictfp来饰类、接口或者方法时,那么在所修饰的范围内Java的编译器和运行时环境会完全依照浮点规范正IEEE-754来执行。因此,如果想让浮点运算更加精确,就可以使用strictfp关键字来修饰类、接口和方法

native关键字

native关键字主要用于修饰一个方法,使用native修饰的方法类似于一个抽象方法。与抽象方法不同的是, native方法通常采用C语言来实现。如果某个方法需要利用平台相关特性,或者访问系统硬件等,则可以使用native修饰该方法,再把该方法交给C语言去实现。一旦Java程序中包含了native方法,这个程序将失去跨平台的功能。

4个访问控制符只能出现其中之一

在表6.3列出的所有修饰符中,4个访问控制符是互斥的,最多只能出现其中之一。

不能和abstract同时使用的修饰符

不仅如此,还有abstractfinal永远不能同时使用;
abstractstatic不能同时修饰方法,可以同时修饰内部类;
abstractprivate不能同时修饰方法,可以同时修饰内部类
privatefinal同时修饰方法虽然语法是合法的,但没有太大的意义,由于private修饰的方法不可能被子类重写,因此使用final修饰没什么意义。

6.10.4 对象的软引用 弱引用和虚引用

对大部分对象而言,程序里会有一个引用变量引用该对象,这是最常见的引用方式。除此之外,java.lang.ref包下提供了3个类: SoftReferencePhantomReferenceWeakReference,它们分别代表了系统对对象的3种引用方式:软引用、虚引用和弱引用。因此,Java语言对对象的引用有如下4种方式。

1. 强引用(StrongReference)

这是Java程序中最常见的引用方式。程序创建一个对象,并把这个对象赋给一个引用变量,程序通过该引用变量来操作实际的对象,此时这引用变量就是强引用
前面介绍的对象和数组都采用了这种强引用的方式。当一个对象被一个或一个以上的引用变量所引用时,它处于可达状态,不可能被系统垃圾回收机制回收。

2. 软引用(SoftReference)

软引用需要通过SoftReference类来实现.
当一个对象只有软引用时,它有可能被垃圾回收机制回收。对于只有软引用的对象而言,

  • 当系统内存空间足够时,它不会被系统回收,程序也可使用该对象;
  • 当系统内存空间不足时,系统可能会回收它。

软引用通常用于对内存敏感的程序中。

3. 弱引用(WeakReference)

弱引用通过Weak Reference类实现。
弱引用和软引用很像,但弱引用的引用级别更低。对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存
当然,并不是说当一个对象只有弱引用时,它就会立即被回收。只有弱引用的对象必须等到系统垃圾回收机制运行时才会被回收。

4. 虚引用(PhantomReference)

虚引用通过PhantomReference类实现。
虚引用完全类似于没有引用。虚引用对 对象本身没有太大影响,对象甚至感觉不到虚引用的存在。如果一个对象只有一个虚引用时,那么它和没有引用的效果大致相同。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列(ReferenceQueue)联合使用。

如何获取被引用的对象

上面三个引用类都包含了一个get()方法,用于获取被它们所引用的对象。

引用队列

引用队列由java.lang.ref.ReferenceQueue类表示,它用于保存被回收后对象的引用

软引用和弱引用在回收之后被放入引用队列

当联合使用软引用弱引用引用队列时,系统在回收被引用的对象之后,将把被回收对象对应的引用添加到关联的引用队列中。

虚引用在对象是否之前被放入引用队列

与软引用和弱引用不同的是,虚引用在对象被释放之前,将把它对应的虚引用添加到它关联的引用队列中,这使得可以在对象被回收之前采取行动。

虚引用不能单独使用

软引用和弱引用可以单独使用,但虚引用不能单独使用,单独使用虚引用没有太大的意义。

虚引用主要用来跟踪对象是否即将被回收

虚引用的主要作用就是跟踪对象被垃圾回收的状态,程序可以通过检查与虚引用关联的引用队列中是否已经包含了该虚引用,从而了解虚引用所引用的对象是否即将被回收

这篇文章还没有读完,还有写例子没有看,我跑过去学习按键精灵了,现在没有心情继续看下去,先看下一篇,后面有空再来补上。