包
包用于划分类的命名空间,使得不同包中的同名类不会冲突。
Java 使用文件夹存储包,文件夹名和包名一致。
Java 运行时系统从当前目录中、CLASSPATH 变量定义的值、-classpath 指定的值这三种途径寻找包。
包和成员访问
可访问性 | private | 无修饰符 | protected | public |
---|---|---|---|---|
同一个类 | 是 | 是 | 是 | 是 |
同一个包的子类 | 否 | 是 | 是 | 是 |
同一个包的非子类 | 否 | 是 | 是 | 是 |
不同包的子类 | 否 | 否 | 是 | 是 |
不同包的非子类 | 否 | 否 | 否 | 是 |
一个源文件中只能有一个 public 类,并且该文件必须以这个类的名称命名。
导入包
import 语句位于 package 语句之后,其他语句之前。
java.lang 包由编译器隐含导入。
如果使用全限定名,则不需要 import 语句。
接口
一个类可以实现任意数量的接口,一个接口可以被任意数量的类实现。
modifier interface name {
type name(parameterList);
type name = value;
}
没有修饰符时,接口只能被同一个包下的其他对象使用。public 接口在一个源文件中只能有一个,并且这个文件的名字必须和这个接口同名。接口中的方法本质上都是抽象方法。每个实现接口的类必须实现这个接口的全部方法。
从 JDK8 开始,接口中的方法允许有默认实现,也有了静态方法。从 JDK9 开始,接口中可以有私有方法。
接口中可以定义变量,这些变量默认是 final 和 static 的,必须初始化,不能被实现类改变。
接口中所有方法和变量默认为 public。
class name implements interface[,interface...] {
// body
}
若某个类实现了两个接口,同时这两个接口定义了完全一样的方法,则类实现这个方法,表示同时实现了这两个接口定义的该方法。
实现接口的方法时,方法必须定义为 public 并且方法签名必须和接口中的定义一致。
接口类型变量可以引用任何实现了该接口的类实例,这个变量调用方法时,调用的是类实例中对应的方法。能够通过该变量调用的方法必须在接口中有定义,不能调用接口中没有定义的方法。
实现接口的类没有实现接口中全部方法时,该类必须定义为抽象类,该类的子类必须实现接口的全部方法或者定义为抽象类。
接口作为一个类或者另一个接口的成员时,该接口分别称为成员接口、nested 接口。nested 接口可以用 public、private 或 protected 修饰。在定义 nested 接口的作用域外使用该接口时,使用完全限定名,如 ClassName.interfaceName
。
实现仅定义了变量的接口的类,具有该接口定义的所有变量,这些变量本质上是常量。(不推荐这种做法。)
接口也可以像类一样,进行继承。实现了某个接口的类必须实现该接口的所有方法,如果该接口还继承了其他接口,那么所有继承自其他接口的方法也必须被实现。
默认接口方法
从 JDK8 开始,接口中允许定义默认方法,默认方法是接口提供了实现的方法,也称 extension method。
默认方法提出的主要动机是,当使用广泛的接口突然加入新的方法,由于之前使用该接口的代码没有实现这个新方法,涉及到这个接口的旧代码都会出错。如果使用了默认方法,则旧代码不会受到影响。
默认方法的另一个动机是,有时接口的部分方法某些实现类不需要,此时只能将该方法实现为空方法,冗余。默认方法解决了这个问题。
接口和类的很大不同之处在于,接口不能维护状态信息。接口不能实例化。
default type name(parameterList) {
// body
}
实现接口的类可以实现,也可以不实现接口的默认方法。
当一个类实现了两个接口,这两个接口具有相同的默认方法时,1)如果该类重写了这个默认方法,则之后使用的是类重写的方法;2)如果没有重写这个默认方法,则报错。
当一个类实现了一个接口 A,A 继承了接口 B。这两个接口具有相同的默认方法时,类没有重写该默认方法,则使用的是接口 A 定义的默认方法。访问另一个默认方法的形式为:interfaceName.super.methodName()
。
interface IA {
default void m() {
System.out.println("a");
}
}
interface IB extends IA {
default void m() {
// 调用 IA 的默认方法
// 只能调用直接父接口的方法
IA.super.m();
System.out.println("b");
}
}
public class InterfaceTest implements IB {
public static void main(String[] args) {
// 不允许使用 IA.super.m()
// 可以使用 IB.super.m()
new InterfaceTest().m();
}
}
接口中使用静态方法
JDK8 开始,接口允许定义静态方法。静态方法的使用与在类中定义时相似,都不需要实例化即可调用。interface.staticMethod()
。
静态方法不能被继承,无论是子接口还是实现了该接口的类。
私有接口方法
JDK9 开始,接口允许定义私有方法。私有方法不能被继承,包括子接口。私有方法只能被同一个接口的默认方法和私有方法使用。
提供私有方法的目的是给其他方法提供通用的代码段,避免代码冗余。
参考
[1] Herbert Schildt, Java The Complete Reference 11th, 2019.
[2] 接口相关