Skip to content

java允许使用包(package)将类组织起来。使用包的主要原因是确保类名的唯一性,防止命名冲突。

package语句必须是文件中除注释以外的第一行程序代码:package access,以表明该文件是在包access 下。

比如说对于两个 Person 类,放在不同的包下,这样在Java虚拟机执行的时候,JVM只看完整类名,因此,只要包名不同,类就不同。 小明的Person.java文件:

java
package ming; // 申明包名ming

public class Person {
}

小红的 Person.java文件:

java
package hong; // hong

public class Person {
}

包可以是多层结构,用.隔开。例如:java.util。 ⚠️要特别注意:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。

Java文件对应的目录层次要和包的层次一致,假设以package_sample作为根目录,src作为源码目录,那么所有文件结构就是: image.png

类的导入

一个类可以使用所属包中的所有类,以及其他包中的公有类(public class)。 我们可以采用两种方式访问另一个包中的公有类。

  1. 为每个类名之前添加完整包名
java
   java.time.LocalDate today = java.time.LocalDate.now();
  1. 使用import 语句

在Java中,我们经常看到public、protected、private这些修饰符。在Java中,这些修饰符可以用来限定访问作用域。

public

定义为public的class、interface可以被其他任何类访问:

package abc;

public class Hello {
    public void hi() {
    }
}

上面的Hello是public,因此,可以被其他包的类访问:

package xyz;

class Main {
    void foo() {
        // Main可以访问Hello
        Hello h = new Hello();
    }
}

定义为public的field、method可以被其他类访问,前提是首先有访问class的权限:

package abc;

public class Hello {
    public void hi() {
    }
}

上面的hi()方法是public,可以被其他类调用,前提是首先要能访问Hello类:

package xyz;

class Main {
    void foo() {
        Hello h = new Hello();
        h.hi();
    }
}

private

定义为private的field、method无法被其他类访问:

package abc;

public class Hello {
    // 不能被其他类调用:
    private void hi() {
    }

    public void hello() {
        this.hi();
    }
}

实际上,确切地说,private访问权限被限定在class的内部,而且与方法声明顺序_无关_。推荐把private方法放到后面,因为public方法定义了类对外提供的功能,阅读代码的时候,应该先关注public方法:

package abc;

public class Hello {
    public void hello() {
        this.hi();
    }

    private void hi() {
    }
}

由于Java支持嵌套类,如果一个类内部还定义了嵌套类,那么,嵌套类拥有访问private的权限:

// private

Run 定义在一个class内部的class称为嵌套类(nested class),Java支持好几种嵌套类。

protected

protected作用于继承关系。定义为protected的字段和方法可以被子类访问,以及子类的子类:

package abc;

public class Hello {
    // protected方法:
    protected void hi() {
    }
}

上面的protected方法可以被继承的类访问:

package xyz;

class Main extends Hello {
    void foo() {
        // 可以访问protected方法:
        hi();
    }
}

package

最后,包作用域是指一个类允许访问同一个package的没有public、private修饰的class,以及没有public、protected、private修饰的字段和方法。

package abc;
// package权限的类:
class Hello {
    // package权限的方法:
    void hi() {
    }
}

只要在同一个包,就可以访问package权限的class、field和method:

package abc;

class Main {
    void foo() {
        // 可以访问package权限的类:
        Hello h = new Hello();
        // 可以调用package权限的方法:
        h.hi();
    }
}

注意,包名必须完全一致,包没有父子关系,com.apache和com.apache.abc是不同的包。

局部变量

在方法内部定义的变量称为局部变量,局部变量作用域从变量声明处开始到对应的块结束。方法参数也是局部变量。

package abc;

public class Hello {
    void hi(String name) { // ①
        String s = name.toLowerCase(); // ②
        int len = s.length(); // ③
        if (len < 10) { // ④
            int p = 10 - len; // ⑤
            for (int i=0; i<10; i++) { // ⑥
                System.out.println(); // ⑦
            } // ⑧
        } // ⑨
    } // ⑩
}

我们观察上面的hi()方法代码:

  • 方法参数name是局部变量,它的作用域是整个方法,即①~⑩;
  • 变量s的作用域是定义处到方法结束,即②~⑩;
  • 变量len的作用域是定义处到方法结束,即③~⑩;
  • 变量p的作用域是定义处到if块结束,即⑤~⑨;
  • 变量i的作用域是for循环,即⑥~⑧。

使用局部变量时,应该尽可能把局部变量的作用域缩小,尽可能延后声明局部变量。

final

Java还提供了一个final修饰符。final与访问权限不冲突,它有很多作用。 用final修饰class可以阻止被继承:

package abc;

// 无法被继承:
public final class Hello {
    private int n = 0;
    protected void hi(int t) {
        long i = t;
    }
}

用final修饰method可以阻止被子类覆写:

package abc;

public class Hello {
    // 无法被覆写:
    protected final void hi() {
    }
}

用final修饰field可以阻止被重新赋值:

package abc;

public class Hello {
    private final int n = 0;
    protected void hi() {
        this.n = 1; // error!
    }
}

用final修饰局部变量可以阻止被重新赋值:

package abc;

public class Hello {
    protected void hi(final int t) {
        t = 1; // error!
    }
}

最佳实践

如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。 把方法定义为package权限有助于测试,因为测试类和被测试类只要位于同一个package,测试代码就可以访问被测试类的package权限方法。 一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。

小结

  • Java内建的访问权限包括public、protected、private和package权限;
  • Java在方法内部定义的变量是局部变量,局部变量的作用域从变量声明开始,到一个块结束;
  • final修饰符不是访问权限,它可以修饰class、field和method;
  • 一个.java文件只能包含一个public类,但可以包含多个非public类。