【Java】接口

一、接口

接口是 Java 中定义类行为规范的一种机制。它只规定类应该实现哪些方法,而不负责具体实现

public interface 接口名{
	//属性
	int SPEED_LIMIT = 100; // 等同于 public static final int SPEED_LIMIT = 100;
	//方法
	// 抽象方法
	void go(String loc); // 等同于 public abstract void go(String loc);
    // default 方法 (JDK8.0包括8.0之后)                                 
    default void stop() {      
        System.out.print("stop");
    };   
    // 静态方法 (JDK8.0包括8.0之后)
    static void start() {
  		System.out.print("start");
	}               

}
  • 声明接口:接口的修饰符号只能是默认和public

    • 如果接口声明为 public,则该接口可以被任何其他类或接口访问。
    public interface Move {
        void go();
    }
    
    • 如果接口没有显式声明修饰符(即默认修饰符),则该接口只能在同一个包内访问。
    interface Move {
        void go();
    }
    
  • 属性:必须且默认为 public static final ,所以必须定义时初始化。

  • 方法:接口中所有方法都是public

    • 声明抽象方法:必须且默认为 abstract+public

在JDK7.0之前,接口中的所有方法都是抽象方法,即无方法体
在JDK8.0包括8.0之后,接口中可以有抽象/静态/默认方法(需要修饰符default),即方法体可有可无

interface USB{  
    int i = 0;//必须赋值  
	 void A();  
	 default void B(){  
	        System.out.print("this id B()");  
	 }  
	 static void C(){  
	        System.out.print("this is C()");  
	 }  
}

二、接口的实现

接口和接口之间可以继承;类实现接口

class 类名 implements 接口{
	//自身属性
	//自身方法
	//实现接口中的所有方法
}
  • 接口不能被实例化
    接口是一种抽象类型,它只定义了方法的签名(即方法的名称、参数和返回类型),而没有具体的实现。因此,接口不能被直接实例化。只能实例化实现了接口的类。

    interface MyInterface {
        void myMethod();
    }
    
    class MyClass implements MyInterface {
        public void myMethod() {
            System.out.println("Method implemented");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            // MyInterface obj = new MyInterface(); // 错误:接口不能被实例化
            MyInterface obj = new MyClass(); // 正确:实例化实现了接口的类
            obj.myMethod();
        }
    }
    
  • 普通类实现接口必须实现接口中的所有方法(快捷键alt+enter)

    interface MyInterface {
        void method1();
        void method2();
    }
    
    class MyClass implements MyInterface {
        @Override
        public void method1() {
            System.out.println("Method 1 implemented");
        }
    
        @Override
        public void method2() {
            System.out.println("Method 2 implemented");
        }
    }
    
  • 抽象类实现接口可以不实现接口的抽象方法
    抽象类可以实现接口,但它不需要实现接口中的所有方法。抽象类可以将这些方法的实现留给它的子类来完成。

    interface MyInterface {
        void method1();
        void method2();
    }
    
    abstract class MyAbstractClass implements MyInterface {
        @Override
        public void method1() {
            System.out.println("Method 1 implemented in abstract class");
        }
        // method2 没有被实现,留给子类实现
    }
    
    class MyClass extends MyAbstractClass {
        @Override
        public void method2() {
            System.out.println("Method 2 implemented in subclass");
        }
    }
    
  • 一个类可以有多个接口接口继承

  • 接口中属性的访问形式:接口名.属性名
    接口中的属性默认是public static final 的,即它们是常量。因此,访问接口中的属性时,应该使用接口名来引用。

    interface MyInterface {
        int MY_CONSTANT = 10; // 默认是 public static final
    }
    
    public class Main {
        public static void main(String[] args) {
            System.out.println(MyInterface.MY_CONSTANT); // 输出: 10
        }
    }
    

三、接口与继承的区别

特性 继承 (extends) 接口 (implements)
关系 类与类(is-a 类与接口(can-do
关键字 extends implements
数量 单继承 (避免“菱形问题”) 多实现
代码复用 直接复用父类代码 不提供代码复用
方法实现 子类继承父类方法 实现类必须实现接口方法
设计目的 代码复用和层次化设计 定义规范和扩展功能
灵活性 强耦合,灵活性较低 松耦合,灵活性高
默认方法 父类可以定义具体方法 Java 8+ 支持默认方法和静态方法

“菱形问题”(Diamond Problem)是多重继承中一个经典的问题,主要出现在一个类同时继承自两个或多个具有共同父类的类时。这个问题之所以被称为“菱形问题”,是因为类继承关系的图形化表示会形成一个菱形状。
什么是菱形问题?
假设有以下继承关系:

  1. A 有一个方法 method()
  2. B 继承自 A,并重写了 method()
  3. C 也继承自 A,并重写了 method()
  4. D 同时继承自 BC

此时,D 类继承了 BC,而 BC 都重写了 Amethod()。那么,当 D 调用 method() 时,应该调用 B 的版本还是 C 的版本?这就是菱形问题。

     A
    / \
   B   C
    \ /
     D

Java 如何解决菱形问题?
Java 通过单继承接口的多实现来避免菱形问题:

  1. 单继承
  • Java 中一个类只能直接继承一个父类,避免了多重继承带来的菱形问题。
  • 例如:class D extends BD 不能同时继承 BC
  1. 接口的多实现
  • Java 允许一个类实现多个接口。
  • 接口中的方法默认是抽象的,实现类必须提供具体实现,因此不会产生方法冲突。
  • 从 Java 8 开始,接口可以定义默认方法(default),但如果多个接口有相同的默认方法,实现类必须重写该方法以解决冲突。

Java 8 中的默认方法与菱形问题
Java 8 引入了接口的默认方法,这可能导致类似菱形问题的情况:

  • 如果一个类实现了两个接口,且这两个接口有相同的默认方法,编译器会要求实现类重写该方法以解决冲突。
interface A {
  default void method() {
     System.out.println("A");
}
}

interface B {
  default void method() {
     System.out.println("B");
}
}

class C implements A, B {
  @Override
 public void method() {
    System.out.println("C"); // 必须重写以解决冲突
}
}

C++ 中的菱形问题
C++ 支持多重继承,因此菱形问题在 C++ 中是一个实际存在的问题。C++ 通过虚继承(Virtual Inheritance)来解决这个问题:

  • 使用 virtual 关键字声明继承关系,确保共同父类只被继承一次。
  • 例如:
class A {
public:
    void method() { cout << "A"; }
};

class B : virtual public A {
public:
 void method() { cout << "B"; }
};

class C : virtual public A {
public:
 void method() { cout << "C"; }
};

class D : public B, public C {
public:
  void method() { cout << "D"; }
};

D 中调用 method() 时,会明确调用 D 的实现,避免了二义性。

四、接口的多态性

  1. 多态参数

    interface A{}  
    class B implements A{}  
    class C implements A{}  
      
    class AA{}  
    class BB extends AA{}  
    class CC extends AA{}  
    public class InterfacePolyParameter {  
        public static void main(String[] args) {  
            //接口的多态体现  
    		 //接口类型的变量a 可以指向 实现了A接口的对象实例  
    		 A a=new B();  
    		 a=new C();  
    		 //继承的多态体现  
    		 //父类类型的变量aa 可以指向 继承了父类AA的子类的对象实例  
    		 AA aa=new BB();  
    		 aa=new CC();  
     }  
    }
    
  2. 多态数组

    interface D{}  
    class E implements D{}  
    class F implements D{}  
    public class InterfacePolyArray {  
        public static void main(String[] args) {  
            //方法一:  
    		 D[]d1=new D[2];  
    		 d1[0]=new E();  
    		 d1[1]=new F();  
    		 //方法二:  
    		 D[ ]d2={new E(), new F() };  
      
     }  
    }
    
  3. 多态传递

    interface J{}  
    interface K extends J{}  
    class L implements K{}  
    public class InterfacePolyPass {  
        public static void main(String[] args) {  
            K k=new L();  
    		J j=new L();  
     }  
    }
    

    关系图:
    【Java】接口_第1张图片

练习

以下程序的运行结果为?

interface A{  
    int a=1;  
}  
class B implements A {  
      
}  
public class InterfaceExercise {  
    public static void main(String[] args) {  
	     B b = new B();  
		 System.out.println(A.a);  
		 System.out.println(B.a);  
		 System.out.println(b.a);  
 }  
}

A类中的a是pubilc static final int类型,所以以上语法都正确且输出都为1

interface G {  
   int x=0;  
}  
class H{  
  int x=1;  
}  
class I extends H implements G{  
  void getX(){  
     System.out.println(x);  
}  
}  
public class InterfaceExercise02 {  
  public static void main(String[] args) {  
     I i = new I();  
		i.getX();  
}  
}

I类继承了H又有接口G,其中H和G都有属性x,这时就会导致指向不明确
接口中的x类型为public static final,因此可以用接口名.属性的方式直接引用;对于父类的属性,可以利用super调用

class I extends H implements G{  
    void getX(){  
        System.out.println(G.x+" "+super.x);  
 }  
}

你可能感兴趣的:(#,Java,java,开发语言)