抽象类

引出

问题:

​ 父类方法有时候具有不确定性

小结:

当父类的某些方法,需要声明,但是又不确定如何实现

时,可以将其声明为抽象方法,那么这个类就是抽象类

例子:

public class Abstract01 {
public static void main(String[] args) { }
} abstract class Animal {
private String name; public Animal(String name) {
this.name = name;
}
//思考:这里eat 这里你实现了,其实没有什么意义
//即: 父类方法不确定性的问题
//===> 考虑将该方法设计为抽象(abstract)方法
//===> 所谓抽象方法就是没有实现的方法
//===> 所谓没有实现就是指,没有方法体
//===> 当一个类中存在抽象方法时,需要将该类声明为abstract类
//===> 一般来说,抽象类会被继承,有其子类来实现抽象方法.
// public void eat() {
// System.out.println("这是一个动物,但是不知道吃什么..");
// }
public abstract void eat() ;
}

介绍

1)用abstract关键字来修饰一个类时,这个类就叫抽象类

​ 访问修饰符abstract类名{

​ }

2)用abstract关键字来修饰一个方法时,这个方法就是抽象方法

​ 访问修饰符 abstract 返回类型 方法名(参数列 表);//没有方法体

3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()

4)抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多

注意事项

1)抽象类不能被实例化

public class AbstractDetail01 {
public static void main(String[] args) {
//抽象类,不能被实例化
//new A();
}
}
abstract class A { }

2)抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法

//抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法,还可以有实现的方法。
abstract class A {
public void hi() {
System.out.println("hi");
}
}

3)一旦类包含了abstract方法,则这个类必须声明为abstract【反之不一定成立】

//一旦类包含了abstract方法,则这个类必须声明为abstract
abstract class B {
public abstract void hi();
}

4)abstract只能修饰类和方法,不能修饰属性和其它的。

//abstract 只能修饰类和方法,不能修饰属性和其它的
class C {
// public abstract int n1 = 1;
}

5)抽象类可以有任意成员【因为抽象类本质还是类】,比如:非抽象方法、构造器、静态属性等等

//抽象类的本质还是类,所以可以有类的各种成员
abstract class D {
public int n1 = 10;
public static String name = "jk";
public void hi() {
System.out.println("hi");
}
public abstract void hello();
public static void ok() {
System.out.println("ok");
}
}

6)抽象方法不能有主体,即不能实现。

abstract void aaa()//{}

7)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
abstract class E {
public abstract void hi();
}
abstract class F extends E { }
class G extends E {
@Override
public void hi() { //这里相等于G子类实现了父类E的抽象方法,所谓实现方法,就是有方法体
}
}

8)抽象方法不能使用private、final和static来修

饰,因为这些关键字都是和重写相违背的

抽象模板模式

需求

1)有多个类,完成不同的任务job

2)要求能够统计各自完成任务的时间

3)请编程实现

直觉

先用最容易想到的方法

例如有TestTemplate、AA、BB三个类

在AA和BB中分别定义两种计算任务(比如1加到100和1乘到100)

以AA为例,那么其中会有一个job方法

该方法定义了具体的计算任务,并调用诸如System.currentTimeMillis()这样的模块计算运行时间

public void job() {
//得到开始的时间
long start = System.currentTimeMillis(;long num = 0;
for (long i = 1; i <= 800000; i++) {
num += i;
}
//得的结束的时间
long end = System.currentTimeMillis(;
System.out.println("执行时间"+(end - start));
}

BB同理

问题

按上面的思路,AA和BB都会有一个job方法,里面计算时间的代码是重复的【重复点1】

这个好办,把这些代码抽象为一个父类即可,该父类中有一个例如calculateTime()的方法,专门计算运行时间

那么这个方法在该父类中应该类似下面的形式

public void calculateTime(){//实现一个方法去调用job
long start = System.currentTimeMillis();
job();//触发动态绑定机制,是aa调用就跳到AA,bb同理
//获取结束时间
long end = System.currentTimeMillis();
System.out.println("AA执行时间:"+(end-start));
}

现在又有一个问题,job()是AA和BB都有的方法,那么抽象到父类中,父类也肯定有一个job()

但是AA和BB中,job方法内的计算任务是不一样的,他们有可能都重写父类的方法,也可能不写

无论是哪种情况,父类都必须实例化一个默认的job()方法,这又造成代码的冗余【重复点2】

那么抽象类就有用了

将父类设计为一个抽象类,那么再写一个抽象方法job,抽象父类无需初始化它,子类用的时候再各自重写即可

优雅

解决

设计一个抽象类(Template),能完成如下功能:

1)编写方法calculateTime().可以计算某段代码的耗时时间

2)编写抽象方法job()

3)编写一个子类Sub,继承抽象类Template,并实现job方法。

4)编写一个测试类TestTemplate,看看是否好用。

抽象类Template

abstract public class Template {//抽象类-模板设计模式

    public abstract void job();//抽象方法

    public void calculateTime(){//实现一个方法去调用job
long start = System.currentTimeMillis();
job();//触发动态绑定机制,是aa调用就跳到AA,bb同理
//获取结束时间
long end = System.currentTimeMillis();
System.out.println("AA执行时间:"+(end-start));
}
}

子类AA

public class AA extends Template{
//计算任务
//1加到10000
public void job(){//实现父类Template的抽象方法job
int num = 0;
for (int i = 0; i <= 800000; i++) {
num += i;
}
}
}

子类BB

public class BB extends Template{
//计算任务
public void job(){
int num = 0;
for (int i = 0; i <= 8000000; i++) {
num *= i;
}
}
}

测试

public class TestTemplate {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime(); BB bb = new BB();
bb.calculateTime();
}
}
=================================================
AA执行时间:2
BB执行时间:15

接口

定义

接口就是给出一些没有实现的方法,封装到一起,到某个

类要使用的时候,在根据具体情况把这些方法写出来。

语法

interface 接口名{

//属性
//方法
// 1.抽象方法
// 2.默认实现方法
// 3.静态方法 }
class 类名 implements 接口{
自己属性;
自己方法;
必须实现的接口的抽象方法; }

小结:

1.在Jdk7.0前,接口里的所有方法都没有方法体。

2 Jdk8.0后接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。

接口初体验

例如,在实际开发中,项目经理定义一些接口,由程序员去具体实现。【假设需求是连接数据库】

接口类
public interface DBInterface { //项目经理负责写的

    public void connect();//连接方法
public void close();//关闭连接
}
MySQL类

具体去实现项目经理定义的接口

//假设这是A程序员的工作
public class MysqlDB implements DBInterface {
@Override
public void connect() {//改一点名字都不行,必须与接口定义的一样
System.out.println("连接mysql");
} @Override
public void close() {
System.out.println("关闭mysql");
}
}
Oracle类
//假设这是B程序员的工作,连接Oracle
public class OracleDB implements DBInterface{ @Override
public void connect() {
System.out.println("连接oracle");
} @Override
public void close() {
System.out.println("关闭oracle");
}
}
使用
public class Interface03 {
public static void main(String[] args) { MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
} public static void t(DBInterface db) {
db.connect();
db.close();
}
}
=====================================
连接mysql
关闭mysql
连接oracle
关闭oracle
总结

在开发中使用接口可以统一程序员的工作成果,提高效率。

细节与注意事项

1)接口不能被实例化。

  • 因为接口本身是希望别的类来实现它,然后再创建实现了接口的具体类的实例
  • 因此接口不能实例化

2)接口中所有的方法是public方法。接口中抽象方法可以不用abstract修饰

3)一个普通类实现接口,就必须将该接口的所有方法都实现。

4)抽象类实现接口,可以不用实现接口的方法。

5)一个类同时可以实现多个接口

//一个类同时可以实现多个接口
class Pig implements IB,IC {
@Override
public void hi() {
}
@Override
public void say() {
}
}

6)接口中的属性只能是final的,而且是public

static final修饰符。

​ 比如:int a=1;

​ 实际上是public static final int a=1;(必须初始

7)接口中属性的访向形式:

接口名.属性名

8)一个接口不能继承其它的类,但是可以继承多个别的接口

//接口不能继承其它的类,但是可以继承多个别的接口
interface ID extends IB,IC {
}

9)接口的修饰符只能是public和默认,这点和类的修饰

符是一样的。

小练习

public class InterfaceExercise01 {
public static void main(String[] args) {
B b = new B();//ok
System.out.println(b.a); //b是对象实例,访问一个public的属性a,没问题,23
System.out.println(A.a); //接口.static类型的属性,没问题,23
System.out.println(B.a); //B实现了A接口,因此可以使用接口中的属性,没问题,23
}
} interface A {
int a = 23; //接口中的属性等价于 public static final int a = 23;
} class B implements A {//A接口没有抽象方法,因此此处语法正确
}

接口与继承

简单来说,接口是对Java单继承机制的一种补充

看下面的例子

LittleMonkey通过继承父类Monkey得到了climbing()方法

再通过接口,实现了swimming()和flying()。无形之中拓展了LittleMonkey的功能

public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey wuKong = new LittleMonkey("悟空");
wuKong.climbing();
wuKong.swimming();
wuKong.flying();
}
} //猴子
class Monkey {
private String name; public Monkey(String name) {
this.name = name;
}
public void climbing() {
System.out.println(name + " 会爬树...");
} public String getName() {
return name;
}
} //接口
interface Fishable {
void swimming();
}
interface Birdable {
void flying();
} //继承
//小结: 当子类继承了父类,就自动的拥有父类的功能
// 如果子类需要扩展功能,可以通过实现接口的方式扩展.
// 可以理解 实现接口 是 对java 单继承机制的一种补充.
class LittleMonkey extends Monkey implements Fishable,Birdable { public LittleMonkey(String name) {
super(name);
} @Override
public void swimming() {
System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳...");
} @Override
public void flying() {
System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔...");
}
}
  • 接口和继承解决的问题不同

    继承的价值主要在于:解决代码的复用性和可维护性。

    接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。
  • 接口比继承更加灵活

    接口比继承更加灵活,继承是满足 is - a 的关系【如猫是动物】,

​ 而接口只需满足 like - a 的关系【如猴子像人】接口在一定程度上实现代码解耦

接口多态特性

多态数组

定义一个接口以及对应的实现接口的类

interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println("手机可以打电话...");
} @Override
public void work() {
System.out.println("手机工作中...");
}
}
class Camera_ implements Usb { @Override
public void work() {
System.out.println("相机工作中...");
}
}

在main方法中

public class InterfacePolyArr {
public static void main(String[] args) { //多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
/*
给Usb数组中,存放 Phone 和 相机对象,Phone类还有一个特有的方法call(),
请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,
还需要调用Phone 特有方法 call
*/
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定机制
//和前面一样,我们仍然需要进行类型的向下转型,即类型判断
//因为接口类型数组中有不同的类型【Phone和Camera】
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
多态参数
public class InterfacePolyParameter {
public static void main(String[] args) { //接口的多态体现
//接口类型的变量 if01 可以指向 实现了IF接口类的对象实例
IF if01 = new Monster();//IF if01 = new IF();是错误的
if01 = new Car(); //继承体现的多态
//父类类型的变量 a 可以指向 继承AAA的子类的对象实例
AAA a = new BBB();
a = new CCC();
}
} interface IF {}
class Monster implements IF{}
class Car implements IF{} class AAA { }
class BBB extends AAA {}
class CCC extends AAA {}

接口多态传递

展示多态传递现象

/**
* 演示多态的传递
*/
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口的类的对象实例
IG ig = new Teacher();
//如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
//那么,实际上就相当于 Teacher 类也实现了 IH接口.
//这就是所谓的 接口多态传递现象.
IH ih = new Teacher();
}
} interface IH {
void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
@Override
public void hi() {
}
}

接口练习题

代码有没有错误,有错误就改,改好后,看输出?

interface A{
int x = 0; }//等价public static final int x=0 class B{
int x = 1;} class C extends B implements A {
public void pX(){
System.out.printin(x);//没有指明是父类的x还是接口的x,编译器会报错
public static void main(String[] args) {
new C().pX();
}
}

修改后

public class InterfaceExercise02 {
public static void main(String[] args) { }
} interface A {
int x = 0;
} //想到 等价 public static final int x = 0; class B {
int x = 1;
} //普通属性 class C extends B implements A {
public void pX() {
//System.out.println(x); //错误,原因不明确x
//可以明确的指定x
//访问接口的 x 就使用 A.x
//访问父类的 x 就使用 super.x
System.out.println(A.x + " " + super.x);
} public static void main(String[] args) {
new C().pX();
}
}

至此,类的五大成员已经学习了4个

即:

  • 属性
  • 方法
  • 构造器
  • 代码块

还差一个难点:**内部类

【Java复健指南12】OOP高级03-抽象类与接口的更多相关文章

  1. Java第五次作业--面向对象高级特性(抽象类与接口)

    Java第五次作业--面向对象高级特性(抽象类与接口) (一)学习总结 1.在上周完成的思维导图基础上,补充本周的学习内容,对Java面向对象编程的知识点做一个全面的总结. 2.汽车租赁公司,出租汽车 ...

  2. 【Java复健指南09】项目练习全解--房屋出租系统

    一个基于文本界面的综合练习,主要用于串联和回忆知识点,比较简单 各个界面的设计样式 主菜单 =============房屋出租系统菜单============ 1 新 增 房 源 2 查 找 房 屋 ...

  3. 【Java复健指南15】链表LinkedList及其说明

    链表LinkedList by Java 之前有写过一些记录(引用),但是忘了乱了,现在重新梳理一遍 链表是Java中List接口的一种实现 定义(引用) 链表(linked list)是一种物理存储 ...

  4. Java基础学习笔记十二 类、抽象类、接口作为方法参数和返回值以及常用API

    不同修饰符使用细节 常用来修饰类.方法.变量的修饰符 public 权限修饰符,公共访问, 类,方法,成员变量 protected 权限修饰符,受保护访问, 方法,成员变量 默认什么也不写 也是一种权 ...

  5. Java C++ 比较 – 虚函数、抽象函数、抽象类、接口

    [转自]原文 Java – 虚函数.抽象函数.抽象类.接口 1. Java虚函数 虚函数的存在是为了多态. C++中普通成员函数加上virtual关键字就成为虚函数 Java中其实没有虚函数的概念,它 ...

  6. Java学习日记基础篇(六)—— 抽象类、接口、final

    抽象类 为什么要有抽象类? 因为父类方法有不确定性,我们在Animal中定义了一个方法,但是它会被子类的方法覆盖掉,我们就不知道这个方法原本是做什么的 public class test1 { pub ...

  7. 面向对象 OOP中的抽象类,接口以及多态

    [抽象类与抽象方法] 1.什么是抽象方法? 没有方法体{}的方法,必须使用abstract关键字修饰,这样的方法,我们称之为抽象方法. abstract function say() 2.什么是抽象类 ...

  8. Java(20)参数传递之类名、抽象类、接口

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201632.html 博客主页:https://www.cnblogs.com/testero ...

  9. Java编程的逻辑 (20) - 为什么要有抽象类?

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  10. java面向对象(三)之抽象类,接口,向上转型

    java类 java类分为普通类和抽象类,接口,上一节我大概讲了java类的一般格式,今天将抽象类和接口.同时讲一下它们是怎样存储的. 最重要的是理解为什么要有抽象和接口,这样学下来你猜不会迷茫,才能 ...

随机推荐

  1. [转帖]宁可信鬼,也不信 iowait 这张嘴!

    https://zhuanlan.zhihu.com/p/407333624 原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. 我们经常遇到iowait这个名词,在top命 ...

  2. OpenEuler2203使用rpm方式安装Oracle19c的过程

    OpenEuler2203使用rpm方式安装Oracle19c的过程 安装介质 oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm oracle-d ...

  3. React中受控组件与非受控组件的使用

    受控组件 受控组件的步骤: 1.在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源) 2.给表单元素绑定change事件,将表单元素的值设置为state的值(这样就可以控制表 ...

  4. RN 表单TextInput的用法

    你要注意安卓和苹果是不同的哈 有些属性是苹果才有的,有些是安卓独有的 有些两个都有哈 // 边框要设置两个属性哈 borderColor: 'pink', marginTop: 10, 具体看地址 h ...

  5. golang实现的 https 协议的四层代理和七层代理

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 四层代理 在 tcp 这一层转发很简单. http 协议是 ...

  6. 【一】LaTeX的安装和使用、安装TeXstudio、中文界面输出设置

    安装方法一:(推荐) 下载链接·:http://tug.org/texlive/acquire-netinstall.html 下载zip,然后运行Windows批处理脚本(install-tl-wi ...

  7. 在.NET Core下的机器学习--学习笔记

    摘要 .NET Core 在机器学习的应用场景,除了 ML .NET 还会介绍一个非常棒的開源技術 TensorFlow .NET , Keras .NET. 讲师介绍 本课内容 人工智能介绍 ML ...

  8. 【简写MyBatis】01-简单映射器

    前言 新开一个坑,为了学习一下MyBatis的源码,写代码是次要的,主要为了吸收一下其中的思想和手法. 目的 关联对象接口和映射类的问题,把 DAO 接口使用代理类,包装映射操作. 知识点 动态代理 ...

  9. NC15532 Happy Running

    题目链接 题目 题目描述 Happy Running, an application for runners, is very popular in CHD. In order to lose wei ...

  10. NC22494 选点

    题目链接 题目 题目描述 有一棵n个节点的二叉树,1为根节点,每个节点有一个值wi.现在要选出尽量多的点. 对于任意一棵子树,都要满足: 如果选了根节点的话,在这棵子树内选的其他的点都要比根节点的值大 ...