-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathpackage.md
More file actions
298 lines (200 loc) · 9.1 KB
/
package.md
File metadata and controls
298 lines (200 loc) · 9.1 KB
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
---
title: 教妹学 Java:package 包
shortTitle: Java中的包
description: Java中的包是一种用于组织和管理代码的机制,可以帮助开发者更有效地处理复杂的项目。本文将详细讲解Java包的概念、创建、导入以及使用方法,以及如何通过包提高代码可读性和模块化。掌握Java包的使用技巧,为更高级的Java编程打下坚实基础。
category:
- Java 核心
tag:
- 面向对象编程
head:
- - meta
- name: keywords
content: Java,Java编程, 包, 代码组织, 代码管理, 包创建, 包导入,包,import,package
---
“三妹,这一节,我们简单过一下 Java 中的包,也就是 package,这个一点就透,很好掌握。”我放下手中的雪碧,翻开笔记本,登上 GitHub,点开《二哥的 Java 进阶之路》,找到这篇「Java 中的包」,开始滔滔不绝起来。
“二哥,你等一下。”让我打开思维导图做一下笔记📒。
### 关于包
在前面的代码中,我们把类和接口命名为`Person`、`Student`、`Hello`等简单的名字。
在团队开发中,如果小明写了一个`Person`类,小红也写了一个`Person`类,现在,小白既想用小明的`Person`,也想用小红的`Person`,怎么办?
如果小军写了一个`Arrays`类,恰好 JDK 也自带了一个`Arrays`类,如何解决类名冲突?
在 Java 中,我们使用`package`来解决名字冲突。
Java 定义了一种名字空间,称之为包:`package`。一个类总是属于某个包,类名(比如`Person`)只是一个简写,真正的完整类名是`包名.类名`。
例如:
小明的`Person`类存放在包`ming`下面,因此,完整类名是`ming.Person`;
小红的`Person`类存放在包`hong`下面,因此,完整类名是`hong.Person`;
小军的`Arrays`类存放在包`mr.jun`下面,因此,完整类名是`mr.jun.Arrays`;
JDK 的`Arrays`类存放在包`java.util`下面,因此,完整类名是`java.util.Arrays`。
在定义`class`的时候,我们需要在第一行声明这个`class`属于哪个包。
小明的`Person.java`文件:
```java
package ming; // 申明包名ming
public class Person {
}
```
小军的`Arrays.java`文件:
```java
package mr.jun; // 申明包名mr.jun
public class Arrays {
}
```
在 Java 虚拟机执行的时候,JVM 只看完整类名,因此,只要包名不同,类就不同。
包可以是多层结构,用`.`隔开。例如:`java.util`。
>要特别注意:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。
没有定义包名的`class`,它使用的是默认包,非常容易引起名字冲突,因此,不推荐不写包名的做法。
我们还需要按照包结构把上面的 Java 文件组织起来。假设以`package_sample`作为根目录,`src`作为源码目录,那么所有文件结构就是:
```ascii
package_sample
└─ src
├─ hong
│ └─ Person.java
│ ming
│ └─ Person.java
└─ mr
└─ jun
└─ Arrays.java
```
即所有 Java 文件对应的目录层次要和包的层次一致。
编译后的`.class`文件也需要按照包结构存放。如果使用 IDE,把编译后的`.class`文件放到`bin`目录下,那么,编译的文件结构就是:
```ascii
package_sample
└─ bin
├─ hong
│ └─ Person.class
│ ming
│ └─ Person.class
└─ mr
└─ jun
└─ Arrays.class
```
编译的命令相对比较复杂,我们需要在`src`目录下执行`javac`命令:
```
javac -d ../bin ming/Person.java hong/Person.java mr/jun/Arrays.java
```
在 IDE 中,会自动根据包结构编译所有 Java 源码,所以不必担心使用命令行编译的复杂命令。
### 包的作用域
位于同一个包的类,可以访问包作用域的字段和方法。
不用`public`、`protected`、`private`修饰的字段和方法就是包作用域。例如,`Person`类定义在`hello`包下面:
```java
package hello;
public class Person {
// 包作用域:
void hello() {
System.out.println("Hello!");
}
}
```
`Main`类也定义在`hello`包下面,就可以直接访问 Person 类:
```java
package hello;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.hello(); // 可以调用,因为Main和Person在同一个包
}
}
```
### 导入包
在一个`class`中,我们总会引用其他的`class`。例如,小明的`ming.Person`类,如果要引用小军的`mr.jun.Arrays`类,他有三种写法:
第一种,直接写出完整类名,例如:
```java
// Person.java
package ming;
public class Person {
public void run() {
mr.jun.Arrays arrays = new mr.jun.Arrays();
}
}
```
很显然,每次都要写完整的类名比较痛苦。
因此,第二种写法是用`import`语句,导入小军的`Arrays`,然后写简单类名:
```java
// Person.java
package ming;
// 导入完整类名:
import mr.jun.Arrays;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
```
在写`import`的时候,可以使用`*`,表示把这个包下面的所有`class`都导入进来(但不包括子包的`class`):
```java
// Person.java
package ming;
// 导入mr.jun包的所有class:
import mr.jun.*;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
```
我们一般不推荐这种写法,因为在导入了多个包后,很难看出`Arrays`类属于哪个包。
还有一种`import static`的语法,它可以导入一个类的静态字段和静态方法:
```java
package main;
// 导入System类的所有静态字段和静态方法:
import static java.lang.System.*;
public class Main {
public static void main(String[] args) {
// 相当于调用System.out.println(…)
out.println("Hello, world!");
}
}
```
`import static`很少使用。
Java 编译器最终编译出的`.class`文件只使用 *完整类名*,因此,在代码中,当编译器遇到一个`class`名称时:
- 如果是完整类名,就直接根据完整类名查找这个`class`;
- 如果是简单类名,按下面的顺序依次查找:
- 查找当前`package`是否存在这个`class`;
- 查找`import`的包是否包含这个`class`;
- 查找`java.lang`包是否包含这个`class`。
如果按照上面的规则还无法确定类名,则编译报错。
我们来看一个例子:
```java
// Main.java
package test;
import java.text.Format;
public class Main {
public static void main(String[] args) {
java.util.List list; // ok,使用完整类名 -> java.util.List
Format format = null; // ok,使用import的类 -> java.text.Format
String s = "hi"; // ok,使用java.lang包的String -> java.lang.String
System.out.println(s); // ok,使用java.lang包的System -> java.lang.System
MessageFormat mf = null; // 编译错误:无法找到MessageFormat: MessageFormat cannot be resolved to a type
}
}
```
因此,编写 class 的时候,编译器会自动帮我们做两个 import 动作:
- 默认自动`import`当前`package`的其他`class`;
- 默认自动`import java.lang.*`。
>注意:自动导入的是java.lang包,但类似java.lang.reflect这些包仍需要手动导入。
如果有两个`class`名称相同,例如,`mr.jun.Arrays`和`java.util.Arrays`,那么只能`import`其中一个,另一个必须写完整类名。
### 包的最佳实践
为了避免名字冲突,我们需要确定唯一的包名。推荐的做法是使用倒置的域名来确保唯一性。例如:
- org.apache
- org.apache.commons.log
- com.tobebetterjavaer.sample
子包就可以根据功能自行命名。
要注意不要和`java.lang`包的类重名,即自己的类不要使用这些名字:
- String
- System
- Runtime
- ...
要注意也不要和 JDK 常用类重名:
- java.util.List
- java.text.Format
- java.math.BigInteger
- ...
### 小结
Java 内建的`package`机制是为了避免`class`命名冲突;
JDK 的核心类使用`java.lang`包,编译器会自动导入;
JDK 的其它常用类定义在`java.util.*`,`java.math.*`,`java.text.*`,……;
包名推荐使用倒置的域名,例如`org.apache`。
---
> 参考链接:[https://www.liaoxuefeng.com/wiki/1252599548343744/1260467032946976](https://www.liaoxuefeng.com/wiki/1252599548343744/1260467032946976),整理:沉默王二
----
GitHub 上标星 10000+ 的开源知识库《[二哥的 Java 进阶之路](https://github.com/itwanger/toBeBetterJavaer)》第一版 PDF 终于来了!包括Java基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:[太赞了,GitHub 上标星 10000+ 的 Java 教程](https://javabetter.cn/overview/)
微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **222** 即可免费领取。
