zoukankan      html  css  js  c++  java
  • 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的。其实还是为了安全考虑的) 这样接口也能起到一定的模版的作用。
    --------------------- 

  • 相关阅读:
    梯度消失、爆炸原因及其解决方法(转)
    Learning to Rank for IR的评价指标—MAP,NDCG,MRR
    tensorflow中使用指定的GPU及GPU显存 CUDA_VISIBLE_DEVICES
    深度学习 weight initialization
    python 第三方包安装
    列表操作 -深拷贝与浅拷贝
    python排序 sorted()与list.sort() (转)
    Python 第三方库 cp27、cp35 等文件名的含义(转)
    Learning to Rank(转)
    Spring MVC异常处理
  • 原文地址:https://www.cnblogs.com/ly570/p/10942272.html
Copyright © 2011-2022 走看看