Java面向对象笔记 • 【第4章 抽象类和接口】
全部章节 >>>>
本章目录
4.1 抽象类
如何定义图形类计算周长的通用方法?
- 不同的图形子类图形计算周长的方式大相径庭,所以导致Shape类的calcPerimeter()方法无法运用某个固定的计算图形周长的公式。
- 可以将calcPerimeter()方法定义为抽象方法,抽象方法没有具体的方法实现,该方法必须由其继承的子类重写,这样该方法就起到了约束规范的作用,又不影响类最初的设计思路。
4.1.1 抽象方法和抽象类
定义抽象类语法
[访问修饰符] abstract class 类名
定义抽象方法语法
[访问修饰符] abstract 返回类型 方法名([参数列表])
抽象类和抽象方法规则:
一个抽象类中可以不定义抽象方法,但是只要类中有一个抽象方法,则该类一定是抽象类。
抽象类不能被实例化,即不能被new创建一个实例对象。
如果一个子类继承一个抽象类,则子类需要通过覆盖的方式来重写该抽象类中的所有抽象方法。如果子类没有完全重写抽象父类中所有的抽象方法,则子类仍是抽象的。
抽象方法可以与public、protected复合使用,但不能与final、private和static复合使用。
abstract 不能用于修饰属性,不能用于修饰局部变量,也不能用于修饰构造器。
示例:在图形继承关系中使用抽象类和抽象方法
// 抽象类 图形Shape :
public abstract class Shape { // 抽象类 图形
private String color;
// 定义一个计算周长的抽象方法
public abstract double calcPerimeter();
// 定一个返回图形子类型的方法
public abstract String getType();
// 有参构造方法
public Shape(String color){
this.color=color;
System.out.println("---执行了Shape类的构造方法---");
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
// 子类 三角形Triangle :
public class Triangle extends Shape{ //子类 三角形
private double x,y,z; //定义三角形边
public Triangle(String color,double x,double y,double z) {
super(color); //调用父类构造器
this.setSide(x, y, z);
}
public void setSide(double x,double y,double z){//设置三角形三边
if(x>y+z || y>x+z || z>x+y){
System.out.println("三角形两边之和必须大于第三边");
return ;
}
this.x=x, this.y=y,this.z=z;
}
public double calcPerimeter() {//重写父类计算周长方法
return x+y+z;
}
public String getType() {//重写父类获取图形类型方法
return "三角形";
}
}
//子类 圆形Circle :
public class Circle extends Shape { //子类 圆形
private double r;//半径
public Circle(String color,double r) {
super(color);
this.r=r;
}
public double calcPerimeter() {//重写父类计算周长方法
return 2*Math.PI*r;
}
//重写父类获取图形类型方法
public String getType() {
return "圆形";
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
main方法
public static void main(String[] args) { // 测试
Shape triangle=new Triangle("红色", 3, 4, 5);
Shape circle=new Circle("红色", 4);
System.out.println(triangle.getType()+" 周长="+triangle.calcPerimeter());
System.out.println(circle.getType()+" 周长="+circle.calcPerimeter());
}
4.1.2 抽象类的作用
避免子类设计的随意性:
- 抽象类不能被实例化,只能作为父类继承。
- 从多个具有相同特征的类中抽象出一个抽象类,以该抽象类作为其子类的模板。
体现了模板模式的设计理念:
- 抽象类作为多个子类的通用模板。
- 子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
- 编写一个抽象父类,父类提供多个子类的通用方法,并且将一个或多个方法留给其子类实现,这就是一种模板模式。
示例:在速度表应用上使用模板设计模式
// 抽象父类速度表 SpeedMeter ,该抽象类为模板类
public abstract class SpeedMeter { //抽象父类速度表,该抽象类为模板类
private double trunRate; //转速
//将返回车轮半径的方法定义为抽象方法
public abstract double getRedius();
//定义计算速度的通用算法
public double getSpeed(){
//速度=车轮半径*2*π*转速
return 2*3.14*getRedius()*getTrunRate();
}
public double getTrunRate() {
return trunRate;
}
public void setTrunRate(double trunRate) {
this.trunRate = trunRate;
}
}
// 子类汽车速度表 CarSpeedMeter
public class CarSpeedMeter extends SpeedMeter{ //子类汽车速度表
//重写父类的获取半径的方法
public double getRedius() {
return 2.0;
}
public static void main(String[] args) {
//创建CarSpeedMeter对象
CarSpeedMeter csm=new CarSpeedMeter();
csm.setTrunRate(15);//设置转速
System.out.println("当前汽车时速="+csm.getSpeed()+"公里/小时");
}
}
SpeedMeter类中提供了速度表的通用算法,但一些具体的实现细节则推迟到其子类CerSpeedMeter类中实现。这是一种典型的模板模式。
模板模式基本规则:
抽象父类仅定义使用的某些方法,将不能实现的部分抽象成抽象方法,留给其子类实现。
父类中包含需要调用其他依赖的方法,这些被调方法既可以由父类实现,也可以由其子类实现。父类中提供的方法仅定义了一个通用算法,需要具体子类辅助实现。
4.1.3 实践练习
4.2 final修饰符
- final关键字可以用于修饰类、变量和方法。
- final修饰变量时,表示该变量一旦获得了初始值就不可能被改变,final修饰的类不能被继承,final修饰的方法可以被继承但不能被重写。
- final意味着终极。
4.2.1 final成员变量
- 对于final修饰的成员变量而言,一旦赋初始值,就不能被重新赋值。
- final修饰的类属性只能在静态初始化块或声明该属性时指定初始值。
- final修饰的实例属性只能在构造方法或声明该属性时指定初始值。
示例:演示final成员变量使用
4.2.2 final局部变量
- 系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化。因此,使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。
- final修饰的局部变量在定义时没有指定默认值,则应在后面的代码中对该final变量赋初始值,但只能赋值一次,不能重复赋值。
- 如果final修饰的局部变量在定义时已经指定默认值,则后面代码中不能对该变量赋值。
示例:演示final局部变量使用
4.2.3 final方法
- final修饰的方法不可以被重写。
- 如果不允许子类重写父类的某个方法,则可以使用final修饰该方法。
示例:演示final方法使用
public class Bank {
//将该方法定义为final,不允许子类重写该方法
public final void LowerInterestRates(){
System.out.println(“央行按照宏观经济情况进行统一降息,各银行按照国家标准统一执行");
}
}
public class ChinaBank extends Bank{
//如果子类重写父类的fianl()方法,程序在编译时将报错
public final void LowerInterestRates(){
}
}
4.2.4 final类
- final修饰符修饰的类称为最终类,最终类不能有子类。
- final类通常具有固定作用,用于完成某种标准功能。
- final不能被继承以达到不能被修改的目的。
示例:演示final类使用
public final class Bank { // final类
public void LowerInterestRates(){
System.out.println(“央行按照宏观经济情况进行统一降息,各银行按照国家标准统一执行");
}
}
public class ChinaBank extends Bank{ //报错,final类不能有子类
}
}
4.2.5 实践练习
4.3 接口
举例:生活中的接口
Java中的接口同生活中的接口一样,体现的是一种能力。
4.3.1 接口的定义
语法:
[访问修饰符] interface 接口名 extends 父接口1,[父接口2,...]
说明:
接口的访问修饰符可以是public和缺省访问修饰符,如果省略public修饰符,系统默认使用缺省访问修饰符。
接口中只能定义公有的、静态的常量,并且这些常量默认都是公有的、静态的。
接口中的方法只能是公有的抽象方法,并且这些方法默认都是公有的、抽象的。
接口只能继承多个接口,接口不能继承类,也不能实现其他接口。
4.3.2 接口的实现
语法:
[访问修饰符] class 类名 implements 接口1,[接口2,...]
说明:
接口是一种标准的体现。
接口不能用于创建实例,接口的主要作用是在设计程序时对其实现类进行规范和约束。
接口的主要用途就是被实现类实现。
一个类可以实现多个接口,从而实现多继承。
示例:设计一个具有输入功能,并且防水、防尘功能的键盘,以及一个防水、防尘和防盗功能的防盗门
public interface Input { //输入接口
//定义输入的标准,由其实现类实现具体的实现细节
public abstract void input(); // abstract 可省略
}
public interface Function { //功能接口
//接口只能定义常量, 而且必须是静态常量
public static final String DEEP="30米";//防水深度
//防尘指数
int INDEX=5; //接口中的常量默认是公有的、静态、终极的
//防水功能
public abstract void waterproof();
//防尘功能
void dust(); //接口中的方法默认是公有的、抽象的
}
public interface ExtendsFunction extends Function { //扩展功能
void antiTheft(); //防盗
}
public class AntitheftDoor implements ExtendsFunction { //防盗门实现扩展功能接口
//实现防水功能
public void waterproof() {
System.out.println("我是防盗门采用高科技的防水技术,防水深度:"+DEEP);
}
//实现防尘功能
public void dust() {
System.out.println("我是防盗门采用纳米防尘技术防尘,防尘指数:"+INDEX+"颗星");
}
//实现防盗功能
public void antiTheft() {
System.out.println("我是防盗门采用密码匹配防盗技术");
}
}
public class Keyboard implements Function,Input{ //键盘类实现功能接口和输入接口
//实现防水功能
public void waterproof() {
System.out.println("我是键盘采用特殊的密封屏蔽技术实现防水,防水深度:"+DEEP);
}
//实现防尘功能
public void dust() {
System.out.println("我是键盘采用全硅胶材料实现防尘功能,防尘指数:"+INDEX+"颗星 ");
}
//实现Input接口中的输入功能
public void input() {
System.out.println("我是键盘可以将敲击键盘上的数据输入到计算机中");
}
}
public class Tset{
public static void main(String[] args) {
//创建键盘对象
Keyboard keyboard=new Keyboard();
keyboard.dust();//调用键盘的防尘方法
keyboard.waterproof();//调用键盘的防水方法
keyboard.input();//调用输入方法
System.out.println("------------------------------------");
//创建防盗门对象
AntitheftDoor antitheftDoor=new AntitheftDoor();
antitheftDoor.antiTheft();//调用防盗门的防盗方法
antitheftDoor.dust();//调用防盗门的防尘方法
antitheftDoor.waterproof();//调用防盗门的防水方法
}
}
4.3.3 抽象类和接口的区别
相同点:
接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
接口和抽象类都可以包含抽像方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
不同点:
接口中只能包含抽象方法,而抽象类则完全可以包含普通方法。
接口中不能定义静态方法,而抽象类中可以定义静态方法。
接口中只能定义静态常量,不能定义普通变量,或非静态的常量,而抽象类中则可以定义不同的属性,也可以定义静态的属性。
接口中不包含构造器,而抽象类中可以包含构造器,抽象类中的构造器并不用于创建对象,而是让其子类调用这些构造器来完成抽象类的初始化操作。
一个类最多只能有一个直接父类,包括抽象类,而一个类可以实现多个接口。通过实现多个接口可以弥补Java单继承的不足。
4.3.4 实践练习
4.4 接口编程案例
什么是面向接口编程?
面向接口编程就是先把客户的业务逻辑线提取出来作为接口,接口业务的具体实现通过该接口的实现类来完成。
当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件中该接口的实现类就可以完成需求,而不需要改写现有代码,从而减少对系统的影响。
面向接口编程的优点:
降低程序的耦合性。在程序中紧密的联系并不是一件好的事情,因为两种事物之间联系越紧密,更换其中之一的难度就越大。
易于系统的扩展。
易于系统的维护。
4.4.1 接口编程实例
使用面向接口编程实现一个简易的用户管理系统
要求用户按照系统在控制台中的提示信息,做出相应的选择。
系统接收到用户输入的指令后,给出相应的提示信息。
创建dto包,在该包中定义类UserInfo用于封装用户信息。
public class UserInfo { //用户实体类
private String name;
private int age;
private String birthday;
private String address;
//省略属性的setter和getter方法
}
创建dao包,在该包中定义一个维护用户信息的接口UserInfoDao,在该接口中定义3个抽象方法,它们的功能分别是删除用户、更新用户信息和保存用户。
public interface UserInfoDao { //维护用户信息接口
public abstract void deleteUser(UserInfo user);
public abstract void updateUser(UserInfo user);
public abstract void saveUser(UserInfo user);
}
在该dao包中定义一个实现UserInfoDao的用户信息维护UserInfoDaoImpl,该类分别实现接口中所有的抽象方法。
public class UserInfoDaoImpl implements UserInfoDao { //实现用户信息维护接口
public void saveUser(UserInfo user) {
System.out.println("执行新增方法");
System.out.println("姓名:"+ user.getName() +" 年龄:"+ user.getAge() + " 生日:"+ user.getBirthday() + " 家庭地址:"+ user.getAddress());
}
public void updateUser(UserInfo user) {
System.out.println("执行更新方法");
}
public void deleteUser(UserInfo user) {
System.out.println("执行删除操作");
}
}
创建business包,在该包中定义UserInfoAccess类,在该类定义UserInfoDao对象属性,该值为实现UserInfoDao接口的具体对象。
在UserInfoAccess类定义服务方法service()实现主体业务。
public class UserInfoAccess {
private UserInfoDao userInfoDao=new UserInfoDaoImpl();
public void service(){
System.out.println("请选择操作【1】添加【2】修改【3】删除");
Scanner input=new Scanner(System.in);
String state=input.next();
if("1".equals(state)){
userInfoDao.saveUser();
}else if("2".equals(state)){
userInfoDao.updateUser();
}else if("3".equals(state)){
userInfoDao.deleteUser();
}
}
}
public class UserMain{
public static void main(String[] args) {
new UserInfoAccess().service();
}
}
4.4.2 实践练习
总结:
一个抽象类中可以不定义抽象方法,但是只要类中有一个抽象方法,则该类一定是抽象类。
抽象类不能被实例化,只能作为父类继承。
final关键字可以用于修饰类、变量和方法。final修饰变量时,表示该变量一旦获得了初始值就不可能被改变,final修饰的类不能被继承,final修饰的方法可以被继承但不能被重写。
接口中只能定义公有的、静态的常量,并且这些常量默认都是公有的、静态的;接口中的方法只能是公有的抽象方法,并且这些方法默认都是公有的、抽象的。
接口只能继承多个接口,接口不能继承类,也不能实现其他接口。
Java面向对象笔记 • 【第4章 抽象类和接口】的更多相关文章
- java面向对象(三)之抽象类,接口,向上转型
java类 java类分为普通类和抽象类,接口,上一节我大概讲了java类的一般格式,今天将抽象类和接口.同时讲一下它们是怎样存储的. 最重要的是理解为什么要有抽象和接口,这样学下来你猜不会迷茫,才能 ...
- JAVA学习笔记(3)—— 抽象类与接口
1. Java 抽象类 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类. 抽象类 ...
- [Effective Java 读书笔记] 第三章类和接口 第十八--十九条
十八条 接口优于抽象类 接口的特点: 1.一个类可以实现多个接口,不能继承多个类(抽象类) 2.接口不能有具体的方法实现,只定义标准类型 骨架类: 即实现一个abstract类来实现接口,提供给其他类 ...
- [Effective Java 读书笔记] 第三章类和接口 第二十三-- ??条
第二十三条 请不要再新代码中使用原生态类型 1 使用原生态类型,就失去了泛型在安全性和表述性方面的所有优势,所以新代码中不要使用原生态类型 2 List<String>可以传递给List作 ...
- [Effective Java 读书笔记] 第三章类和接口 第二十-二十一条
第二十条 用函数对象表示策略 函数指针(JAVA的函数指针,是指使用对象的引用来作为参数,传递给另一个对象的方法)主要用来实现策略模式,为了在JAVA中实现这种模式,要申明一个接口来表示该策略,并为每 ...
- [Effective Java 读书笔记] 第三章类和接口 第十三 -- 十四条
第十三条 使类和成员的可访问性最小化 总得来说,我们应该尽量将成员的访问范围限制到最小!有利于解耦,开发.测试和优化都能够更加独立. 对于成员(域,方法,嵌套类和嵌套接口),有四种可能的访问级别,访问 ...
- [Effective Java 读书笔记] 第三章类和接口 第十六条
第十六条 复合优先于继承 如果不确定B和A的关系是,is-a的关系,B确实也是A,那么久不应该使用B继承A,否则会暴露实现细节, 你的实现都会限制在原始的实现上. 书中举的第一个例子,实现了一个类ex ...
- 20145330《Java学习笔记》第一章课后练习8知识总结以及IDEA初次尝试
20145330<Java学习笔记>第一章课后练习8知识总结以及IDEA初次尝试 题目: 如果C:\workspace\Hello\src中有Main.java如下: package cc ...
- Java面向对象程序设计第14章3-8和第15章6
Java面向对象程序设计第14章3-8和第15章6 3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串. import java.io.*; public class tes ...
- Java面向对象程序设计第9章1-9
Java面向对象程序设计第9章1-9 1. 线程和进程的联系和区别是什么? 联系: 一个进程可以包括多个线程. 区别: 进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统 ...
随机推荐
- git提交指定文件
1. 用git add 命令添加第一个commit需要的文件 git add file1 git add file2 2. 隐藏其他修改,git stash 的参数中 -k 开关告诉仓库保持文件的完整 ...
- window ntp服务
一.确定服务端和客户端处于同一网段,能相互 Ping 通. 二.服务器端(Server)配置 1.选择一台服务器(Windows 系统)作为时间同步服务器: 2.Win + R (运行 cmd 命令行 ...
- shell条件测试语句实例-测试apache是否开启
终于理解了shell条件测试语句"!="和"-n"的用法区别,于是有了如下的shell脚本,做为练习. 第一种方法:测试apache是否开启?字符串测试 #!/ ...
- Activiti工作流引擎使用详解(一)
一.IDEA安装activiti插件 在插件库中查找actiBPM,安装该插件,如果找不到该插件,请到插件库中下载该包手动安装,插件地址 http://plugins.jetbrains.com/pl ...
- maven打包插件详解
maven-jar-plugin插件的使用及详解 该插件的xml配置及详解如下: <plugin> <groupId>org.apache.maven.plugins</ ...
- JDK的简介,卸载和安装过程
JDK的简介,卸载和安装过程 JDK JRE JVM JDK:Java Development Kit JRE:Java Runtime Environment JVM:Java Virtual Ma ...
- SpringCloud技术涵盖简介
SpringCloud是微服务架构的集大成者,云计算最佳业务实践. 我们平常使用的Spring和他们的关系,对Spring,springboot , SpringCloud 的 概念区分,上图: Sp ...
- ERROR: Command errored out with exit status 1:安装pip3 install --user pyecharts==0.5.11失败问题总结
一.前言:最近在学习pyecharts学习到Grid时候发现代码无法运行了,经过在网上查找资料说是pyecharts版本不适配了,之前的版本是 pip install pyecharts==0.1.9 ...
- (转)synchronize线程同步例子
在CSDN开了博客后,一直也没在上面发布过文章,直到前一段时间与一位前辈的对话,才发现技术博客的重要,立志要把CSDN的博客建好.但一直没有找到好的开篇的主题,今天再看JAVA线程互斥.同步的时候又有 ...
- Dom 解析XML
xml文件 <?xml version="1.0" encoding="UTF-8"?><data> <book id=&q ...