相关文章:

  1. 《面向对象再探究》:介绍了面向对象的基本概念
  2. 《详解Java的对象创建》:介绍了对象的创建、构造器的使用
  3. 《一文打尽Java继承的相关问题》:介绍了继承的使用方式和注意事项

本文来介绍Java的抽象类和接口的使用。

1. 抽象类

在前面的文章中提到过:父类比子类更加抽象,子类比父类更加具体。

《一文打尽Java继承的相关问题》这篇文章中举了动物和狗的例子:

  1. public class Animal {
  2. private String name;
  3. private int age;
  4. public Animal(String name, int age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. public Animal() {
  9. }
  10. public void say() {
  11. System.out.println("我是" + name + ",今年" + age + "岁了");
  12. }
  13. //getters and setters ...
  14. }
  1. public class Dog extends Animal {
  2. private String address;
  3. public Dog(String name, int age, String address) {
  4. super(name, age);
  5. this.address = address;
  6. }
  7. public Dog() {
  8. }
  9. public void say() {
  10. System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪...");
  11. }
  12. public void watchDoor() {
  13. System.out.println("我在" + address +"看门...");
  14. }
  15. //getters and setters ...
  16. }

上面Dog类很自然地继承了Animal类,没毛病!但是仔细琢磨一下Animal类的say()方法。

动物是一个很宽泛的概念,如果写代码表示,我们平常见到的大部分生物都可以继承该类。如下图:

有这么多类继承Animal类,那Animal类的say()方法这样写合适吗?因为每种动物说话的方式都不同,而动物又是这么宽泛的一个概念,我们通常会new Dog()new People(),但很少会去new Animal()

所以Animal类的say()方法体对其来说就是鸡肋一般的存在,因为即使有方法体,也会被其子类重写。既然这样那就干脆不要方法体了。

换句话说,我们将Animal类再进行更高层次地抽象,它具有各种动物都有的属性,比如nameage,也有各种动物都有的行为,比如say但是,Animal类并不具体实现该方法,具体的实现交给子类来做

这样一来,谁继承了Animal类,谁就有了它的属性和行为,子类不用管父类的行为是否合适,因为父类的行为“有名无实”,所以子类只需继承这些“名”,具体的“实”则由子类来完成。

这样的Animal类就是抽象类

下面将上例中的Animal类修改为抽象类,Dog类无需改动:

  1. public abstract class Animal {
  2. private String name;
  3. private int age;
  4. public Animal(String name, int age) {//有参构造器
  5. this.name = name;
  6. this.age = age;
  7. }
  8. public Animal() {//无参构造器
  9. }
  10. public abstract void say();//抽象方法
  11. public String getName() {//被具体实现的方法
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. //getters and setters..
  18. }

下面是抽象类的特点:

(一)抽象类被abstract关键字修饰。

  1. public abstract class Animal {
  2. //......
  3. }

(二)类中没有方法体的方法叫抽象方法,也需要使用abstract关键字修饰。

  1. public abstract void say();//抽象方法

(三)有抽象方法的类一定是抽象类。

(四)没有抽象方法的类也可以是抽象类。

(五)抽象类中可以有成员变量、构造器、被具体实现的方法。构造器不能是抽象的。

(六)抽象类不能被实例化,但是可以声明一个抽象类变量

  1. Animal animal = new Animal();//报错: 'Animal' is abstract; cannot be instantiated
  2. Anima animal;//抽象类变量,可行

我们以前遇到的类,比如Dog类,是用来描述对象的,但抽象类的方法没有具体实现,所以它没有足够的信息来描述对象,所以抽象类只能被继承用来描述其子类而不能实例化。

(七)子类扩展抽象父类有两种选择:

  1. 当子类不是抽象类时,子类必须实现抽象父类的抽象方法:
  1. public class Dog extends Animal {
  2. //属性、构造器、其他方法
  3. //实现抽象父类的抽象方法
  4. @Override
  5. public void say() {
  6. System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪...");
  7. }
  8. }
  1. 当子类是抽象类时,子类可以实现抽象父类的抽象方法,也可以选择不实现。
  1. public abstract class Dog extends Animal {
  2. //属性、构造器、其他方法
  3. //可以选择不实现父类的抽象方法
  4. }

2. 接口

2.1. 什么是接口?

生活中有一种接口是大家每天都在用的,那就是插座。

不管是什么样的电器,冰箱、电视、电脑、电风扇,只要买回来,就能插上通电。之所以这么便利,就是因为电器生产商和插座生产商都遵守了一个生产规范:我把插座生产成这个模样,你把插头也生产成这个模样,我不管你电器内部是啥样,你也不用管我的插座内部是啥样,大家把产品生产好,各自卖给客户,合作愉快,一起赚钱。这些产品如果以后坏了,那就再买一个遵守规范的就能继续配套使用了。

想一想,如果没有这个规范,插座和插头生产的千奇百怪,买回来怎么用?只能把插座和冰箱拆开,用手接220V的电线了。

换句话说,接口就是生产规范 / 标准,或者双方遵守的协议,只要双方都遵守,那么就能愉快地交流、愉快地合作。

在Java开发中,一个软件系统肯定不是由一个人完成的,而是由一个团队完成的。那如何避免甲写的类乙不能用,乙写的类丙不能用呢,最后导致甲改了乙的代码,乙改了丙的代码?事先定好规范(接口),大家都遵守接口,只要我知道你的接口,那么我不需要知道你的具体代码,就能调用你的类。

2.2. 接口的使用

掌握关于接口几个特点就能愉快地写接口了:

(一)Java中使用inteface关键字来声明一个接口,接口必须是public的,只有公有了才能让大家遵守:

  1. public interface Runnable {
  2. }

(二)接口中通常写各种抽象方法,但只声明,不能写方法体。

  1. public interface Runnable {
  2. /*public abstract*/ void run();
  3. }

(三)不必将方法声明为public abstract ,在接口中的所有方法都默认的是public abstract修饰。

(四)接口中不能有成员变量、静态代码块。

(五)接口中可以含有常量,常量默认是public static final修饰。

  1. public interface Runnable {
  2. /*public static final*/ int i = 1;
  3. void run();
  4. }

(六)类通过implements关键字实现接口,必须同时实现接口中的所有方法。

  1. public class Dog implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("跑得飞快");
  5. }
  6. //......
  7. }

(七)如果实现接口的类是抽象类,可以不用实现接口中的方法。

(八)一个类可以同时继承类和实现接口。

  1. public class Dog extends Animal implements Runnable {
  2. //......
  3. }

(九)一个类可以实现多个接口。

  1. public class Dog implements Runnable, Flyable {
  2. //......
  3. }

(十)接口之间可以继承,并且允许多继承。

  1. public interface A {
  2. //......
  3. }
  4. public interface B extends A, Runnable{
  5. //......
  6. }

(十一)接口不能被实例化,但是可以声明一个接口变量。

  1. Runnable runnable = new Runnable();//'Runnable' is abstract; cannot be instantiated
  2. Runnable runnable;//接口变量,可行

3. 总结

抽象类用abstract关键字声明,抽象类中除了可以有抽象方法(用abstract关键字声明)外,还可以有普通类的成员变量、构造器、方法。不能被实例化,但可以声明抽象类的变量。子类继承抽象类要实现父类的抽象方法(如果子类是抽象的,则不用实现)。

接口用interface关键字声明,接口中只能有抽象方法、常量(忽略修饰符)。不能被实例化,但可以声明接口变量。接口之间可以继承,且允许多继承。类实现接口使用implements关键字,且必须实现接口中的抽象方法(如果类是抽象的,则不用实现)。

总结了抽象类和接口的特点,发现抽象类好像也能作为“接口”使用。那有了抽象类,为什么还要有接口?

类只能单继承,如果使用抽象类作为“接口”,这意味着一个类只能遵守一份“接口”,显然不符合实际。而接口则灵活多了。

4. 关于我

如有错误,还请指正。

一文打尽Java抽象类和接口的相关问题的更多相关文章

  1. XML文档形式&JAVA抽象类和接口的区别&拦截器过滤器区别

    XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? a: 两种形式 dtd schemab: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发 ...

  2. java抽象类与接口的区别及用法

    java抽象类与接口的区别及用法 一.抽象类里面的方法可以有实现,但是接口里面的方法确是只能声明. 二.接口是设计的结果 :抽象类是重构的结果 . 三.java不支持多重继承,所以继承抽象类只能继承一 ...

  3. Java 抽象类与接口总结

    一.为什么要使用抽象类?有什么好处? 抽象类是通用接口.不同的子类可以用不同的方法表示此接口.通用接口建立起一种基本形式,以此表示所有子类的共同部分. 必须覆写父类abstract抽象的方法  含有抽 ...

  4. JAVA抽象类和接口的深入探讨

    Java 语言中,抽象类(abstract class) 和接口(interface) 是抽象思想的两种体现形式.初学者很容易把这两者搞混,所以Java面试中考抽象类和接口的区别的面试题也常有出现的. ...

  5. 第十八节:详解Java抽象类和接口的区别

    前言 对于面向对象编程来说,抽象是它的特征之一. 在Java中,实现抽象的机制分两种,一为抽象类,二为接口. 抽象类为abstract class,接口为Interface. 今天来学习一下Java中 ...

  6. Java抽象类和接口的比较

    一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法和一些具体 ...

  7. java抽象类与接口区别

    java抽象类与接口区别: abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力. abstr ...

  8. Java抽象类和接口的区别(好长时间没看这种文章了)

    Java抽象类和接口的区别(好长时间没看这种文章了) abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的 ...

  9. Java 抽象类和接口的理解

    Java 抽象类和接口的理解 一.抽象类 为什么使用抽象类(个人理解): 面向对象的概念是,我们知道的所有的对象都是通过类来描绘的,如果类包含的信息不能描绘一个具体的对象,就需要抽象来解决了,意思是一 ...

随机推荐

  1. CSS(二)- 选择器 - 一定要搞懂的选择器优先级和权重问题

    css的优先级之前一直没怎么注意没当回事,总以为对同一元素靠后的渲染会覆盖前面的渲染,要是覆盖不了那就来个!important嘛.直到我那在学前端基础的后端伙伴拿一个问题问住了我,我才意识到这是重点中 ...

  2. 静态方法中注入bean

    @Componentpublic class ScriptExecuteContent { @Autowired private static SignRepository signRepositor ...

  3. java 基本语法(十八)Lambda (五)Stream API

    1.Stream API的理解:1.1 Stream关注的是对数据的运算,与CPU打交道集合关注的是数据的存储,与内存打交道 1.2 java8提供了一套api,使用这套api可以对内存中的数据进行过 ...

  4. 在flask中使用flask-migrate管理数据库

    Flask-Migrate是一个为Flask应用处理SQLAlchemy数据库迁移的扩展,使得可以通过Flask的命令行接口或者Flask-Scripts对数据库进行操作. 安装 pip3 insta ...

  5. web 部署专题(二):gunicore 并发部署(用gunicorn+gevent启动Flask项目)

    转自:https://blog.csdn.net/dutsoft/article/details/51452598 Flask,webpy,Django都带着 WSGI server,当然性能都不好, ...

  6. mongodb(四):对文档操作增删查改(python)

    连接mongodb #!/usr/bin/env python # -*- coding:utf-8 -*- import pymongo mongo_client = pymongo.MongoCl ...

  7. python之class面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  8. 自定义类支持foreach

    建议使用yield语句简化迭代 using System; using System.Collections; namespace 自定义类实现foreach { class A { int[] w; ...

  9. javascript : 点击按钮,把某标签中的内容复制到剪贴板

    需求如题. 静态页面如下. 需要的库:jquery(不用应该也能做). 浏览器:PC chrome 68 Mobile MIUI9.5(Android 7) <p>1.用电脑打开网址:&l ...

  10. 循序渐进nginx(一):介绍、安装、hello world、Location匹配

    目录 前言: Nginx是什么 使用场景: 官方文档说明 安装 windows下: linux(CentOS7)下: docker下: 目录结构 Hello World 1.展示一下默认的核心配置: ...