今天上午在读《Effective Java》时,有这样一句话:”接口中“不能有静态方法,于是联想起面试时老是被问接口相关的东西,决定总结一下,谁知道这一总结,就发现了自己知识的一大漏洞。
在以前的思维中,接口中所有的方法都是抽象的,而抽象的方法没有static,有static的方法不能被override。但是在java8以后,允许在接口里定义默认方法和类方法。
一、接口代码
TestInterfac:
public interface TestInterface {
//此处的静态方法只能被public修饰(或者省略不写),不能是private或者protected。
static void out1() {
System.out.println("接口的静态输出方法1");
}
void out2();
default void out3() {
System.out.println("默认输出方法3");
}
}
实现类 TestImpl:
public class TestImpl implements TestInterface{
public static void main(String[] args) {
TestInterface.out1();
TestImpl demo = new TestImpl();
demo.out2();
demo.out3();
}
@Override
public void out2() {
System.out.println("实现普通输出方法2");
}
}
运行结果:
当我们在实现接口时,发现默认只需要实现out2方法,因为只有out2方法是抽象的。当然也可以手工实现将out3()方法重写,但是不能够重写静态方法out1。可以用TestInterface.out1()直接调用接口中的静态方法。
当创建demo对象时,可以直接调用out2,out3,但不可以调用静态方法out1()。为什么不能调用out1()?因为一个类可以实现多个接口。如果2个接口具有相同的 static 方法,则它们都将被继承,编译器将不知道要调用哪个。
Java8为什么要引入默认方法?
默认方法的主要优势是提供一种拓展接口的方法,而不破坏现有代码。加入我们有一个已经投入使用接口需要拓展一个新的方法,在JDK8以前,如果为一个使用的接口增加一个新方法,则我们必须在所有实现类中添加该方法的实现,否则编译会出现异常。如果实现类数量少并且我们有权限修改,可能会工作量相对较少。如果实现类比较多或者我们没有权限修改实现类源代码,这样可能就比较麻烦。而默认方法则解决了这个问题,它提供了一个实现,当没有显示提供其他实现时就采用这个实现。这样新添加的方法将不会破坏现有代码。
默认方法的另一个优势是该方法是可选的,子类可以根据不同的需求Override默认实现。
二、继承的父类和实现的接口中有相同的方法
父类TestClass:
public class TestClass {
public void out3() {
System.out.println("我是父类中的输出方法3");
}
}
子类:
public class TestImpl extends TestClass implements TestInterface{
public static void main(String[] args) {
TestInterface.out1();
TestImpl demo = new TestImpl();
demo.out2();
demo.out3();
}
@Override
public void out2() {
System.out.println("实现普通输出方法2");
}
}
运行结果:
所以,当继承的父类和实现的接口中有相同签名的方法时,优先使用父类的方法。
三、实现的多个接口中有相同的方法。
接口1:
public interface TestInterface {
default void out3() {
System.out.println("默认输出方法3");
}
}
接口2:
interface TestInterface2 {
default void out3() {
System.out.println("第二个接口中的默认输出方法3");
}
}
实现类:
public class TestImpl implements TestInterface,TestInterface2{
public static void main(String[] args) {
TestImpl demo = new TestImpl();
demo.out3();
}
}
当我们去写实现类的时候发现会报错,错因如下:
必须在实现类中通过重写方法解决冲突问题,否者无法通过编译,在重写的方法中可以通过 接口名.super.方法名(); 的方式显示调用需要的方法。
为什么java的接口里的属性必须是static的?并且要求必须是final的呢?
接口中的数据对所有实现类只有一份,所以是static
要使实现类为了向上转型成功,所以必须是final的(接口不能被实例化,所以接口里面如果是变量的话不会被赋初始值这样就会出问题,所以必须是final的。其实还是为了安全考虑的) 这样接口也能起到一定的模版的作用。
参考文章:https://blog.csdn.net/qq_34755766/article/details/82861916
https://www.cnblogs.com/wuyx/p/9129118.html