抽象类

什么是抽象类?

  • 在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. centos6分区要点

    安装centos6系统时,为了以后能够扩展存储,分区时要注意几点: 1.boot引导分区要选固定分区类型存储,大小是500M 2.其余分区全部做成物理卷lvm  pyshiic类型存储 3.在这个物理 ...

  2. AutoCAD 逆向工程中 Shx 字体文件解析

    数据格式相关的文章 https://wenku.baidu.com/view/8abbfc33eefdc8d376ee32a1.html 代码实现 https://blog.csdn.net/qq_2 ...

  3. C# 相等比较

    C# 相等比较 有两种类型的相等: 值相等:即两个值是一样的 引用相等:即引用是一样的,也就是同一个对象 默认地,对于值类型来讲,相等指的就是值相等:对于引用类型,相等就是指的引用相等. int a ...

  4. AI智能体策略FunctionCalling和ReAct有什么区别?

    Dify 内置了两种 Agent 策略:Function Calling 和 ReAct,但二者有什么区别呢?在使用时又该如何选择呢?接下来我们一起来看. 1.Function Calling Fun ...

  5. 用 AI 实现一个 GBK/GB2312 转 UTF-8 工具:轻松解决文本编码转换难题(附完整源码)

    用 AI 实现一个 GBK/GB2312 转 UTF-8 工具:轻松解决文本编码转换难题 在处理历史文件或与不同系统交互时,我们经常会遇到 GBK 或 GB2312 编码的文本文件.虽然现在 UTF- ...

  6. 浅谈Spring、Spring MVC、Spring Boot和Spring Cloud的关系和区别

      Spring 框架就像一个家族,有众多衍生产品,例如 boot.security.jpa等等.但它们的基础都是Spring的IOC和AOP等.IOC提供了依赖注入的容器,AOP解决了面向横切面编程 ...

  7. Web前端入门第 62 问:JavaScript 循环结构注意事项

    HELLO,这里是大熊的前端开发笔记. 循环作为 算法与数据结构 中的基石,JS 与其他编程语言一样,都提供了多种循环结构用于处理数据. for 循环 事物的开端往往都是从最常用的开始,循环结构咱们从 ...

  8. 红色教育软件需求分析 NABCD

    N(need) 红色教育指在以红色作为时代精神内涵的象征.务实的落点在于教育.要呼唤有志青年忧国忧民.挑战自我.超越自我.挑战极限.奉献社会的崇高精神.而我们大学生作为实现中华民族伟大复兴的有生力量, ...

  9. cookie,session以及application的比较

    cookie工作原理:  cookie代码: 1 @WebServlet(value = "/cookie",name = "CookieServlet") 2 ...

  10. BAPI_RESERVATION_CHANGE 删除预留

    CLEAR: reservationitems[],reservationitems. CLEAR: reservationitemsx[],reservationitemsx,reservation ...