为了避免类在一起混乱,可以把类放在文件夹里。这时就需要用 package 语句告诉 java 这个类在哪个 package 里。package 语句要和源文件的目录完全对应,大小写要一致。(就像public class要和文件名一致)
package com.test
,但实际目录却为org.abc
,就会在 package com.test
下标记红线报错,但测试过(单一文件不涉及导入其他类的情况)并不影响编译运行。package com.test
,那么源代码就只应该放到com\test
下,而不是放到com\test\xxx
下都可以。如果想放到com\test\xxx
下,那么就package com.test.xxx
。一般来说,类都会在包里,而不会直接放在根目录(src
)下。
而且如果一个类(比如叫 TestClass)放到了默认的根目录(src)下,而没有放到一个包中,你想在别的包中的类里引用这个类(TestClass),你都无法import导入,也无法使用类的全限定名(因为没有包名)来引用这个类。(非得引用这个类,需要用到反射机制,这就很繁琐了,所以不要把问题复杂化,所有的类都应该放到某个包中)
src
|
|--- com.phone
|
|--- parts
com.phone
实际上是com\phone\
,只是 IDEA 做了优化,但实际上不是一个目录,而是两个(/层)目录。com
下面是phone
,phone
下面是 parts
。
这里假设的是所有代码文件都是带 package 语句,并且都放到了与package 语句描述相符的文件路径下。
当使用另一个包里的类时,需要带上包名。
java 的设定是,一个类只能发现和它在同一个目录下的类(即同一个包里的类,这种类不需要
import
导入,就可以直接用),并看不到它的上一层、下一层目录中的类(这种类需要导入,或者使用该类的全限定名来引用)。
但每次使用别的包里的类都写com.xxx.xxx.类名
,尤其是对同一个类还进行多次使用时,就很麻烦,所以可以在源代码上方(package语句下)加入 import 语句,把该类导入进来,之后在后面的代码中就可以直接使用该类名,就不用写前面那一段包的信息。(类名
)
一个 java 程序中,package 语句虽然只能有一个,但 import 语句可以有多个。
*
通配符。package com.test;
import com.test.person.*; // 导入 com.test.person 包下的所有类
import com.test.product.CPU; // 导入 com.test.product 包下的 CPU 类
CPU iPhoneCPU = new CPU();
如果 A 源文件中,使用了 package 语句,那么其他源文件要使用 A 中的类时,就要使用 import 语句(通过A中的 package语句中声明的包,定位到想要引用的类)来将需要的类导入。
经过实际试验:只要不加 package 语句,java 就认为这个类是放在 src 下的,不管这个类到底在哪一层文件夹中。而只有同样是在 src 下的类,才能直接引用对方而不需要导入。
并不是说其他包导入了 A 包中的 a 类,就能像 A 包一样地使用这个 a 类。这里还存在一些 “范围” 问题。
package com.test;
public class Person{
String name; // 缺省访问修饰符,就只能被同一个包中的类所访问,即便 Person类被导入到其他包中)
public String id;
public int age;
}
现在假设 B 包中一个 java 程序(类)导入了这个 com.test.Person
,那么它可以使用 public 修饰的属性(如 id、age),但不能使用没有 public 修饰的属性(name)。只有同在 com.test
包中的其他类才能使用 com.test.Person
中没有 public修饰的属性(name)。
[!faq] 如果我引用的是公共类(public class) 也需要 import 吗?
只要是类在不同的包中,就需要 import,不 import 就得用类的全限定名。而关于类的 public 访问修饰符,并不是说是 public 就不用导入,而是当你用全限定名类名或 import 后,这个被导入的类如果是 public 的,才能被访问到。即可以理解成:我得先找到这个类(import或使用类的全限定名),我再看这个类的访问修饰符来知道这个类能不能被我访问。
src
|
|--- A
| |
| |--- aaa
| |--- abc
|
|--- B
| |
| |--- abc
|
|--- C
| |
| |--- abc
假如 A 包中有一个类 abc,那么 A 包中的类 aaa 是可以直接引用这个类 abc 的,此时,如果 aaa 中导入了 B 包中的同名类 abc,则直接在 aaa 中使用 abc是指向 B 包中的 abc(即原来同一个包中的同名类被覆盖),若此时再多导入一个 C 包中的同名类 abc,则会报错,jvm 无法确定 abc 指向哪个包中的 abc 类。
import xxx as yyy
来给导入的类起一个别名,所以当遇到需要引用多个不同的包中的同名类时,解决方式就是直接使用它们各自的全限定类名。这里有个要注意的点,如果导入的方式是全限定名导入,那么的确是导入的类会覆盖掉这个包中原先的同名类。但如果导入的方式是用通配符(
*
),则并不会覆盖掉这个包中的同名类,直接使用该类名,还是会用的是包中原先的同名类。// com.test 下有一个叫 CPU 的类, com.test.phone 下也有一个叫 CPU 的类 // 当前文件在 com.test 下 package com.test; import com.test.phone.*; CPU a = new CPU(); // 此时用的是 com.test 下的 CPU类 package com.test; import com.test.phone.CPU; CPU a = new CPU(); // 此时用的是 com.test.phone 下的 CPU类,即覆盖掉 com.test 下的同名类
简称:类的全名
同一个 java 程序中,全限定名不可重复。
类的全限定名 = 包名 + 类名。
java 中,有些自带的函数是可以直接使用的,而不需要显式地使用 import 来导入其所在的类、包。
凡是在 java.lang 包中的类,如 Math 等,都不需要 import 就可以直接使用其中的方法,如:Math.random()
。
但只要不是 java.lang 包中的,比如 java.util 包中的,就需要显式 import 导入才能使用其中的函数,如:
import java.util.Random; // 单独导入 java.util 包中的 Random 类
public class TestClass{
public static void main(String[] args){
Random abc = new Random();
}
}
当然,如果是用 IDEA 的话,在你写 Random abc = new Random();
时,IDEA 会自动帮你在代码上方添加导入语句(import java.util.Random;),而不需要你自己手动添加。如果 IDEA 添加了,你又不小心删除了该导入语句,Random
就会标红,此时鼠标停留在其上,按下键盘alt
+enter
,就会让你选择代码补全,则又能重新自动添加该导入语句。
如果是你直接使用
Math.random()
,则你不需要写它的 import 语句,IDEA 也不会帮你添加它的 import 语句,因为就是不需要import 的。