抽象类

什么是抽象类?

  • 在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。
  • abstract如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类。

抽象类的注意事项、特点

  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
  • 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
  • 抽象类最主要的特点:抽象类不能使用new关键字来创建对象,它仅作为一种特殊的父类,让子类继承并实现。
  • 子类继承抽象类,那么就必须要重写完抽象类的全部抽象方法,否则该子类也要定义为抽象类。

案例:

父类:
public abstract class A {
// 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
private String name;
private int age;
public A() { }
public A(String name, int age) {
this.name = name;
this.age = age;
}
// 抽象方法:abstract修饰,只能有方法声明,没有方法体。
public abstract void go(); public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} 子类:
// 一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须声明为抽象类。
public class B extends A{ @Override
public void go() {
}
} main方法:
// 目标:认识抽象类,搞清楚它的特点
public class Test {
public static void main(String[] args) {
// 抽象类的核心特点:不能被创建对象
// A a = new A(); // 报错
B b = new B();
b.go();
}
}

抽象类的场景与好处

  • 父类知道每个子类都要做某个行为,但每个子类要做的情况都不一样,父类就定义成抽象类方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好的支持多态。

案例:

父类:
public abstract class Animal {
private String name; // 抽象类的好处:1. 方法体无意义时可以不写(简化代码)
// 2. 强制子类重写方法(更好的支持了多态)
public abstract void cry(); public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
} 子类:
public class Cat extends Animal { @Override
public void cry() {
System.out.println("猫咪,喵喵喵的叫~");
}
} public class Dog extends Animal{
@Override
public void cry() {
System.out.println("狗,汪汪汪的叫~");
}
} 测试:
//目标:搞清楚抽象类的应用场景
public class Test {
public static void main(String[] args) {
Animal a = new Cat();
a.cry();
Animal b = new Dog();
b.cry();
}
}
猫咪,喵喵喵的叫~
狗,汪汪汪的叫~

抽象类的常见应用场景:模板方法设计模式

模板方法设计模式解决了什么问题?

  • 解决方法中存在重复代码的问题。


模板方法设计模式的写法

  1. 定义一个抽象类
  2. 在里面定义两个方法
  3. 一个是模板方法:把相同代码放到里面去。
  4. 一个是抽象方法:具体实现交给子类完成。
  • 建议使用final关键字来修饰模板方法,为什么?

    1. 模板方法是给对象直接使用的,不能被子类重写。
    2. 一旦子类重写了模板方法,模板方法就失效了。

案例:

目标:完成学生和老师写作文的功能

写作文的统一步骤:

  1. 第一步,写标题
  2. 第二步,写正文,但是内容各不相同
  3. 第三步,写结尾
抽象类:
public abstract class Person {
// 把它设计成模板方法
public final void writeArticle() {
System.out.println("写标题");
System.out.println("第一段内容相同");
// 每个子类都是要写正文的,但是每个子类写的情况是不一样的,我们就可以把正文的书写定义成抽象方法
// 具体的实现交给子类来写
writeBoay();
System.out.println("结尾是相同的");
} public abstract void writeBoay();
}
子类:
public class Student extends Person{
@Override
public void writeBoay() {
System.out.println("我的正文是这样的...");
}
} public class Teacher extends Person{
@Override
public void writeBoay() {
System.out.println("我的正文很优雅是这样的...");
}
} 测试方法:
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.writeArticle(); Teacher t = new Teacher();
t.writeArticle();
}
} 输出结果:
写标题
第一段内容相同
我的正文是这样的...
结尾是相同的
写标题
第一段内容相同
我的正文很优雅是这样的...
结尾是相同的
  • 注意:final关键字和abstract是互斥的。

接口

  • Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构,接口。


注意

  • 接口不能创建对象。接口是用来被类实现(implements)的,实现接口的类称为实现类
  • 这个实现可以理解为继承,继承接口类。

案例:

接口类A:
// 接口
// 1.8版本之前,接口中只能定义常量和抽象方法
public interface A {
// 1. 常量:接口中定义常量可以省略public static final,不写,默认会加上
// public static final String SCHOOL_NAME = "霍格沃兹";
String SCHOOL_NAME = "霍格沃兹"; // 2. 抽象方法: 接口中定义抽象方法可以省略public abstract不写,默认会加上
// public abstract void run();
void run();
void go();
}
接口类C:
public interface C {
void eat();
} 实现类:
// 实现类,相当于继承了接口的子类
// 实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须是抽象类。
public class BImpl implements A,C{
@Override
public void run() {
System.out.println("run");
} @Override
public void go() {
System.out.println("go");
} @Override
public void eat() {
System.out.println("eat");
}
} 测试:
//目标:认识接口,搞清楚接口的特点。
public class Test {
public static void main(String[] args) {
// 接口最需要注意的特点:不能创建对象
// A a = new A(); // 报错:Cannot instantiate the type A
BImpl b = new BImpl();
b.run();
b.go();
b.eat();
}
}

总结:

  1. 1.8版本之前,接口中只能定义常量和抽象方法
  2. 常量:接口中定义常量可以省略public static final,不写,默认会加上
  3. 抽象方法: 接口中定义抽象方法可以省略public abstract不写,默认会加上
  4. 接口最需要注意的特点:不能创建对象
  5. 实现类,相当于子类。实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须是抽象类。

接口的好处(重点)

  • 弥补了类单继承的不足,一个类同事可以实现多个接口。
  • 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。(更利于程序的解耦合)

案例:

父类:
public class Person {}
子类:
public class Student extends Person implements Driver, Doctor{}
public class Teacher implements Driver, Doctor{}
接口:
public interface Driver {}
public interface Doctor {}
测试方法:
// 目标:理解接口的好处
public class Test {
public static void main(String[] args) {
// 1.弥补了类单继承的不足,接口让一个对象拥有更多角色,更多的能力。
Person p = new Student();
Driver d = new Student();
Doctor doc = new Student();
// 2.面向接口编程是软件开发中目前很流行的开发模式,能更灵活的实现解耦合。
Driver d1 = new Teacher(); // 多态
Doctor doc1 = new Teacher(); // 多态
}
} 注意:案例仅辅助理解接口的优势。

接口的应用案例:班级学生信息管理模块的开发

学生类:
public class Student {
private String name;
private char sex;
private double score; public Student() {
} public Student(String name, char sex, double score) {
this.name = name;
this.sex = sex;
this.score = score;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public char getSex() {
return sex;
} public void setSex(char sex) {
this.sex = sex;
} public double getScore() {
return score;
} public void setScore(double score) {
this.score = score;
}
}
接口类:
public interface ClassData {
void printAllStudentInfos();
double getAverageScore();
} 实现类1:
// 第一套实现类
public class ClassDataImpl1 implements ClassData{
private ArrayList<Student> students; public ClassDataImpl1(ArrayList<Student> students) {
this.students = students;
}
@Override
public void printAllStudentInfos() {
System.out.println("展示所有学生信息:");
for (int i = 0; i < students.size(); i++) {
System.out.println("姓名:" + students.get(i).getName() +
",性别:" + (students.get(i).getSex() == '男' ? "男" : "女") +
",成绩:" + students.get(i).getScore());
}
} @Override
public double getAverageScore() {
double sum = 0;
System.out.println("展示所有学生的平均成绩");
for (int i = 0; i < students.size(); i++) {
sum += students.get(i).getScore();
}
return sum / students.size();
}
} 实现类2:
public class ClassDataImpl2 implements ClassData {
private ArrayList<Student> students; public ClassDataImpl2(ArrayList<Student> students) {
this.students = students;
}
@Override
public void printAllStudentInfos() {
int count = 0;
System.out.println("展示所有学生信息:");
for (int i = 0; i < students.size(); i++) {
System.out.println("姓名:" + students.get(i).getName() +
",性别:" + (students.get(i).getSex() == '男' ? "男" : "女") +
",成绩:" + students.get(i).getScore()); if(students.get(i).getSex() =='男')count ++;
}
System.out.println("男生人数:" + count);
System.out.println("女生人数:" + (students.size() - count));
} @Override
public double getAverageScore() {
double sum = 0;
double min = students.get(0).getScore();
double max = students.get(0).getScore(); for (int i = 0; i < students.size(); i++) {
sum += students.get(i).getScore(); if(max < students.get(i).getScore())
max = students.get(i).getScore(); if(min > students.get(i).getScore())
min = students.get(i).getScore();
} System.out.println("最高成绩:" + max);
System.out.println("最低成绩:" + min);
System.out.println("展示所有学生的平均成绩");
return (sum - max - min) / (students.size() - 2);
}
} 测试:
// 目标:实现班级学生管理系统
/*
* 1. 每个学生是一个对象,所以先定义学生类,用于创建学生对象,封装学生数据。
* 2. 定义接口:ClassData
* 3. 定义两套实现类,来分别处理,以便解耦合。
* */
public class Test {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("张三", '男', 90));
list.add(new Student("李四", '女', 80));
list.add(new Student("王五", '男', 70));
list.add(new Student("赵六", '女', 75));
list.add(new Student("王二", '男', 85));
// 多态:父类引用指向子类对象
//ClassData data = new ClassDataImpl1(list);
ClassData data = new ClassDataImpl2(list);
data.printAllStudentInfos();
System.out.println(data.getAverageScore());
}
}

接口的多继承

  • 一个接口可以同时继承多个接口

接口多继承的作用

  • 便于实现类去实现。

案例:

// 目标:接口的多继承
public class Test {
public static void main(String[] args) {
// 类与类是单继承的,一个类只能直接继承一个父类
// 类与接口是多实现的,一个类可以同时实现多个接口 }
}
// 接口的多继承可以让实现类只实现一个接口,相当于实现了很多个接口
class D implements A{
@Override
public void a() {
System.out.println("a方法");
} @Override
public void b() {
System.out.println("b方法");
} @Override
public void c() {
System.out.println("c方法");
}
} // 接口与接口是多继承的,一个接口可以同时继承多个接口
interface A extends B,C{
void a();
} interface B{
void b();
} interface C{
void c();
}

总结:

  • 类与类是单继承的,一个类只能直接继承一个父类
  • 类与接口是多实现的,一个类可以同时实现多个接口
  • 接口与接口是多继承的,一个接口可以同时继承多个接口

JDK8开始,接口中新增了三种形式的方法

  1. 默认方法
  • 默认方法(也就是普通方法):必须用default修饰,它有方法体
  • 默认会用public修饰
  • 必须用接口的实现类的对象来调用
  1. 私有方法
  • 私有方法(私有的实例方法),JDK9开始有的
  • 只能在当前接口内部的默认方法或者私有方法中调用

3.静态方法

  • 默认会用public修饰
  • 接口的静态方法,必须用接口名本身调用

JDK8开始为什么要新增这三种方法?

  • 增强了接口的能力,更便于项目的拓展和维护。

** 接口使用的注意事项**

  1. 一个接口继承多个接口,如果多个接口中存在方法签名冲突。则此时不支持多继承。
  2. 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
  3. 一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
  4. 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

    案例:
public class Test {
public static void main(String[] args) {
// Cat c = new Cat();
// c.run();
// c.test();
}
} // 1. 一个接口继承多个接口,如果多个接口中存在方法签名冲突。则此时不支持多继承。
/*
interface A1{
String run();
}
interface B1{
void run();
}
interface C1 extends A1,B1{}
*/
// 2. 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
/*
interface A2{
String run();
}
interface B2{
void run();
}
class C2 implements A2,B2{}
*/
// 3. 一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
/*
class Animal{
public void run(){
System.out.println("动物跑的贼快~");
}
}
interface Go{
default void run(){
System.out.println("跑的贼快~");
}
}
class Cat extends Animal implements Go{
public void test(){
run();
Go.super.run();// 这种方式会调用接口的默认方法
}
}
*/
// 4. 一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
interface A3{
default void run(){
System.out.println("A3 run");
}
}
interface B3{
default void run(){
System.out.println("B3 run");
}
}
class C3 implements A3,B3{ @Override
public void run() {
//A3.super.run();
//B3.super.run();
System.out.println("C3 run");
}
}

14Java基础之抽象类、接口的更多相关文章

  1. 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait

    [源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...

  2. 程序猿的日常——Java基础之抽象类与接口、枚举、泛型

    再次回顾这些基础内容,发现自己理解的又多了一点.对于一些之前很模糊的概念,渐渐的清晰起来. 抽象类与接口 抽象类通常是描述一些对象的通用方法和属性,并且默认实现一些功能,它不能被实例化.接口仅仅是描述 ...

  3. Java基础之抽象类与接口

    Java基础之抽象类与接口 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的时候 ...

  4. java基础之抽象类与接口的形式参数和返回值

    抽象类与接口形式参数和返回值问题 1.形参问题 /* 1.形式参数: 基本类型(太简单,不是我今天要讲解的) 引用类型 (1)类名:(匿名对象的时候其实我们已经讲过了) 需要的是该类的对象 (2)抽象 ...

  5. 3、java基础:抽象类与接口的区别

    抽象类 我们都知道在面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的.如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样 ...

  6. [.net 面向对象编程基础] (15) 抽象类

    [.net 面向对象编程基础] (15) 抽象类 前面我们已经使用到了虚方法(使用 Virtual修饰符)和抽象类及抽象方法(使用abstract修饰符)我们在多态一节中说到要实现类成员的重写必须定义 ...

  7. “全栈2019”Java第一百零六章:匿名内部类与抽象类接口注意事项

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. 面向对象 继承 抽象类 接口 static 权限修饰符

    Day01 面向对象 继承 抽象类 接口 static 1.匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量. 2.类的继承是指在一个现有类的基础上去构建一个新的类,构建出 ...

  9. 13. 抽象类 & 接口

    一.抽象类 // 抽象类Shape public abstract class Shape { // 1. 成员变量 private String color; // 2. 初始化块 { System ...

  10. 《Java基础——抽象与接口》

    Java基础--抽象与接口       一.抽象: 规则: 关键字 abstract 修饰的类称为抽象类. 子类通过关键字extends实现继承. 关键字 abstract 修饰的方法称为抽象方法,抽 ...

随机推荐

  1. Linux内核中断irq.h头文件找不到的问题

    头文件 在vscode中,进行tasklet和work中断实验的时候,对于包含的头文件如下两个一直爆红: #include <linux/irq.h> #include <linux ...

  2. 卢卡斯(lucas)定理

    对于质数 \(p\),有 \[{\Large \begin{aligned} & \binom{n}{m} \equiv \binom{\left \lfloor n/p \right \rf ...

  3. 【晴神宝典刷题路】codeup+pat 题解索引(更新ing

    记录一下每天的成果,看多久能刷完伐 c2 c/c++快速入门 <算法笔记>2.3小节--C/C++快速入门->选择结构 习题4-10-1 奖金计算 <算法笔记>2.4小节 ...

  4. WPF Thumb 滑块控件踩坑

    最近在做一个仿 手机选择时间的控件,如下图,选用了 Thumb 滑块控件做上下滑动的功能.订阅了 Thumb_OnDragStarted.Thumb_DragDelta和Thumb_DragCompl ...

  5. LUNARiA

    本文同步发布于我的网站 也算是头一次在没有任何安利和剧透,仅在看了简介的情况下就直接下单并开始游玩一部gal了.果然,没有给我留下什么遗憾呢. 游玩日志 SKYOUT-FOREVER <LUNA ...

  6. 浅析区块链BaaS平台定位

    一.概述 区块链是一种聚合了分布式存储.密码学.链式结构.p2p通讯,使得链上数据具有防篡改.可追溯等特点的一种信任技术. 继数字藏品热潮之后,2023年以来,区块链的发展进入了Gartner成熟度曲 ...

  7. 一个老程序员, 两个小时能用corsur做出什么样的东西

    背景 最近cosur太火了, 很多没开发背景的人也直接说0基础建站了, 互联网项目的门槛越高越低. 第一次看到一个行业拼命卷自己的.  作为一个16年的老程序员了, 肯定得试试这款颠覆性的产品. 在上 ...

  8. 三种AI人机交互系统的记忆模块对比:小智、OPEN-LLM-VTUBER和MaiBot

    MaiBot 的记忆和情感系统 https://github.com/MaiM-with-u/MaiBot 记忆系统 MaiBot 拥有最复杂和完整的记忆系统: 海马体记忆系统 (Hippocampu ...

  9. 一站式运维管家 ChengYing 主机接入原理解析

    之前的文章中,我们已经为大家介绍了 ChengYing 的安装原理.产品包制作.产品线部署等内容,本篇将和大家介绍一个困扰许多开发者的内容--ChengYing 主机接入.帮助所有对 ChengYin ...

  10. Kerberos身份验证在ChunJun中的落地实践

    Kerberos,在古希腊神话故事中,指的是一只三头犬守护在地狱之门外,禁止任何人类闯入地狱之中. 那么在现实中,Kerberos指的是什么呢? 一.Kerberos介绍 01 Kerberos是什么 ...