父类定义了相关子类的共有属性和行为。而接口可以定义类的共同行为(包括非相关的类)。

了解接口前,先来说说抽象类。抽象类介乎于普通类和接口之间,提供部分实现方法以及未实现方法,可以看作为一个半成品。

抽象类

在继承中, 父类是一个通用类,每一个子类都会使类变得越来越明确和具体。如果从子类追溯到父类,类就会变得通用、更加不明确。类的设计应该确保父类包含它的子类的共同特征和行为。有时候,一个父类会设计得非常抽象,导致它没有具体实例,这就是抽象类。

按照类和对象的关系来看:类是对象的抽象,是对象的模板,而抽象类可以理解为对类的抽象,是类的模板。

抽象类不能创建实例。抽象类中可以同时包含抽象方法和普通方法。抽象类的抽象方法的由子类来具体实现。

使用abstract修饰符定义一个类为抽象类:

public abstract class Sharp {
//采用protected进行修饰,保证能被子类访问。
protected String sharpType; //图形类型
protected String color; //图形颜色
protected Sharp() {}
protected Sharp(String sharpType, String color) {
this.sharpType = sharpType;
this.color = color;
}
/** 抽象方法 */
//获取图形面积
abstract double getArea(); //获取图形周长
abstract double getPermiter(); //提供一个普通方法
@Override
public String toString() {
return "图形:" + sharpType + " 颜色:" + color;
}
}
public class Circle extends Sharp {
private double radius;
public Circle(double radius) {
super("圆形", "白色");
this.radius = radius;
}
public Circle(String sharpType, String color, double radius) {
super(sharpType, color);
this.radius = radius;
}
@Override
public double getArea() {
return radius * radius * Math.PI;
}
@Override
public double getPermiter() {
return 2 * Math.PI * radius;
}
@Override
public String toString() {
return super.toString() + " 半径:" + radius
+ " 面积:" + getArea() + " 周长:" + getPermiter();
}
}
//正方形类
public class Square extends Sharp{
private double side;//边长
public Square(double side) {
super("正方形", "白色");
this.side = side;
}
public Square(String sharpType, String color, double side) {
super(sharpType, color);
this.side = side;
}
@Override
public double getArea() {
return side *side;
}
@Override
public double getPermiter() {
return side * 4;
}
@Override
public String toString() {
return super.toString() + " 边长:" + side
+ " 面积:" + getArea() + " 周长:" + getPermiter();
}
}
//长方形类
public class Rectangle extends Sharp {
private double length;
private double width;
public Rectangle(double length, double width) {
super("长方形", "白色");
this.length = length;
this.width = width;
}
public Rectangle(String sharpType, String color, double length, double width) {
super(sharpType, color);
this.length = length;
this.width = width;
}
@Override
public double getArea() {
return length * width;
}
@Override
public double getPermiter() {
return (length + width) * 2;
}
@Override
public String toString() {
return super.toString() + " 长:" + length + " 宽" + width
+ " 面积:" + getArea() + " 周长:" + getPermiter();
}
}

通过案例可以看出,抽象类和普通类差别不大,但抽象类中可以包含抽象方法,但是不允许实例化对象。抽象方法就是:只定义了方法,但没有提供具体实现,即没有方法体。抽象方法必须由子类来实现。包含了抽象方法的类必须声明为抽象类。

这也是为什么不允许实例化抽象类对象,因为调用抽象方法毫无意义。 一般来说,若要定义为抽象类,最好提供抽象方法,不然定义为抽象类无意义。

定义成抽象方法的好处,可以利用多态特性。例如:

    public static void main(String[] args) {
Sharp cir = new Circle("圆", "红色", 2.5);
Sharp square = new Square(4);
Sharp rec = new Rectangle(2, 5); test(cir);
test(square);
test(rec);
}
//接收Sharpl类型对象参数
public static void test(Sharp s) {
System.out.println(s.toString());
}
图形:圆 颜色:红色 半径:2.5 面积:19.634954084936208 周长:15.707963267948966
图形:正方形 颜色:白色 边长:4.0 面积:16.0 周长:16.0
图形:长方形 颜色:白色 长:2.0 宽5.0 面积:10.0 周长:14.0

以后想要设计一个新的图形类,继承Sharp抽象类即可。执行时,会根据该引用变量的实际类型来决定调用哪一个方法。充分利用了多态来优化代码。

使用抽象类的注意点

  • 抽象方法不能定义在非抽象类中,抽象方法只能由子类来实现。若是子类无法对其实现,则子类也必须定义为抽象类,交由它的子类来实现。
  • 抽象方法不能是静态方法。因为静态方法绑定于某个类,无法被方法重写。所以抽象方法只能是实例的。
  • 父类是非抽象类,是一个具体类。 但子类也可以定义为抽象类。 例如基类Object是具体类,可以实例化。但依然可以创建一个抽象类,隐式继承Object类。
  • 抽象类可以作为一种类型,运用在多态中。即父类引用变量指向子类对象。

抽象类在程序架构设计中的作用很大。通过JavaAPI文档,可以看到定义了很多抽象类,许多具体类都是继承同一个抽象类。其中的典型类就是包装类和IO流相关类。 虽然平常使用时基本用不到抽象类,但是这种设计模式是很值得学习的。可以花时间多看看Java源码,学习其中的类是如何设计的,对提高自身的代码境界真的很有帮助。

接口

接口是一种与类相似的结构,接口中只能包含常量和抽象方法。

接口和抽象类很相似,但它的目的是定义相关或者不相关类的多个对象的共同行为。使用正确的接口,可以指明这些对象能做什么。例如集合类接口Collection,保证实现的集合类必须实现增、删以及获取集合大小等一些功能。

接口作用:提供统一的协议,体现一种规范,只要实现某个接口,则必须实现接口的所有方法。接口的方法不提供具体实现,由实现类来提供具体实现。

定义接口的方式
修饰符 interface 接口名{
//常量声明
//抽象方法
}
public interface Letter {
  int MAX = 26; //常量
//接口的方法
void setUpperCase();
int getInteger();
}

接口中所有数据域都是public static final ,所有方法都是public abstract。所以定义常量和抽象方法时,可以忽略这些修饰符。接口会默认为常量和抽象方法加上修饰符。  

接口可以看作一种特殊类,和常规类一样,每个接口都会编译成单独的字节码文件。使用接口与使用抽象类差不多,只不过接口更加抽象。接口是一种特殊类,可作为引用变量类型,指向接口实现类对象。即父类型变量指向子类型对象。

接口和抽象类一样不允许实例化对象。实现某个接口和继承方式差不多,只不过采用implements关键字。接口继承和类继承本质上都是继承,但接口允许多继承,多个接口之间用逗号分开。

public class C implements AImpl, BImpl{
@Override
public void getB() {
//需要对其实现
}
@Override
public void getA() {
//需要对其实现
}
}

C类实现多个接口,则C类同时是AImpl和BImpl接口的实例。前面说过接口也是一种类类型,可以用父类型引用变量指向子类对象。例如:

        AImpl a = new C();
BImpl b = new C();

编译时,匹配的方法是由声明类型决定的,a引用变量只能匹配AImpl接口的方法,b引用变量只能匹配BImpl接口的方法。无法同时匹配实现的方法。

除了自定义接口外,了解一下Java中经常用到的接口。Comparable、Cloneable、Serializable以及Runnable。

Comparable接口

Comparable接口中定义了一个compareTo()方法,用于比较对象。有时候,我们需要对同一类型的对象进行比较,如果是自定义类,则无须专门提供一个比较同对象方法,实现Comparable接口即可。Comparable接口是泛型接口,可以很方便接收任意类型。

public interface Comparable<T> {
public int compareTo(T o);
}

compareTo()方法用于判断当前对象相较于给定对象o的顺序,当前对象小于、等于或大于给定对象时,分别返回负整数、0和正整数。

Java的许多常用类都已经实现了该接口。例如String、Date和Calendar等等。若是自定义类想比较同类型对象时,可实现该接口,根据类中的属性来制定一套比较规则。

        Date d1 = new Date();
Thread.sleep(50); //延迟一下,不然看不出日期比较效果
Date d2 = new Date();
System.out.println( "a".compareTo("c") ); //-2
System.out.println(d1.compareTo(d2)); //-1

数字可以直接比较数值。但通过实现Comparable接口,就可以对对象按照某种规则进行排序。例如求一个学生对象的综合排名,通过综合多方面因素来制定一套比较规则,就可以对大量学生对象进行排序。

Cloneable接口

Cloneable接口给出一个可克隆的对象。有时候经常会出现需要创建一个拷贝对象的情况,通过实现Cloneable接口,就能允许使用Object的clone()方法来完成拷贝。

Cloneable接口是一个比较特殊的接口,它的内部是空的,不存在常量以及抽象方法。它的作用就是标注实现类是可克隆的。【Java有些类已实现Cloneable接口,能直接使用clone()方法】

        Date date = new Date();
Date d1 = date;
Date d2 = (Date) date.clone();
System.out.println(d1 == date); //true
System.out.println(d2 == date); //false
System.out.println(date.equals(d2)); //比较日期内容,两者相同

使用clone()的好处就是拥有同样的内容,但并非同个对象。 尤其是像数组元素很多时,直接采用clone()来拷贝一份,可以方便很多。

Serializable接口

Serializable接口也是一个标注接口,用于标注实现类能被序列化。

Runnable接口

Runnable接口是Java中实现多线程常用的方式之一,实现Runnnable接口来定义一个线程类对象。

接口与抽象类的归纳总结

接口只能定义常量(即public static final),定义时可忽略修饰符。 而抽象类可以定义实例变量、静态变量以及常量。

接口中没有构造方法,无法使用new操作符实例化。 抽象类可以有构造方法,但只能是通过子类通过构造方法链来调用,同样无法使用new操作符实例化。

接口中只能定义公共抽象方法(即public abstract),定义时可忽略修饰符。而抽象类则定义普通方法、静态方法以及抽象方法。

一个类可以实现多个接口,即多重继承。但一个类只能继承一个抽象类,受单一继承限制。

另外,接口可以实现其他接口,但用得很少,无多大意义。 Java8允许接口中有一个默认方法,也就是一个具体实现的方法。关于默认方法的使用,请自行查阅相关资料。

Java接口和抽象类详解的更多相关文章

  1. Java中的抽象类详解,它存在的意义在哪里?

    学习抽象类前先理解下面这段话: 问你个问题,你知道什么是"东西"吗?什么是"物体"吗? "麻烦你,小王.帮我把那个东西拿过来好吗" 在生活中 ...

  2. Java接口修饰符详解

    接口就是提供一种统一的”协议”,而接口中的属性也属于“协议”中的成员.它们是公共的,静态的,最终的常量.相当于全局常量.抽象类是不“完全”的类,相当于是接口和具体类的一个中间层.即满足接口的抽象,也满 ...

  3. “全栈2019”Java第六十四章:接口与静态方法详解

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

  4. “全栈2019”Java第六十三章:接口与抽象方法详解

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

  5. “全栈2019”Java第六十二章:接口与常量详解

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

  6. Java接口和抽象类有什么区别,哪些时候用接口,哪些时候用抽象类?

    Java接口和抽象类有什么区别,哪些时候用接口,哪些时候用抽象类? 2013-01-05 17:16:09|  分类: JAVA |  标签:java  |举报|字号 订阅     下面比较一下两者的 ...

  7. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  8. java web.xml配置详解(转)

    源出处:java web.xml配置详解 1.常规配置:每一个站的WEB-INF下都有一个web.xml的设定文件,它提供了我们站台的配置设定. web.xml定义: .站台的名称和说明 .针对环境参 ...

  9. Java的JDBC事务详解

    Java的JDBC事务详解         分类:             Hibernate              2010-06-02 10:04     12298人阅读     评论(9) ...

随机推荐

  1. 有关从经典部署模型迁移到 Azure Resource Manager 部署模型的常见问题

    此迁移计划是否影响 Azure 虚拟机上运行的任何现有服务或应用程序? 不可以. VM(经典)是公开上市的完全受支持的服务. 你可以继续使用这些资源来拓展你在 Azure 上的足迹. 如果我近期不打算 ...

  2. EF中使用SqlQuery执行语句

    string sql = @" SELECT B.[FId], A.[FileTypeNo], A.[FtypeName], A.[FtypeId], A.[ProcessName], A. ...

  3. Visual Studio强行修改运行平台和注意事项

    默认情况下,会发现项目属性中只有一个Any CPU可供选择,无法修改运行平台. 解决方法如下: 右键“解决方案”,选择“属性”,此时发现每一个项目的平台依然只有Any CPU,点击右上角“配置管理器” ...

  4. mysql那些招

    show table status mysql官方文档在 http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html 这里的rows行是 ...

  5. Python学习---Django的基础学习

    django实现流程 Django学习框架:     #安装: pip3 install django          添加环境变量    #1  创建project       django-ad ...

  6. Java学习---Map的学习

    1. Map 1.1. map中的方法 1.2. Map.Entry 对于集合来讲,就是把kye-value的数据保存在了Map.Entry的实例之后,再在Map集合中插入了一个Map.Entry的实 ...

  7. MP4

  8. August 08th 2017 Week 32nd Tuesday

    The very essence of romance is uncertainty. 浪漫的精髓就在于它充满种种可能. Romance is the glamour that can turn th ...

  9. shell基础学习

    1. #! /bin/bash #设置只读变量,只读变量不可修改myUrl="http://www.baidu.com"readonly myUrl #删除变量,unset不能删除 ...

  10. webpack和gulp

    在没有使用任何自动化工具之前,如果用sass写了css, 用coffee写了js, 那么我们必须手动用相应的compiler去编译各自的文件,然后各自minify(js,css文件压缩并合并).这时如 ...