Java8新特性-接口中的静态方法与默认方法

时间:2022-06-01 19:22:11

今天上午在读《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的。其实还是为了安全考虑的) 这样接口也能起到一定的模版的作用。
---------------------