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


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

  • 相关阅读:
    java网络编程【b站狂神课程笔记】
    算法设计与分析
    NP问题/NP完全问题(NP-complete problem)如何判断是否是NP完全问题
    递归的三部解题曲 关联leetcode 104. 二叉树最大深度练习
    修改typora偏好设置实现自动上传图片 关联PicGo + Gitee(码云) + typora实现markdown图床
    Typescript常见面试题
    INTEL Trusted Execution Technology (TXT) -- 基本原理
    北京大学肖臻老师《区块链技术与应用》笔记
    JavaGUI编程之贪吃蛇小游戏原码
    LeetCode 21.合并两个有序链表
  • 原文地址:https://www.cnblogs.com/ly570/p/10942272.html
Copyright © 2020-2023  润新知