一、抽象类

// 抽象类Shape
public abstract class Shape
{
// 1. 成员变量
private String color; // 2. 初始化块
{
System.out.println("执行Shape的初始化块...");
} // 3. 构造器
public Shape() {}
public Shape(String color)
{
System.out.println("执行Shape的构造器...");
this.color = color;
} // 4. 方法:抽象方法和普通方法都可以
public abstract double calPerimeter();
public void setter(String color)
{
this.color = color;
} // 5. 内部类(接口、枚举)
}

1. 抽象方法

  • 抽象方法没有方法体(只有方法签名,没有方法实现),只能由子类提供实现(即重写)
  • 抽象方法必须能被其子类重写才有意义,即private和abstract不能同时修饰某个方法
  • final修饰的方法不能被重写,因此final和abstract不能同时修饰某个方法
  • 类方法不能被定义成抽象方法,即static和abstract不能同时修饰某个方法
  • 含有抽象方法的类只能被定义成抽象类

2. 抽象类

  • 抽象类不能被实例化(不能创建抽象类的实例),只能当作父类被其他子类继承
  • final修饰的类不能被继承,因此final和abstract永远不能同时使用
  • 子类只有实现抽象父类里的所有抽象方法,才能被定义成普通类

3. 抽象类的成员:成员变量、方法、初始化块、构造器、内部类(接口、枚举)

  • 抽象类里可以没有抽象方法
  • 抽象类中的初始化块和构造器都不是在创建该类对象时被调用的(抽象类的构造器不能用于创建实例),而是在创建其子类的实例时被调用

4. 利用抽象类可以发挥多态的优势,使程序更加灵活

// 下面定义一个Circle普通类,其必须实现Shape里的抽象方法
public class Circle extends Shape
{
private double radius;
public Circle(String color, double radius)
{
super(color);
this.radius = radius;
} public void setRadius(double radius)
{
this.radius = radius;
} // 重写Shape类的计算周长的抽象方法
public double calPerimeter()
{
return 2 * Math.PI * radius;
} public static void main(String[] args)
{
// 定义Shape类型的引用变量s,s指向Circle对象
Shape s = new Circle("黄色", 3); // 由于在Shape类中定义了calPerimeter()方法,所以程序可以直接调用变量s的calPerimeter()方法
// 无须将变量s强制转换为其子类类型
System.out.println(s.calPerimeter());
}
}

5. 抽象类的作用

  不同Shape子类对周长的计算方法是不一样的,即Shape类无法准确地知道其子类计算周长的方法,故Shpe类不知道如何实现calPerimeter()方法。此时若不在Shape类中定义calPerimeter()方法,则Shape引用变量s虽然可以引用到Shape子类的实例,但该变量s却无法调用calPerimeter()方法,必须将其强制转换为其子类类型才行,这就降低了程序的灵活性。这种情况下,我们可以在Shape类中将calPerimeter()方法定义为抽象方法,其具体实现交给子类来完成。也就是说,抽象父类把不能实现的方法定义为抽象方法,留给其子类去实现。

  • 从语义的角度来看,抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象
  • 从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类设计的随意性
  • 抽象类体现的是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会大致保留抽象类的行为方式

二、接口

/*
* 示例:定义一个接口
*/
[修饰符] interface 接口名 extends 父接口1, 父接口2...
{
// 成员1:静态常量
[public static final int] MAX_SIZE = 50; // 成员2:抽象方法
[public abstract] void getData(String msg); // 成员3:默认方法
[public] default void test()
{
System.out.println("默认的test()方法");
} // 成员4:类方法
[public] String staticTest()
{
return "接口里的类方法";
} // 成员5:私有方法
private void foo()
{
System.out.println("foo私有方法");
}
private static void bar()
{
System.out.println("bar私有静态方法");
} // 成员6:内部类、内部接口、内部枚举
}

1. 定义接口概述

  • 定义接口使用interface关键字
  • 修饰符可以是public或省略,如果省略了public访问控制符,则默认采用包权限访问控制符
  • 接口名应与类名采用相同的命名规则,通常使用形容词
  • 接口只能继承接口,且接口支持多继承(可以有多个直接父接口)
  • 一个Java源文件里最多只能有一个public接口,且如果某Java源文件里定义了一个public接口,则该文件名必须与public接口名相同

2. 接口的成员

由于接口里定义的是多个类共同的公共行为规范,因此接口里的成员(除了私有方法)都是public访问权限。

定义接口成员(除了私有方法)时,既可以显式使用public修饰符,也可以省略不写(此时系统会自动添加public修饰符)。

①静态常量

  • 接口里的成员变量只能是静态常量,它们是接口相关的
  • 在接口中定义成员变量时,不管是否使用public static final修饰符,接口里的成员变量总是使用这三个修饰符来修饰(系统自动添加)
  • 由于接口里没有初始化块和构造器,因此接口里的静态常量只能在定义时指定默认值

②抽象方法(无方法体)

  • 由于接口里定义的方法只能是抽象方法、类方法、默认方法和私有方法,因此如果不是定义后三种方法,系统将自动为普通方法增加abstract修饰符
  • 定义接口里的普通方法时,不管是否使用public abstract修饰符,接口里的普通方法总是使用public abstract来修饰(系统自动添加)

③默认方法(带方法体)

  • 默认方法必须使用default修饰,且不能使用static修饰,故不能直接使用接口来调用
  • 定义接口里的默认方法时,不管是否使用public修饰符,接口里的默认方法总是使用public来修饰(系统自动添加)
  • 接口的默认方法其实就是实例方法,只是多了个default修饰符而已

④类方法(带方法体)

  • 类方法必须使用static修饰,且不能使用default修饰,可以直接使用接口来调用
  • 定义接口里的类方法时,不管是否使用public修饰符,接口里的默认方法总是使用public来修饰(系统自动添加)

⑤私有方法(带方法体)

  • Java9增加了私有方法,这是因为:Java8允许在接口中定义带方法体的默认方法和类方法,那么当两个默认方法(或类方法)中包含一段相同的实现逻辑时,程序必然考虑将这段实现逻辑抽取成工具方法,而工具方法时应该被隐藏的,故Java9增加了私有方法。

⑥内部类、内部接口、内部枚举

  • 接口里的内部类、内部接口、内部枚举默认采用public static来修饰(系统自动添加)

3. 接口的作用

  • 抽象类是从多个类中抽象出来的模板,如果将这种抽象进行得更彻底,那就得到了“接口”
  • 接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据和方法实现细节,它只规定这些类里必须提供哪些方法
  • 接口是从多个相似类中抽象出来的规范,接口不提供任何实现,它体现的是规范和实现分离的设计哲学
  • 接口作为系统与外界交互的窗口,它规定了实现者必须向外提供哪些服务,还规定了调用者可以调用哪些服务以及如何调用这些服务
  • 当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个程序之间使用接口时,接口是多个程序之间的通信标准

4. 抽象类 & 接口

  • 抽象类体现的是一种模板式设计,它作为系统中多个子类的抽象父类,已经实现了系统的部分功能(那些已经提供实现的方法)
  • 接口体现的是一种规范,它是系统的“总纲”,制定了系统各模块应该遵循的标准,故一个系统的接口不应该经常改变

三、面向接口编程

1. 接口的三大用途

  • 定义引用类型变量,该变量必须引用到接口实现类的对象,该变量也可进行强制类型转换
  • 调用接口中定义的常量
  • 被实现类实现

2. 类实现接口

// 类实现接口的语法格式
[修饰符] class 类名 extends 父类 implements 接口1, 接口2...
{
}
  • 类实现接口使用implements关键字
  • 一个类可以继承一个父类,并同时实现一个或多个接口,implements部分必须放在extends部分之后
  • 类实现接口时,该类将获得接口中定义的静态常量、方法等,故可以把实现接口理解为一种特殊的继承
  • 类实现接口时,必须完全实现接口里所定义的全部抽象方法,否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类
  • 实现接口方法时,必须使用public访问控制修饰符,因为接口里的方法都是public的,故实现类实现接口里的方法时只能使用public访问权限

3. 模拟多继承

interface Output
{
// 静态常量,系统自动添加public static final修饰符
int MAX_CACHE_LINE = 50;
} interface Product
{
// 抽象方法,系统自动添加public abstract修饰符
int getProduceTime();
} // 让Printer类实现Output和Product接口
public class Printer implements Output, Product
{
public int getProduceTime()
{
return 45;
} public static void main(String[] args)
{
// ex1:创建一个Printer对象,当成Output使用
Output o = new Printer(); // ex2:创建一个Printer对象,当成Product使用
Product p = new Printer();
System.out.println(p.getProduceTime()); // ex3:所有接口类型的引用变量都可直接赋给Object类型的变量
Object obj = p;
}
}
  • Printer类实现了Output接口和Product接口,故Printer对象既可直接赋给Output变量,也可直接赋给Product变量
  • 彷佛Printer类既是Output类的子类,也是Product类的子类,这就是Java提供的模拟多继承,通过实现多个接口可以弥补单继承的不足
  • 虽然接口不能显式继承任何类,但所有接口类型的引用变量都可直接赋给Object类型的引用变量

13. 抽象类 & 接口的更多相关文章

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

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

  2. python 全栈开发,Day21(抽象类,接口类,多态,鸭子类型)

    一.昨日复习 派生方法和派生属性 super 只有在子父类拥有同名方法的时候, 想使用子类的对象调用父类的方法时,才使用super super在类内 : super().方法名(arg1,..) 指名 ...

  3. python面向对象 : 抽象类(接口类),多态,封装(私有制封装)

    一. 抽象类(接口类) 与java一样, python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类, 它的特殊之处在于只能被继承, 不能被实例化. 从设计角度去看, 如果类是从现实对 ...

  4. 【学习笔记】--- 老男孩学Python,day18 面向对象------抽象类(接口类), 多态, 封装

    抽象类,接口类 Python没有接口这个概念 抽象类(接口类): 目的是制定一个规范 要学会归一化设计,有重复的东西就要想把它们合并起来 from abc import ABCMeta, abstra ...

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

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

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

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

  7. python day - 19 抽象类 接口类 多态 封装

    一. 抽象类接口类即制定一个规范 特点: 1.不可被实例化. 2.规范子类当中必须事先某个方法. 3.在python中有原生实现抽象类的方法,但没有原生实现接口类的方法. 例题:制定一个规范就是,子类 ...

  8. C# 你什么让程序员寂寞成酱紫 (男生版 娱乐中学习 抽象类 接口 继承 实现方法 )

    你什么让程序员寂寞成酱紫 (男生版 娱乐中学习 抽象类 接口 继承 实现方法 )   一个家庭 相当于 一个空间,这个空间里 有 很多元素,比如 爱,爱这个抽象事物,可能有很多动作,接吻.交流,对于一 ...

  9. 面向对象的理解 抽象类&接口

    一.关于面向对象 1.什么是面向对象     在解释面向对象之前,先说说面向过程.学过C的同学都知道,C就是面向过程的一种语言.那什么是面向过程呢?比方说组装主机,对于面向过程,需要从0开始.买cpu ...

随机推荐

  1. QT--HTTP图片下载器

    QT--HTTP图片下载器 1.http使用前提 QT       += core gui network    //必须加上network 2.必须头文件 #include <QNetwork ...

  2. 36-Docker 的两类存储资源

    我们从本章开始讨论 Docker 存储. Docker 为容器提供了两种存放数据的资源: 由 storage driver 管理的镜像层和容器层. Data Volume. 我们会详细讨论它们的原理和 ...

  3. 克服悲伤情绪的三个P原则

    1.自责(Personalization) --不要自责 2.永久化(Permanence) --悲伤不会永远存在,一切都会过去 据科学研究发现:人遇到开心或悲伤的事情之后,心情在短期内会产生巨大的波 ...

  4. java-11-Stream优化并行流

      并行流    多线程    把一个内容分成多个数据块  不同线程分别处理每个数据块的流   串行流   单线程  一个线程处理所有数据   java8 对并行流优化  StreamAPI 通过pa ...

  5. 8. java 面向对象

    一.面向对象特征 1. 封装 方法就是一种封装 关键字private也是一种封装 封装就是讲一些逻辑细节信息隐藏起来,对于外界不可见:外界只需调用我即可: 一旦使用了private进行修饰,那么本类当 ...

  6. AHOI 2009 维护序列

    洛谷 P2023 [AHOI2009]维护序列 洛谷传送门 题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式 ...

  7. HDU2899Strange fuction(二分/三分)

    传送门 题目大意:求 F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100):的最小值 题解:求个导,二分导函数零点,就是原函数最小值所在的 ...

  8. CF750G New Year and Binary Tree Paths(DP)

    神仙题.为啥我第一眼看上去以为是个普及题 路径有两种,第一种是从 LCA 一边下去的,第二种是从 LCA 两边都下去了的. 先考虑第一种. 先枚举路径长度 \(h\). 当 LCA 编号是 \(x\) ...

  9. 使用OC实现单链表:创建、删除、插入、查询、遍历、反转、合并、判断相交、求成环入口

    一.概念 链表和数组都是一种线性结构,数组有序存储的,链表是无序存储的. 数组中的每一个元素地址是递增或者递减的关系,链表的每一个节点的地址没有此规律,它们是通过指针的指向连接起来. 链表种类:单链表 ...

  10. php 数组赋值

    结果: 结论:第一种方式的运行速度是第二种方式的二倍左右.