乐趣区

关于java:Java-包学习-Java-编程语言

Java 容许应用包(package)将类组织在一个汇合中。借助包能够不便地组织本人的代码,并将本人的代码与他人提供的代码库离开治理。

规范的 Java 类库散布在多个包中,包含 java.long、java.util 和 java.net 等。规范的 Java 包具备一个层次结构。所有规范的 Java 包都处于 java 和 javax 包档次中。

1. 包名

应用包的次要起因是确保类名的唯一性。事实上,为了确保包名的相对唯一性,要用一个因特网域名(这显然是惟一的)以逆序的模式作为包名,而后对于不同的工程应用不同的子包。例如,域名 xiang117.com,逆序来写,失去包名 com.xiang117。而后能够追加一个工程名,如 com.xiang117.corejava。如果在把 Employee 类放在这个包里,那么这个类的“齐全限定”名就是 com.xiang117.corejava.Employee。

从编译器的角度看来,嵌套的包之间没有任何关系。例如,java.util 包与 java.util.jar 包毫无关系。每一个包都是独立的类汇合。

2. 类的导入

一个类能够应用所属包中的所有类,以及其余包中的公共类(public class)。
能够采纳两种形式拜访另一个包中的私有类:

  1. 应用齐全限定名(fully qualified name),即包名后跟着类名。
    java.time.LocalData today = java.time.LocalDate.now();
  2. 应用 import 语句。

能够应用 import 语句导入一个特定的类或者整个包。import 语句应该位于资源文件的顶部(但位于 package 语句的前面)。

import 语句是一种援用包中各个类的简捷形式。一旦应用了 import 语句,在应用类时,就不用写出类的全名了。

import 语句的惟一益处是简捷。能够应用简短的名字而不是残缺的包名来援用一个类。

能够应用上面语句导入 java.time 包中的所有类。import java.time.*;
就能够应用 LocalDate today = localDate.now();
无需在后面加上包的前缀。

java.time.* 的语法比较简单,对代码的规模也没有任何负面影响。当然,如果可能明确地指出所导入的类,将会使代码的读者更加精确地晓得你应用了哪些类。

须要留神的是,只能应用星号(_)导入一个包,而不能应用 import java._或 import java._._ 导入以 java 为前缀的所有包。

能够导入一个包中的特定类:import java.time.LocalDate;

在大多数状况下,能够只导入所须要的包,并不用过多地思考它们。但在产生命名抵触的时候,就要留神包了。例如,java.util 和 java.sql 包都有 Date 类。如果在程序中导入了这两个包:import java.util.; import java.sql.;
在程序应用 Date 类的时候,就会呈现一个编译谬误:Date today; // Error–java.util.Date or java.sal.Date?
此时编译器无奈确定程序应用的是哪一个 Date 类。能够采纳减少一个特定的 import 语句来解决这个问题:import java.util.; import java.sql.; import iava.util.Date;
如果这两个 Date 类都须要应用,须要在每个类名的后面加上残缺的包名。java.util.Date deadline = new java.util.Date(); java.sql.Date today = new java.sql.Date();

在包中定位类是编译器(compiler)的工作。类文件中的字节码总是应用残缺的包名援用其余类。

3. 动态导入

有一种 import 语句容许导入静态方法和动态字段,而不只是类。

如果在源文件顶部,增加一条指令:import static java.lang.System.*;
就能够应用 System 类的静态方法和动态字段。而不用加类名前缀:out.println(“Goodbye, World!”); // i.e., System.out exit(0); // i.e., System.exit

能够导入特定的办法或字段:import static java.lang.System.out;

实际上,是否有很多网站监控程序员想要用简写 System.out 或 System.exit,这一点让人狐疑。这样写出的代码看起来不太清晰。不过,sqrt(pow(x, 2) + pow(y, 2))
看起来比 Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
清晰得多。

4. 在包中减少类

要想将类放入包中,就必须将包的名字放在源文件的结尾,即放在定义这个包中各个类的代码之前。例如在 com.xiang017.corejava 包中减少 Employee 类:

Employee.java

package com.xiang017.corejava;

public class Employee

{

}

如果没有在源文件中搁置 package 语句,这个源文件中的类就属于_无名包(unnamed package)_。无名包没包名。

PackageTest.java

import com.xiang017.javacore.*;

public class PackageTest {

public static void main(String[] args) {

Employee harry = new Employee(“Harry Hacker”, 50000, 1989, 10, 1);

}

}

将源文件放到与完整包名匹配的子目录中。例如,com.xiang017.corejava 包中的所有源文件应该搁置在子目录 com/xiang017/corejava 中。编译器将类文件也放在雷同的目录构造中。例如:

. (基目录)

PackageTest.java

└─com

└─xiang017

└─javacore

Employee.java

要想编译这个程序,只需切换到基目录,并运行命令:javac PackageTest.java
编译器就会主动地查找文件 com/xiang017/corejava/Employee.java 并进行编译。编译后的后果如下:

. (基目录)

PackageTest.class

PackageTest.java

└─com

└─xiang017

└─javacore

Employee.class

Employee.java

要运行这个程序,须要在基目录下执行命令:java PackageTest

如果 PackageTest.java 源文件没有在基目录下,在 mycompany 包下,如:

.(基目录)

|– com/

|– corejava/

| |– Employe.java

| |– Employe.class

|

|– mycompany/

|– PackageTest.java

|– PackageTest.class

依然要从基目录编译和运行类,即蕴含 com 目录的目录:javac com/mycompany/PackageTest.java java com.mycompany.PackageTest

须要留神,编译器对文件(带有文件分隔符的扩展名 .java 的文件)进行操作。而 Java 解释器加载类(带有 . 的分隔符)。

正告: 编译器在编译源文件的时候不查看目录构造。例如,假设有一个源文件结尾有以下指令:package com.mycompany;
即便这个源文件不在子目录 com/mycompany 下,也能够进行编译。如果它不依赖于其余包,就能够通过编译而不会呈现编译谬误。然而,最终的程序将无奈运行,除非先将所有的类文件移到正确的地位上。如果包与目录不匹配,虚拟机就找不到类。

PackageTest.java

import com.xiang017.javacore.*;

public class PackageTest {

public static void main(String[] args) {

Employee harry = new Employee(“Harry Hacker”, 50000, 1989, 10, 1);

System.out.println(“name=” + harry.getName() +

“,salary=” + harry.getSalary() +

“,hireDay=” + harry.getHireDay());

}

}

com/mycompany/Employee.java

package com.xiang017.javacore;

import java.time.LocalDate;

import java.util.Objects;

public class Employee {

private String name;

private double salary;

private LocalDate hireDay;

public Employee(String name, double salary, int year, int month, int day) {

this.name = name;

this.salary = salary;

hireDay = LocalDate.of(year, month, day);

}

public String getName() {

return name;

}

public double getSalary() {

return salary;

}

public LocalDate getHireDay() {

return hireDay;

}

public void raiseSalary(double byPercent) {

double raise = salary * byPercent / 100;

salary += raise;

}

}

5. 包拜访

标记为 public 的局部能够由任意类应用;标记为 private 的局部只能由定义它们的类应用。如果没有指定 public 或 private,这个局部(类、办法或变量)能够被同一个包中的所有办法拜访。

没有标记修饰符的类只有在同一个包中其余类能够拜访。对于类来说,这种默认形式是合乎情理的。然而,对于变量来说就有些不合适了,变量必须显式地标记为 private,不然的话将默认为包可见。这样会毁坏封装性。

在默认状况下,包不是一个关闭的实体。也就是说,任何人都能够向包中增加更多的类。

从 1.2 版开始,JDK 的实现者批改了类加载器,明确禁止加载包名以“java.”结尾的用户自定义类!当然,用户自定义的类无奈从这种爱护中受害。另一种机制让 JAR 文件申明包为密封的(sealed),以避免第三方批改,但这种机制曾经过期。当初该当应用模块封装包。

退出移动版