🐿️
type
status
date
slug
summary
tags
category
icon
password
Property
在现实中,如果小明写了一个
Person
类,小红也写了一个Person
类,现在,小白既想用小明的Person
,也想用小红的Person
,怎么办?如果小军写了一个
Arrays
类,恰好JDK也自带了一个Arrays
类,如何解决类名冲突?Java定义了一种名字空间,称之为包:
package
。一个类总是属于某个包,类名(比如Person
)只是一个简写,真正的完整类名是包名.类名
。例如:小明的
Person
类存放在包ming
下面,完整类名是ming.Person
;小军的Arrays
类存放在包mr.jun
下面,完整类名是mr.jun.Arrays
;JDK的Arrays
类存放在包java.util
下面,完整类名是java.util.Arrays
。在定义
class
的时候,需要在第一行声明这个class
属于哪个包,小明的Person.java
文件:小军的
Arrays.java
文件:🐿️
type
status
date
slug
summary
tags
category
icon
password
Property
Java的内部类可分为Inner Class、Anonymous Class和Static Nested Class三种:
- Inner Class和Anonymous Class本质上是相同的,都必须依附于Outer Class的实例,即隐含地持有
Outer.this
实例,并拥有Outer Class的private
访问权限;
- Static Nested Class是独立类,但拥有Outer Class的
private
访问权限。
Inner Class
如果一个类定义在另一个类的内部,这个类就是Inner Class:
上述定义的
Outer
是一个普通类,而Inner
是一个Inner Class,它与普通类有个最大的不同,就是Inner Class的实例不能单独存在,必须依附于一个Outer Class的实例。示例代码如下:要实例化一个
Inner
,必须首先创建一个Outer
的实例,然后,调用Outer
实例的new
来创建Inner
实例:🐿️
type
status
date
slug
summary
tags
category
icon
password
Property
classpath
什么是
classpath
?classpath
是JVM用到的一个环境变量,它用来指示JVM如何搜索class
。因为Java是编译型语言,源码文件是
.java
,而编译后的.class
文件才是真正可以被JVM执行的字节码。因此,JVM需要知道,如果要加载一个abc.xyz.Hello
的类,应该去哪搜索对应的Hello.class
文件。所以,
classpath
就是一组目录的集合,它设置的搜索路径与操作系统相关。例如,在Windows系统上,用;
分隔,带空格的目录用""
括起来,可能长这样:在Linux系统上,用
:
分隔,可能长这样:现在假设
classpath
是.;C:\work\project1\bin;C:\shared
,当JVM在加载abc.xyz.Hello
这个类时,会依次查找:🐿️
type
status
date
slug
summary
tags
category
icon
password
Property
从Java 9开始,JDK引入了模块(Module)
.class
文件是JVM看到的最小可执行文件,而一个大型程序需要编写很多Class,并生成一堆.class
文件,很不便于管理,所以jar
文件就是class
文件的容器。在Java 9之前,一个大型Java程序会生成自己的jar文件,同时引用依赖的第三方jar文件,而JVM自带的Java标准库,实际上也是以jar文件形式存放的,这个文件叫
rt.jar
,一共有60多M。如果是自己开发的程序,除了一个自己的
app.jar
以外,还需要一堆第三方的jar包,运行一个Java程序,一般来说,命令行写这样:如果漏写了某个运行时需要用到的jar,那么在运行期极有可能抛出
ClassNotFoundException
。所以,jar只是用于存放class的容器,它并不关心class之间的依赖。
从Java 9开始引入的模块,主要是为了解决“依赖”这个问题。如果
a.jar
必须依赖另一个b.jar
才能运行,那应该给a.jar
加点说明啥的,让程序在编译和运行的时候能自动定位到b.jar
,这种自带“依赖关系”的class容器就是模块。为了表明Java模块化的决心,从Java 9开始,原有的Java标准库已经由一个单一巨大的
rt.jar
分拆成了几十个模块,这些模块以.jmod
扩展名标识,可以在$JAVA_HOME/jmods
目录下找到它们:- java.base.jmod
🦔
type
status
date
slug
summary
tags
category
icon
password
Property
Java的数据类型分两种:
- 基本类型:
byte
,short
,int
,long
,boolean
,float
,double
,char
- 引用类型:所有
class
和interface
类型
引用类型可以赋值为
null
,表示空,但基本类型不能赋值为null
:如何把一个基本类型视为对象(引用类型)?
比如,想要把
int
基本类型变成一个引用类型,可以定义一个Integer
类,它只包含一个实例字段int
,这样,Integer
类就可以视为int
的包装类(Wrapper Class):🦔
type
status
date
slug
summary
tags
category
icon
password
Property
Java编译器对
String
做了特殊处理,可以直接用+
拼接字符串。虽然可以直接拼接字符串,但在循环中,每次循环都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。
为了能高效拼接字符串,Java标准库提供了
StringBuilder
,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder
中新增字符时,不会创建新的临时对象:StringBuilder
还可以进行链式操作:进行链式操作的关键是,定义的
append()
方法会返回this
,这样,就可以不断调用自身的其他方法。🦔
type
status
date
slug
summary
tags
category
icon
password
Property
使用
String
、Integer
等类型的时候,这些类型都是不变类,一个不变类具有以下特点:- 定义class时使用
final
,无法派生子类
- 每个字段使用
final
,保证创建实例后无法修改任何字段
假设希望定义一个
Point
类,有x
、y
两个变量,同时它是一个不变类,可以这么写:为了保证不变类的比较,还需要正确覆写
equals()
和hashCode()
方法,这样才能在集合类中正常使用,代码写起来很繁琐。record
从Java 14开始,引入了新的
Record
类。定义Record
类时,使用关键字record
。把上述Point
类改写为Record
类: