学习笔记之JavaSE(17)--面向对象编程8

今天学习的内容是抽象类与接口


一、抽象类和抽象方法

之前说到继承,子类不仅包含父类的所有内容,还有自己的新功能,那么实例化父类就显得没有意义了。在实际工作中,一般将父类定义为抽象类。有时没有办法作出给任何子类都有意义的共同程序代码,就可以把它定义为抽象方法。抽象类和抽象方法的知识点如下:

  • 被abstract关键字修饰的类叫做抽象类,被abstract关键字修饰的方法叫做抽象方法
  • 抽象类格式:abstract class 类{} 
  • 抽象方法格式:abstract 返回值类型  方法();
  • 抽象类不能被实例化,因为调用抽象类对象的抽象方法没有意义
  • 抽象类中可以定义抽象方法和具体方法,可以全都是抽象方法,也可以全都是具体方法
  • 抽象类中全都是具体方法的目的就是不让该类创建对象,通常这个类中的方法都有方法体但是没有具体内容,所以创建该类对象没有意义
  • 只要类中至少有一个抽象方法存在,它就必须定义为抽象类
  • 抽象类中存在构造函数,是为了给父类子对象进行初始化
  • 与普通的类和方法一样,抽象类和抽象方法也被权限修饰符控制(抽象类只能是public或包访问权限)
  • abstract关键字不能和private、static和final关键字共存,这是因为这三种修饰符所修饰的方法压根没法被覆盖!!而没法被覆盖就更没法多态!!
  • 如果某类继承了抽象类,并想创建子类对象,那么就必须实现抽象类中所有抽象方法。如果不这么做也可以,子类便也是抽象类,必须加上abstract关键字,否则编译报错
示例程序:
abstract class Fu{
	
	//抽象类中也有构造函数,是为了给父类的子对象进行初始化
	public Fu(){
		System.out.println("父类构造函数");
	}

	//abstract不能和private、static和final共存
	//!private abstract void test();
	//!static abstract void test();
	//!final abstract void test();
	
	//抽象类中可以定义抽象方法和具体方法,可以都是抽象方法,也可以都是具体方法
	public abstract void absA();
	public abstract void absB();
	public void aa(){
		System.out.println("父类的aa()方法");
	}
}

public class Zi extends Fu{

	//实现父类的抽象方法absA()
	public void absA() {
		System.out.println("子类实现父类的抽象方法absA");
	}
	
	//实现父类的抽象方法absB()
	public void absB() {
		System.out.println("子类实现父类的抽象方法absB");
	}
	
	//覆盖父类的方法aa()
	public void aa(){
		System.out.println("子类的aa()方法");
	}
	
	public static void main(String[] args){
		//如果某类继承了抽象类,并想创建子类对象,那么就必须实现抽象类中所有抽象方法
		Zi z=new Zi();//会调用抽象类构造函数
		z.aa();//子类的aa()方法
		z.absA();//子类实现父类的抽象方法absA
		z.absB();//子类实现父类的抽象方法absB
		//!Fu fu=new Fu(); 抽象类不能被实例化,因为调用抽象方法没意义
	}
}

二、接口

接口是抽象类的延伸,是一种规范。接口中的所有方法都是抽象方法,没有提供任何具体实现。接口的知识点:
  • 由interface修饰的类叫做接口
  • 语法格式:interface 接口名{}
  • 接口被权限修饰符控制,可以是public和包访问权限
  • 接口中的所有变量都被隐式定义为public、static和final的
  • 接口中所有方法都被隐式定义为public和abstract的
  • 实现接口的类,除非实现了所有抽象方法,否则必须加abstract
  • 接口解决了多继承的“致命方块”问题(因为实现类只会有一个该方法 ,不存在不清楚调用哪个的问题
  • 接口支持多实现,一个类可以同时继承单个父类与实现多个接口
  • 实现的格式为:class 接口  implements 接口1,接口2...{}
  • 接口与接口之间是继承关系,而且可以多继承

interface JieKou1{
	String STR="123";//接口中的变量自动是public、static、final的,
	
	void aa();//接口中的方法自动是public、abstract的
}


interface JieKou2{
	void bb();
}

//接口与接口之间是继承关系,而且可以多继承
interface JieKou3 extends JieKou1,JieKou2{}

abstract class Fu{
	abstract public void cc();
}

//一个类可以同时继承单个父类与实现多个接口
public class Impl extends Fu  implements JieKou1,JieKou2{

	@Override
	public void aa() {
		System.out.println("实现第一个接口的aa()方法");
		
	}
	
	@Override
	public void bb() {
		System.out.println("实现第二个接口的bb()方法");
	}
	
	@Override
	public void cc(){
		System.out.println("覆盖父类的cc()方法");
	}
	
	
	public static void main(String[] args){
		Impl impl=new Impl();
		impl.aa();//实现第一个接口的aa()方法
		impl.bb();//实现第二个接口的bb()方法
		impl.cc();//覆盖父类的cc()方法
		System.out.println(JieKou1.STR);//123
	}
}


三、使用场景

组合、继承和接口到底应该什么时候使用呢?

之前使用Spring+SpringMVC+Mybatis框架做项目时,我发现项目中使用最多的是组合还有接口。从实际出发,我总结了一下这三种技术的使用场景(个人愚见)

组合:目的只是复用代码,将现有类的对象引用置于本类中即可。其实组合主要是为了调用第三方API。。

接口:目的是建立规范解耦

比方说开会,会议内容一定是先致辞、然后讨论、最后总结,但是你并不知道每个步骤具体要做什么。这时可以将会议定义为一个接口,这个接口有致辞、讨论和结束三个方法(建立规范)。首先你要实现会议接口,这个实现类就是符合规范的会议;然后在程序中用接口会议的引用指向传入的实现类会议对象(向上转型),制定规范的人不用知道每个会议具体是如何实现的(解耦),直接调用对象的方法即可(运行时多态)。

继承:目的是复用代码扩展新功能。还是上面的例子,如果已经有了一个会议,你不仅想要保留这个会议的内容(复用代码),还想增加新内容比如发奖金(扩展新功能)。这时就可以使用继承,将已有的会议继承,该覆盖的覆盖,并实现定义了发奖金方法的接口。然后在程序中用父类会议的引用指向传入的子类会议对象(向上转型),直接调用对象的方法即可(运行时多态)。


关于接口,我还在知乎上看到一种不错的比喻:


接口就是个招牌。

比如说你今年放假出去杭州旅游,玩了一上午,你也有点饿了,突然看到前面有个店子,上面挂着KFC,然后你就知道今天中饭有着落了。(实现KFC接口的类会被视作KFC

KFC就是接口,我们看到了这个接口,就知道这个店会卖炸鸡腿(实现接口的方法)。

那么为神马我们要去定义一个接口涅,这个店可以直接卖炸鸡腿啊(直接写方法),是的,这个店可以直接卖炸鸡腿,但没有挂KFC的招牌,我们就不能直接简单粗暴的冲进去叫服务员给两个炸鸡腿了。
要么,我们就要进去问,你这里卖不卖炸鸡腿啊,卖不卖汉堡啊,卖不卖圣代啊(这就是反射)。很显然,这样一家家的问实在是非常麻烦(反射性能很差)。

要么,我们就要记住,中山路108号卖炸鸡,黄山路45号卖炸鸡(硬编码),很显然这样我们要记住的很多很多东西(代码量剧增),而且,如果有新的店卖炸鸡腿,我们也不可能知道(不利于扩展)。

顺便说一下,接口分为广义和狭义两个意思:狭义指的是Java中的interface;广义指的就是应用程序接口--API,也就是通过调用某些方法获得应用程序的功能,比方说我们自己写的public方法和第三方库的public方法,都可以视作API。不仅是在程序中调用,在实际开发中的所谓后端数据接口(RESTful API)也可以视作API,其原理就是通过调用Server端程序的表现层方法,获得其需要的功能(俗称的后台接口)。

面试题:

1.接口和抽象类?

答:

1.一个类可以实现多个接口,但只能继承一个抽象类(除非将接口或抽象类的所有抽象方法全都实现,否则就得用abstract修饰)

2. 接口默认使用abstract+public修饰抽象方法

3. 抽象类中可以定义抽象方法和具体方法;接口中可以定义抽象方法、默认方法和静态方法

4. 接口的属性是默认的public static final

5. 抽象类中可以含有静态代码块和静态方法,而接口可以含有静态方法,但不能含有静态代码块。

6. 抽象类可以含有构造方法,接口不能含有构造方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值