栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

接口作为形参,以及一个类作为子类和实现类,同时继承与实现后,调用同名方法的一些情况

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

接口作为形参,以及一个类作为子类和实现类,同时继承与实现后,调用同名方法的一些情况

使用接口作为形参

当我们编写一个有参方法,形参就是使用时传入的参数类型。这个类型限制了传入的参数。

而有一种语法,可以将接口对象当做形参。

而我们知道,接口是不可以new对象的,所以这里的接口形参,实际上是规定一个大范围。

真正调用方法时应当传入一个接口的实现类作为方法的参数。

目前较新的JDK都已经可以允许接口、抽象类中存在各种访问权限等级的方法,包括私有。

并且这些方法,除了抽象方法,都可以有方法体存在。

首先我们要知道,在动态绑定(不懂的可以去看我另一篇介绍这个定义的文章)发生时,实际会执行子类中重写后的方法。

public class Test5 extends Father5 implements I5{
   public void show() {
      System.out.println("子类方法执行");
   }
   public static void main(String[] args) {
      Test5 t1 = new Test5();
      I5 t2 = new Test5();
      Father5 t3 = new Test5();

      t1.show(); //子类方法执行
      t2.show(); //子类方法执行
      t3.show(); //子类方法执行
   }
}

interface I5 {
   default void show(){
      System.out.println("接口方法执行");
   }
}

class Father5 {
   public void show() {
      System.out.println("父类方法执行");
   }
}

但这仅仅是参数相同(无参也算相同)的情况下。

当我们把形参设成不同类型时,子类中的方法就不再是重写后的方法,所以会用声明类型中的方法来实现。

public class Test5 extends Father5 implements I5{
   public void show(Test5 test5) {
      System.out.println("子类方法执行");
   }
   public static void main(String[] args) {
      Test5 t1 = new Test5();
      I5 t2 = new Test5();
      Father5 t3 = new Test5();

       //即使Test5确实是I5的实现类,Father5的子类,但形参不同,就不会发生动态绑定
      t1.show(t1); //子类方法执行
      t2.show(t1); //接口方法执行
      t3.show(t1); //父类方法执行
       
      t1.show(t1); //子类方法执行
      t2.show(t2); //接口方法执行
      t3.show(t3); //父类方法执行
   }
}

interface I5 {
   default void show(I5 i5){
      System.out.println("接口方法执行");
   }
}

class Father5 {
   public void show(Father5 father5) {
      System.out.println("父类方法执行");
   }
}

这样写也是可以的,因为t1是Test5类型,是子类同时也是实现类,所以符合另外两个show方法对形参类型的要求。

但如果我们把t3作为参数给到t2的show方法(反之亦然),那么就会报错,因为I5与Father5之间没有一定的关联。

至少在编译器看来它们俩是没关系的。

当然,我们程序员能够看出,t1,t2,t3的实际类型都是Test5类,所以进行强转是没有问题的,强转后程序也能够正常执行。

Test5 t1 = new Test5();
I5 t2 = new Test5();
Father5 t3 = new Test5();

t1.show(t1); //子类方法执行
t2.show((I5) t3); //接口方法执行
t3.show((Father5) t2); //父类方法执行
综合案例(很重要!!)
package base;

//创建一个父类A
class A3 {
    //给一个方法f
   void f(A3 a){
      System.out.println("A");
   }

// void test() {
//    System.out.println("父类");
// }
}

interface I2 {

   //这里他使用了接口本身作为形参
   default void f(I2 i) {
      System.out.println("I");
   }

    //一个接口内的无参方法
   default void test(){
      System.out.println("接口");
   }

   default void test2(I2 i2){
      System.out.println("接口");
   }
}

public class Test3 extends A3 implements I2 {

   //如果把f方法的参数换成I2 i,那么编译器会要求把访问权限设置成public
   // 因为参数相同,变成重写接口方法了。这时调用同名方法,会发生动态绑定
   //这样写的话,后面所有的I都会变成B
// public void f(I2 i2) {
//    System.out.println("B");
// }

   //当参数是Test3时,后面我们调用main方法时,main方法里的f,其实是接口的方法
   //因为实现了接口,但因为f不是抽象方法,所以不要求一定重写
   //那么实际上就相当于,Test3并没有实现I2接口中的这个方法,而是方法重载

   //这里的形参是一个具体的类
   //所以其实压根和接口I2里的不是一个方法,那个default void f是被继承、隐藏了,后续调用的相当于隐藏起来的方法
   void f(Test3 test3) {
      System.out.println("B");
   }

   //无参实验方法
    public void test() {
      System.out.println("子类");
   }

   //有参实验方法
   public void test2(Test3 test3) {
      System.out.println("子类");
   }

   public static void main(String[] args) {
      I2 i = new Test3();

      //test方法,如果父类、接口中都有(无论是哪个,编译都可以通过)
      //那么该方法在参数相同的情况下,默认被当做重写后的父类方法
       
      //所当我们用动态绑定来创建对象后,是正常的逻辑,调用子类中的重写方法
      i.test(); //子类


      //但如果参数不相同,接口内的方法形参是接口对象(不存在,所以其实相当于实现类)
      //而实现类内部的方法形参是他本身,那么就相当于接口的方法没有真正被重写,而是重载了
      //但当我们new实现类作为实参时,由于该类实现了I2接口,所以他相当于一个”接口对象”
      //我们恰好是用i去调用,i是接口实现类对象。从参数类型上来看,没有问题。
      //所以这里去实际调用的方法就是接口内的方法。
      i.test2(new Test3()); //接口

      Test3 tmp = new Test3();

      //Test3实际上相当于没有实现接口内的方法,所以当我们用i去调用f方法时,I2中有f方法,不报错
      //同时,只有接口I2中有这个方法(形参类型为I2),所以调用时也只能使用这个方法
      i.f(tmp); // I
      System.out.println("=========================");
      i.f(new Test3()); // I
      i.f(i);// I

   }
}
注意事项
  • 实现接口中的方法时,访问权限修饰符不能小于接口内方法本身。大多数情况下,重写时都需要用public修饰来确保。
  • 形参不同时(类型、个数),同名方法不算做重写,而是重载。这时,什么类型的引用去调用,就会用这个类型内的方法去实现。
  • 接口中的静态方法不会被继承,但默认方法会被继承,非抽象方法不要求实现。
public class Interface1 implements I6{
   public static void main(String[] args) {

      //默认方法可以被继承
      Interface1 interface1 = new Interface1();
      interface1.show();//方法被继承了

      //静态方法不能被继承,会报错
      //interface1.show2();

      //但可以直接通过类名. 来调用
      I6.show2(); //未被继承
   }
}

interface I6 {
   default void show(){
      System.out.println("方法被继承了");
   }

   static void show2() {
      System.out.println("未被继承");
   }

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/975356.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号