首页 > 编程语言 >Java——接口

Java——接口

时间:2024-11-11 12:18:24浏览次数:3  
标签:Java void System 接口 println public out

一、接口是什么

在Java中,接口(Interface)是一种引用数据类型,类似于类,然而它只能包含常量、方法签名和嵌套类型。接口不能包含实例变量或方法的实现(在Java 8及之后的版本,可以在接口中定义默认方法和静态方法)。接口主要用于定义类的外部行为,并允许类实现这些行为。

二、接口详细介绍

1、接口定义语法

接口的定义使用 interface 关键字,以下是一个简单的接口示例:

public interface Animal {
    // 常量
    int LEGS = 4; // 默认有修饰符 public static final

    // 抽象方法
    void makeSound();// 默认有修饰符 public abstract
    void eat();// 默认有修饰符 public abstract
}

2、接口的实现

一个类通过 implements 关键字来实现接口,并提供接口中所有抽象方法的具体实现。例如:

public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }

    @Override
    public void eat() {
        System.out.println("Dog is eating.");
    }
}

3、接口的使用

通过接口引用实现类对象,可以实现多态性(类似于父类引用指向子类对象):

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.makeSound(); // 输出: Woof!
        myDog.eat();       // 输出: Dog is eating.
    }
}

三、接口的特点

1、方法公有性和抽象性

接口中的方法都默认是 public 的,而且必须是 public 的,因为 private 和 protected 修饰符都不能在接口中使用,而且如果不写访问修饰符的话,就是默认访问限制,但在接口中默认访问限制就是 public 的。所以接口中的所有方法都是 public 的,以便能够被实现类访问。

除了默认方法和静态方法之外,接口中的其他方法默认是抽象的,即没有方法体。实现接口的类必须提供这些抽象方法的实现。

interface Animal {
	void cry();// 默认有修饰符 public abstract
	
	public abstract void eat();// 这里的 public abstract 是没有必要的
}

可以看到图中的 public abstract 颜色是灰色,这说明在这里写 public abstract 是没有必要的。

2、变量默认为公有静态常量

接口中定义的变量默认是 public static final 修饰的,即静态常量,所有实现该接口的类都可以访问这些常量。因为接口中不能使用 private 和 protected 修饰符,所以接口中的属性也都是公有的,而且必定是公有静态常量。

public class Example {
	public static void main(String[] args) {
		System.out.println(Animal.a);// 直接使用接口名访问
		//Animal.a++;// 会报错
	}
}

interface Animal {
	int a = 0;// 默认有修饰符 public static final
}

可以看到图中的 public static final 都是灰色的,说明这里写 public static final 是没有必要的。

所以说对于接口中的成员属性能直接使用接口名访问:

InterfaceName.variable

3、不能被实例化

接口不能被实例化,所以不支持构造函数。尝试在接口中写构造函数会出现报错:

4、默认方法和静态方法

从Java 8开始,接口可以包含默认方法和静态方法:

默认方法(default):默认方法可以有方法体。默认方法不需要实现接口的类去实现,但是它们仍然是 public 的。使用 default 关键词修饰的是默认方法。

静态方法(static):静态方法也有方法体,不需要实现接口的类实现,这些方法也是 public 的,并且可以在接口本身上调用。使用 static 修饰的为静态方法。

interface Animal {
	// 默认方法
	default void eat() {
		System.out.println("...");
	}

	// 静态方法
	static void foo() {
		System.out.println("~");
	}
}

默认方法和静态方法都是默认且一定是 public 的,所以在它们前面显式地添加 public 修饰符是没有必要的。

对于默认方法,实现这个接口的类可以重写它:

interface Animal {
	// 默认方法
	default void eat() {
		System.out.println("...");
	}

	// 静态方法
	static void foo() {
		System.out.println("~");
	}
}

class Cat implements Animal {
	@Override
	public void eat() {
		System.out.println("猫吃鱼...");
	}
}

5、接口的抽象方法的实现

一个普通类实现接口,则需要将接口中的所有抽象方法实现。如果是一个抽象类实现接口,则是否实现抽象方法都行。

因为抽象类中是允许有抽象方法的,但是普通类中不允许有抽象方法。

interface Interface {
	void foo();
}

abstract class AbstractClass implements Interface{
	// 抽象类实现接口,可以不实现接口的抽象方法
}

6、接口之间的继承

接口不能继承某个类,但是接口可以继承接口。

interface InterfaceA {
	void fun1();
}

interface InterfaceB extends InterfaceA {
	void fun2();
}

Java接口支持多重继承,一个接口可以继承多个其他接口。这与类的继承不同,类在Java中只能单继承(即一个类只能继承一个父类)。

interface InterfaceA {
	void fun1();
}

interface InterfaceB {
	void fun2();
}

interface InterfaceC extends InterfaceA, InterfaceB{
	
}

示例:

// 定义基本接口
interface Animal {
    void eat();
}

// 定义一个继承自 Animal 的接口
interface Mammal extends Animal {
    void giveBirth();
}

// 定义一个继承自 Mammal 的接口
interface Dog extends Mammal {
    void bark();
}

// 实现 Dog 接口的类
class Bulldog implements Dog {
    @Override
    public void eat() {
        System.out.println("Bulldog is eating.");
    }

    @Override
    public void giveBirth() {
        System.out.println("Bulldog gives birth to puppies.");
    }

    @Override
    public void bark() {
        System.out.println("Bulldog barks.");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        Bulldog myDog = new Bulldog();
        myDog.eat();        // 输出: Bulldog is eating.
        myDog.giveBirth();  // 输出: Bulldog gives birth to puppies.
        myDog.bark();       // 输出: Bulldog barks.
    }
}

四、多重接口实现

Java中的类不能多重继承(一个子类继承多个基类),但一个类可以实现多个接口,这样就实现了多重继承的效果。这种特性称为多重接口实现

1、语法与要求

一个类实现多个接口时,接口名之间用逗号分隔。例如:

public class MyClass implements InterfaceA, InterfaceB {
    // 实现接口中的所有方法
}

实现多个接口时,类必须实现所有接口中定义的抽象方法。如果某个接口有默认方法,则可以选择重写它或直接使用。

2、示例

// 定义接口A
interface InterfaceA {
    void methodA();
}

// 定义接口B
interface InterfaceB {
    void methodB();
}

// 定义一个类实现这两个接口
public class MyClass implements InterfaceA, InterfaceB {
    @Override
    public void methodA() {
        System.out.println("Method A implemented.");
    }

    @Override
    public void methodB() {
        System.out.println("Method B implemented.");
    }
    
    // 其他类的方法
    public void additionalMethod() {
        System.out.println("Additional method.");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        MyClass myObject = new MyClass();
        myObject.methodA(); // 输出: Method A implemented.
        myObject.methodB(); // 输出: Method B implemented.
        myObject.additionalMethod(); // 输出: Additional method.
    }
}

3、方法冲突

如果多个接口中定义了同名的方法,且没有默认实现,类必须提供具体实现。例如:

interface InterfaceA {
    void method();
}

interface InterfaceB {
    void method();
}

public class MyClass implements InterfaceA, InterfaceB {
    @Override
    public void method() {
        System.out.println("Implemented method from both interfaces.");
    }
}

4、默认方法冲突

如果多个接口中有相同方法标签的默认方法,实现类必须重写该方法以消除歧义。

interface InterfaceA {
	default void foo() {
		System.out.println("A");
	}
}

interface InterfaceB {
	default void foo() {
		System.out.println("A");
	}
}

class C implements InterfaceA, InterfaceB {
	@Override
	public void foo() { // 重写方法以消除歧义。必须重写这个方法,不然会报错
		System.out.println("C");
	}
}

如果方法标签不同,则可形成重载,则不需要实现类重写来消除歧义。

interface InterfaceA {
	default void foo() {
		System.out.println("A");
	}
}

interface InterfaceB {
	default void foo(int a) {
		System.out.println("A");
	}
}

class C implements InterfaceA, InterfaceB {
	// 这里即使不重写,也不会报错,因为上面的两个方法不存在歧义
}

五、实现接口和继承类

1、继承单一性 vs 接口多实现:

继承类:Java中一个类只能继承一个父类(单继承)。这是因为Java不支持多重继承,以避免菱形继承问题。

实现接口:一个类可以实现多个接口。这允许Java类通过实现多个接口来模拟多重继承。

2、使用场景:

继承类:用于表示一种“is-a”关系,表示子类是一种特殊的父类类型。

实现接口:用于表示一种“can-do”关系,表示类能够执行接口定义的行为。

abstract class Animal {
	private String name;

	public Animal(String name) {
		this.name = name;
	}

	public abstract void cry();
}

interface ShakeHands {
	void shakeHands();
}

interface SpinningAround {
	void spinningAround();
}

class Dog extends Animal implements ShakeHands, SpinningAround {
	public Dog(String name) {
		super(name);
	}

	@Override
	public void cry() {
		System.out.println("汪汪~");
	}

	@Override
	public void shakeHands() {
		System.out.println("握手~");
	}

	@Override
	public void spinningAround() {
		System.out.println("转圈圈~");
	}
}

Dog 类继承自抽象类 Animal 表示狗是一种动物,Dog 实现了 ShakeHands 和 SpinningAround 两个接口,说明狗通过练习可以握手和转圈圈。

3、价值

继承类:解决代码的复用性和可维护性。

实现接口:接口设计好各种规范,实现类来实现这些规范的方法,可以更加灵活。

4、接口对于代码的解耦 

接口在Java中用于定义一组方法的规范,允许不同的类实现这些方法,从而实现代码的解耦。

代码解耦意味着不同的模块或类之间的依赖关系减少,使得修改一个部分的代码时,不会影响到其他部分,从而提高了系统的灵活性和可维护性。

// 定义支付接口
interface Payment {
    void pay(double amount);
}

// 实现信用卡支付
class CreditCardPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " using Credit Card.");
    }
}

// 实现支付宝支付
class AlipayPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " using Alipay.");
    }
}

// 使用支付接口的用户类
class ShoppingCart {
    private Payment payment;

    public ShoppingCart(Payment payment) {
        this.payment = payment;
    }

    public void checkout(double amount) {
        payment.pay(amount);
    }
}

// 测试代码
public class Main {
    public static void main(String[] args) {
        Payment creditCardPayment = new CreditCardPayment();
        ShoppingCart cart1 = new ShoppingCart(creditCardPayment);
        cart1.checkout(100.0); // 使用信用卡支付

        Payment alipayPayment = new AlipayPayment();
        ShoppingCart cart2 = new ShoppingCart(alipayPayment);
        cart2.checkout(150.0); // 使用支付宝支付
    }
}

ShoppingCart 类与具体的支付方式(如CreditCardPayment或AlipayPayment)没有直接的依赖关系。你可以轻松地在不修改 ShoppingCart 类的情况下,添加新的支付方式,只需实现 Payment 接口即可。

六、接口的多态

接口多态意味着可以使用接口类型的引用来指向任何实现该接口的类对象。这样可以在程序中灵活切换不同实现,达到多态的效果。

1、多态数组

可以将接口类型引用数组的元素指向不同的实现类的对象。

package com.study.episode10.Interface.Example3;

public class Example {
	public static void main(String[] args) {
		InterfaceCry[] ic = new InterfaceCry[2];
		ic[0] = new Dog();
		ic[1] = new Cat();
		for(InterfaceCry i : ic) {
			i.cry();
		}
	}
}

interface InterfaceCry {
	void cry();
}

class Dog implements InterfaceCry {
	@Override
	public void cry() {
		System.out.println("Woof~");
	}
}

class Cat implements InterfaceCry {
	@Override
	public void cry() {
		System.out.println("Meow~");
	}
}

运行结果:

2、多态参数

利用接口类型作为方法参数,可以将任何实现了该接口的类的对象作为参数传入。

package com.study.episode10.Interface.Example3;

public class Example {
	public static void animalCry(InterfaceCry ic) {
		ic.cry();
	}

	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		animalCry(dog);
		animalCry(cat);
	}
}

interface InterfaceCry {
	void cry();
}

class Dog implements InterfaceCry {
	@Override
	public void cry() {
		System.out.println("Woof~");
	}
}

class Cat implements InterfaceCry {
	@Override
	public void cry() {
		System.out.println("Meow~");
	}
}

运行结果:

3、接口的多态传递

public class Example {
	public static void main(String[] args) {
		Interface1 i1 = new A();
	}
}

interface Interface1 {}

interface Interface2 extends Interface1 {}

class A implements Interface2 {}

这个示例展示了Java中接口的继承和多态性。具体来说,Interface2 继承自 Interface1,而类 A 实现了 Interface2。这使得 A 也间接实现了 Interface1。这种结构提供了接口的传递性,即可以使用Interface1类型的引用来指向实现了Interface2的类的对象。

4、接口相关的向下转型和向上转型

在进行过向上转型后,也就是接口类型的引用指向实现类的对象,这时,只能通过引用变量访问 接口中有的成员,不能访问实现类的特有成员,如果想要访问实现类的特有成员,则需要进行向下转型:

public class Example {
	public static void main(String[] args) {
		Interface i = new ImplementingClass();
		System.out.println(i.specificField);// 接口特有字段,接口中有的成员,所以能访问
		i.commonMethod();// 共有成员,接口中也有,所以能调用

		// i.specificMethod; // 这里就会报错,因为接口中没有这个成员,
		// 这是实现类的特有成员,如果要访问,则需要向下转型

		((ImplementingClass)i).specificMethod();// 向下转型后访问实现类的特有成员
	}
}

interface Interface {
	String specificField = "Interface specific field~";
	void commonMethod();
}

class ImplementingClass implements Interface {
	@Override
	public void commonMethod() {
		System.out.println("common method~");
	}

	public void specificMethod() {
		System.out.println("implementing class specific method~");
	}
}

七、补充

1、名称冲突

interface I {
	int x = 0;// public static final int x = 0;
}

class A {
	int x = 1;
}

class B extends A implements I {
	public void prtX() {
		System.out.println(x);// 这里会出现歧义,会报错,说x是模棱两可的,没有指明x
						      // 因为B类从A类中继承了一个x,从I接口中实现时得到了一个静态常量x
							  // 这里直接写一个x就相当于this.x,这样是不清晰的,因为B类中有了两个x
							  // 需要指明是哪个x
	}
}

这是因为接口 I 和类 A 中都定义了一个同名的字段 x,这会导致类 B 中引用 x 时产生歧义。Java中解决这种字段冲突的办法是明确指定你想要访问的 x 的来源。

访问接口中的 x

如果想要在 prtX() 方法中访问接口 I 中定义的 x,可以这样修改:

	public void prtX() {
		System.out.println(I.x);
	}

因为接口中的字段都是静态的,可以直接使用接口名加字段名访问。

访问父类中的 x

如果你想要在 prtX() 方法中访问类 A 中定义的 x,可以这样修改:

	public void prtX() {
		System.out.println(super.x);
	}

标签:Java,void,System,接口,println,public,out
From: https://blog.csdn.net/stewie6/article/details/143482361

相关文章

  • JavaScript基础总结
             JavaScript(简称JS)是一个广泛使用的客户端脚本语言,常用于网页开发中。它可以在浏览器中运行,执行交互操作和动态效果。以下是JavaScript基础的所有核心知识点,按主题分类列出。1.基本语法声明变量使用var、let和const来声明变量:varname='Alice';/......
  • JavaScript题目一 根据成绩给出学生考评
            根据学生的成绩给出考评,可以通过if或switch语句来实现。下面是一个简单的JavaScript代码示例,根据学生的成绩返回不同的评语。示例代码:functionevaluateStudent(score){letevaluation;if(score>=90){evaluation='优秀';}else......
  • JavaScript题目二 实现猜数字游戏
    实现一个猜数字游戏的过程,通常包括以下几个步骤:生成一个随机数:计算机随机生成一个目标数字。用户输入猜测:玩家猜测数字并提交。比较用户输入与目标数字:计算机检查玩家的猜测,给出提示(比如“猜小了”或“猜大了”)。循环进行:直到玩家猜对为止,或者达到预设的次数。1.HTML文件(......
  • JavaScript题目三 制作简易计算器
    目标:提供四个基本的运算功能:加、减、乘、除。支持数字输入和运算符输入。显示结果。1.HTML文件(index.html)<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,i......
  • Qualcomm SA8295P资源解析(一):驱动智能驾驶与车载娱乐的多接口技术先锋
    QualcommSA8295P的核心:多核CPU设计QualcommSA8295P的CPU采用了Kryo695架构,其分成了两种不同配置的核心组,分别是KryoGoldPrime和KryoGold核心。KryoGoldPrime核心带有1MB的L2缓存,最高频率可以达到2.38GHz,而KryoGold核心配备512KB的L2缓存,频率最高为2.09GHz。这......
  • java浅拷贝BeanUtils.copyProperties引发的RPC异常
    作者:京东物流吴义背景近期参与了一个攻坚项目,前期因为其他流程原因,测试时间已经耽搁了好几天了,本以为已经解决了卡点,后续流程应该顺顺利利的,没想到人在地铁上,bug从咚咚来~没有任何修改的服务接口,抛出异常:java.lang.ClassCastException:java.util.HashMapcannotbecastto......
  • 代码随想录之滑动窗口、Java日期api、集合(11.4-11.11)
    代码1、长度最小的子数组⭐使用滑动窗口的思想,外层循环控制结束位置j,内层循环控制起始位置i,看似是双层循环,但时间复杂度是o(2n)。 2、水果成篮自己想法:使用backet1和backet2表示篮子1和篮子2;使用backet1Account和backet2Account分别表示两个篮子里水果的数量,内层循环将i指针......
  • 「Java开发指南」如何自定义Spring代码生成?(二)
    搭建用户经常发现自己对生成的代码进行相同的修改,这些修改与个人风格/偏好、项目特定需求或公司标准有关,本教程演示自定义代码生成模板,您将学习如何:创建自定义项目修改现有模板来包含自定义注释使用JET和Skyway标记库中的标记配置项目来使用自定义在上文中,我们为大家介绍了......
  • JavaScript变量
    变量是用于存储信息的"容器"。实例varx=5;vary=6;varz=x+y;尝试一下»就像代数那样x=5y=6z=x+y在代数中,我们使用字母(比如x)来保存值(比如5)。通过上面的表达式z=x+y,我们能够计算出z的值为11。在JavaScript中,这些字母被称为变量。您可以把变量看做存储数......
  • java计算机毕业设计电脑销售管理系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、研究背景在当今数字化的时代,电脑销售行业竞争日益激烈。随着市场的不断扩大,电脑产品的种类繁多,销售渠道也日益多样化,传统的管理方式已经难以满足企业高效......