黑马程序员——面向对象14:接口

本文详细介绍了接口的概念、书写方式、用法以及多实现、多继承的特点,并通过实例展示了接口如何提高代码的扩展性和降低耦合性,进而解释了接口在编程中的核心价值。

------- android培训java培训、期待与您交流! ----------

1. 接口的书写格式

我们可以把接口理解为一种特殊的抽象类,因为接口特点之一就是它所有的方法都是抽象的。接口的书写格式如下:

代码1:

interface Inter
{
	//常量
	public static final doublePI = 3.14;
	//抽象方法
	public abstract void f();
}
接口的标识符是interface,这与类的标识符class是有区别的。通常,在接口内部定义的都是常量和抽象方法,并且两者修饰符都是固定的,常量的修饰符:public static final;方法的修饰符:public abstract。大家需要注意的是:只要定义的是接口,那么其内部的常量和方法的上述修饰符不必手动添加,系统会自动添加缺少的修饰符。但是为了提高代码的阅读性,应尽量将修饰符添加齐全。

2. 接口的用法

接口和抽象类一样,因为抽象方法的存在,无法创建实例对象,也要通过子类“继承”的形式复写方法。对于接口来说,它的子类和接口之间的关系不再称为“继承”,而是称为“实现”,关键字为“implements”。以上述Inter接口为例,

代码2:

interface Inter
{
	//常量
	public static final doublePI = 3.14;
	//抽象方法
	public abstract void f();
}
class Demo implements Inter
{
	public void f()
	{
		System.out.println(“Demo run”);
	}
}
class InterfaceDemo
{
	public static voidmain(String[] args)
	{
		Demo d =new Demo();
		System.out.println(d.PI);
		System.out.println(Demo.PI);
		System.out.println(Inter.PI);
	}
}
运行结果为:

3.14

3.14

3.14

这表明,虽然不能调用接口的方法,但是可以通过接口名调用接口内的常量。当然,由于final修饰符的原因,无论是通过接口名、类名还是对象调用该常量,都是不能重新赋值的。此外,上述代码中子类Demo实现了Inter接口,并复写了f()方法。

3. 继承与实现的区别

从形式上看,好像子类实现接口和子类继承抽象父类没有什么区别。实际上,抽象父类中既有抽象方法还有非抽象方法,子类继承了非抽象方法,就可以直接使用了,也就是说子类还是从父类“继承”了一些现成的东西,不必完全由自己定义;而对于接口来说,子类只有把接口的所有方法全部复写一遍,也就说是将这些抽象方法“实现”为真正的有实际用途的方法以后,才能使用。

4. 接口的多实现

所谓多实现,就是一个类可以实现多个接口。多实现的格式如下:

代码3:

interface Inter1
{
	public abstract void f_1();
}
interface Inter2
{
	public abstract void f_2();
}
class Demo2 implements Inter1, Inter2
{
	public void f_1()
	{
		System.out.println(“f_1run”);
}
	public void f_2()
	{
		System.out.println(“f_2run”);
	}
}
子类通过逗号分隔实现的多个接口,并复写所有接口的所有非同名抽象方法。这里为什么要强调非同名方法,因为假如两个接口定义了两个同名的抽象方法(两个方法的返回值类型必须相同,否则会出现编译错误),子类实现了这两个接口以后,实际上只需要复写一次该方法就行了,这就是接口可以实现多实现的原因,因为接口的方法没有方法体,在都只有方法名的情况下不存在子类无法区分两个方法的问题。而继承体系中,如果两个父类定义了两个同名方法,那么子类在继承并调用的时候,就会出现问题。

此外,子类在继承了某个类的情况下还可以进行多实现,比如,

代码4:

class Sub extends Super implements Inter1, Interface2{}

小知识点1:

类与类之间是继承;

接口与类之间是实现;

接口与接口之间只能是继承,这是因为,所谓实现,必须由子类将接口的抽象方法复写,并定义具体的实际内容,而接口内部都是抽象方法,也就不可能具体实现了。


5. 接口的多继承

前面的内容中我们讲到,Java中不允许直接地多继承,而是通过其他的方法间接实现,那就是通过接口来多继承

代码5:

interface Inter1
{
	public abstract void f_1();
}
interface Inter2
{
	public abstract void f_2();
}
interface Inter3 extends Inter1, Inter2
{
	public abstract void f_3();
}
接口可以实现多继承的原因和它允许多实现的原因是一样的,就是因为接口的方法没有方法体,即使方法名相同也不会造成混乱。但是,不能出现方法名相同,而返回值类型不同的情况,比如:

代码5:

interface Inter1
{
	public abstract int f();
}
interface Inter2
{
	public abstract booleanf();
}
interface Inter3 extends Inter1, Inter2{}
对于上述代码,如果有子类实现了Inter3接口,那么复写了两个f()方法以后,就会出现返回值类型混乱的情况,当调用子类对象的f()方法时无法确定返回值类型到底是什么。那么这就是Java中唯一可以实现多继承的地方,除此以外,均不能进行多继承。

6. 接口的意义

为了大家更好的理解接口的存在意义,我们举一个现实生活中的例子来说明。早期的CPU都是焊死在主板上的,然而CPU的更新换代速度以及人们对CPU处理性能的要求越来越高,将CPU焊死在主板上的方式显然不能满足人们的要求——每次需要升级电脑都要重新购买新的设备。

这个时候,为了提高计算机的扩展性,人们在主板上专门设计了一个通用的CPU插槽,有了这个插槽,就可以方便的更换符合这类插槽“规则”的CPU而不需要重新购买电脑了。有了这种“插槽”的设计,就降低了CPU和主板的耦合性,换句话说,原来CPU和主板之间的关系非常紧密,而现在二者关系的紧密程度大大降低,也就是解耦了。此外,不仅可以设计CPU的插槽,还可以设计显卡插槽、声卡插槽、网卡插槽等等,只要板卡符合对应C插槽的规则就可以使用,大大提高了计算机功能的扩展性,这就是“插槽”的好处。而这里“插槽”就可以理解为程序中的“接口”,同样提高了代码的扩展性。

那么降低了耦合性以后,无论对厂商还是对消费者都是有好处的。对厂商来说,CPU厂商和主板厂商就可以专门研发各自的产品,而不需要分散精力;对于消费者来说,方便的更换自己需要的板卡,随意进行功能扩展。

我们用一段代码来说明接口的意义,比如我们定义车辆(Vehicle)类,车辆类中有一个开车方法(定义了具体的方法体)和加油的抽象方法(因为不同的车加不同的油)。再定义一个轿车(Sedan)类继承车辆类,复写加油方法,并打印“加93号汽油”。我们又希望这个轿车通过改装变成赛车,也就说为它增加一个比赛功能,此时我们为了增加代码的扩展性,定义一个比赛接口,其内部定义一个比赛方法,轿车类实现比赛接口并复写比赛方法即可。

代码6:

/*
	定义抽象类——车辆。
	由于不同车加不同的油,加油方法定义为抽象方法
*/
abstract class Vehicle
{
	//抽象方法,加油
	abstract void refuel();
	//开车方法
	public void drive()
	{
		System.out.println("开车");
	}
}
/*
	比赛接口,实现该接口,可获得比赛功能
*/
interface Racing
{
	public abstract voidrace();
}
/*
	轿车类继承车辆类,复写加油方法;
	实现比赛接口,复写比赛方法
*/
class Sedan extends Vehicle implements Racing
{
	public void refuel()
	{
		System.out.println("加93号汽油");
	}
	public void race()
	{
		System.out.println("进行赛车比赛");
	}
}
class InterfaceTest
{
	public static voidmain(String[] args)
	{
		Sedan s = newSedan();
		s.refuel();
		s.drive();
		s.race();
	}
}
运行结果为:

加93号汽油

开车

进行赛车比赛

通过这样的设计,可以让有需要的轿车类,通过实现比赛接口,而拥有比赛功能;反之,如果将比赛功能定义在车辆类中,只要继承了车辆类就会拥有比赛功能,而这是不符合现实情况的。

通过上述例子,我们可以进一步理解实现和继承的区别:继承的关系可以理解为“is a”,轿车是车辆的一种,通过继承子类应该拥有该继承体系的基本方法;实现的关系可以理解为“like a”,轿车通过实现比赛接口拥有了比赛功能,扩展了它原有的功能。如果我们再定义别的接口,轿车类就又可以进一步扩展了。因此,接口内应定义扩展功能。

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值