一、接口的默认访问修饰符
接口中的所有变量都是以public static final进行默认修饰的。
而且我们不能以其他的方式来修饰这些变量,所以我们只需要以下面这样的形式来定义一个变量即可。
int age = 18;
我们不需要显示的去修饰其是public static final的。
即便我们以public final,或者static final这样漏掉一个或两个修饰符的方式去显示修饰,其仍然是以public static final进行修饰的实际上。
public interface Company {
// private final int age = 18;
// Illegal modifier for the interface field Company.age; only public, static & final are permitted
final int age = 18;
// static char sex;
// 没有初始化,错误的代码
static char sex = '男';
String name = "刘昊然";
// public static final String name = "刘昊然";这两者是等同的
}
class Test{
public void test() {
int age = Company.age;
char sex = Company.sex;
String name = Company.name;
}
}
以上是接口中成员变量的修饰符相关内容。
接下来是接口中方法的修饰符相关内容。
首先接口中的方法都是以public abstract作为默认修饰符的。
其次,和变量一样的,方法不能以private的方式进行修饰,并且如果你以public又或是abstract的方式进行修饰,编译器仍然会为你补齐剩下的修饰符,所以我们只需要常规的定义一个方法即可。
public void test();
但不同的是,接口中的方法可以是abstract,static,default中的一个,不过其一定是public的。
而且static和default方法可以有其方法体,static方法可以通过接口名直接调用,而default方法必须通过实现该接口的类来调用。
public interface Company {
/* private abstract void test();
* Illegal combination of modifiers for the private interface method test;
* additionally only one of static and strictfp is permitted
*/
void recruitment();
/*
* void paySalary(int number) { // Abstract methods do not specify a body }
*/
default void payBonus() {
//default修饰的方法可以具有方法体
}
static void paySalary(int number) {
//static修饰的方法同样可以具有方法体
System.out.println("这里除了我什么都没有,因为我是不会给你们发工资的");
}
}
在以上接口内我们定义了一个抽象的方法招聘,一个默认的有方法体的方法支付奖金,一个静态的有方法体的方法支付工资。
这分别是接口内的三种方法的修饰符形式。然后对于这些不同的修饰符,类在对其进行实现时会出现不同的结果。
首先没有方法体的抽象方法显然是必须被实现的,另外两个方法则无需被实现,因为他们有其方法体。
(
Ps:default修饰符可以用在接口中时jdk8新加入的特性,之所以要加入这个特性,是因为如果我们要修改一个接口来扩展其功能,那么我们会发现所有已经实现了该接口或该接口的子接口的实现类都不得不实现添加的新抽象方法。
而这会导致许多类可能因为接口的更新而崩溃。
为了避免这种情况的出现,我们可以向其中加入default方法,该解释参考自以下链接。
)
那么,如果一个类同时实现了两个接口,且该接口具有同样的default和static方法会如何呢?
二、同时实现多个接口
首先给出另一个接口的定义
public interface Money {
default void payBonus() {
//这是一个和Company接口中default方法同名的方法
}
static void paySalary() {
//这是一个和Company接口中static方法同名的方法
System.out.println("我要给大家发工资啦!");
}
}
可以看到这里有同名的支付奖金和支付工资方法,且具有相同的访问修饰符。
那么接下来定义一个类同时实现这两个接口。
public class Boss implements Company,Money{
@Override
public void recruitment() {
}
@Override
public void payBonus() {
Company.super.payBonus();
// Company.super.paySalary(1000);
// This static method of interface Company can only be accessed as Company.paySalary(int number)
}
}
首先,我们必须实现招聘方法。
其次,尽管我们不必实现default方法原本,但由于两个接口中有着同名的default方法,编译器将会无法选择用谁覆盖谁,所以编译器将会逼迫我们进行重写。
但是我们可以在重写的方法内主动调用某个接口中的default方法。
有意思的是由于接口并不是实现类的父类,所以我们不能直接以super指代父接口,super仅仅只能用于指代父类。
但是我们可以以父接口名.super的方式来指代某个父接口,从而调用其中的default方法(但我们不能调用其static方法,而只能用接口名.static方法的方式来调用)ps:但我没有明白为何要这样设计
然后大家可以看到在这些代码里并没有static方法的重写,这是因为我们无需重写父接口的重名static方法吗?
事实上并不是这样的,父接口中的static方法实际上和成员变量一样,是以static final的修饰符进行修饰的。
所以实现类根本无法继承父接口的该static方法,也就不存在重写了。
以下是对Boss类的实例化测试。
public class Test {
public static void main(String[] args) {
Boss b = new Boss();
b.payBonus();
// ((Company) b).paySalary(1000);
// b.paySalary(1000);
// The method paySalary(int) is undefined for the type Boss
}
}
可以看到Boss类中根本不存在paySalary这个方法,同时我们也无法以向上转型的方式来调用父接口的paySalary方法,这个原理和无法通过super对static final方法进行调用是一样的。