Java接口和抽象类详解
父类定义了相关子类的共有属性和行为。而接口可以定义类的共同行为(包括非相关的类)。
了解接口前,先来说说抽象类。抽象类介乎于普通类和接口之间,提供部分实现方法以及未实现方法,可以看作为一个半成品。
抽象类
在继承中, 父类是一个通用类,每一个子类都会使类变得越来越明确和具体。如果从子类追溯到父类,类就会变得通用、更加不明确。类的设计应该确保父类包含它的子类的共同特征和行为。有时候,一个父类会设计得非常抽象,导致它没有具体实例,这就是抽象类。
按照类和对象的关系来看:类是对象的抽象,是对象的模板,而抽象类可以理解为对类的抽象,是类的模板。
抽象类不能创建实例。抽象类中可以同时包含抽象方法和普通方法。抽象类的抽象方法的由子类来具体实现。
使用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 { |
//正方形类 |
//长方形类 |
通过案例可以看出,抽象类和普通类差别不大,但抽象类中可以包含抽象方法,但是不允许实例化对象。抽象方法就是:只定义了方法,但没有提供具体实现,即没有方法体。抽象方法必须由子类来实现。包含了抽象方法的类必须声明为抽象类。
这也是为什么不允许实例化抽象类对象,因为调用抽象方法毫无意义。 一般来说,若要定义为抽象类,最好提供抽象方法,不然定义为抽象类无意义。
定义成抽象方法的好处,可以利用多态特性。例如:
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接口和抽象类详解的更多相关文章
- Java中的抽象类详解,它存在的意义在哪里?
学习抽象类前先理解下面这段话: 问你个问题,你知道什么是"东西"吗?什么是"物体"吗? "麻烦你,小王.帮我把那个东西拿过来好吗" 在生活中 ...
- Java接口修饰符详解
接口就是提供一种统一的”协议”,而接口中的属性也属于“协议”中的成员.它们是公共的,静态的,最终的常量.相当于全局常量.抽象类是不“完全”的类,相当于是接口和具体类的一个中间层.即满足接口的抽象,也满 ...
- “全栈2019”Java第六十四章:接口与静态方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第六十三章:接口与抽象方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第六十二章:接口与常量详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Java接口和抽象类有什么区别,哪些时候用接口,哪些时候用抽象类?
Java接口和抽象类有什么区别,哪些时候用接口,哪些时候用抽象类? 2013-01-05 17:16:09| 分类: JAVA | 标签:java |举报|字号 订阅 下面比较一下两者的 ...
- java反射机制深入详解
java反射机制深入详解 转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...
- java web.xml配置详解(转)
源出处:java web.xml配置详解 1.常规配置:每一个站的WEB-INF下都有一个web.xml的设定文件,它提供了我们站台的配置设定. web.xml定义: .站台的名称和说明 .针对环境参 ...
- Java的JDBC事务详解
Java的JDBC事务详解 分类: Hibernate 2010-06-02 10:04 12298人阅读 评论(9) ...
随机推荐
- ARCGIS 10.0破解版安装过程error 1606 和error 1316问题 及安装流程
来自:http://blog.csdn.net/don_lvsml/article/details/8681100 楼主今天安装ESRI.ArcGIS.10.CS时,由于第一次接触该软件,将其按照一般 ...
- C++11 之for 新解 auto
C++11 之for 新解 auto 前言 C++11这次的更新带来了令很多C++程序员期待已久的for range循环,每次看到javascript, lua里的for range,心想要是 ...
- Mac安装Dart的SDK
最近了解到谷歌推迟Flutter兼容开发iOS.Android移动应用的框架,该框架使用的语音是Dart.作为一个iOS开发者来说,不感兴趣就不正常了,于是开始从学习Dart开始,所有的开发语音其实都 ...
- 使用@Value进行静态常量的值注入
@Component public class ExpressConstant { public static String URL; @Value("${express.url}" ...
- sql server2008安装时提示重启计算机失败怎么办?
在键盘上按下组合键[Win]+[R],调出运行窗口. 在窗口中输入“regedit”,点击确定,打开注册表管理界面. 在注册表左侧目录栏中找到如下位置:“HKEY_LOCAL_MACHINE\SYST ...
- .net core系列之《.net core中使用集成IDistributedCache接口的Redis和MongoDB实现分布式缓存》
分布式的缓存可以提高性能和可伸缩性的 ASP.NET Core 应用程序,尤其是托管在云中或服务器场中时. 什么是分布式的缓存 分布式的缓存由多个应用程序服务器共享,缓存中的信息不存储在单独的 Web ...
- python之路——进程
操作系统背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其 ...
- Lua操作mysql
require "luasql.mysql" --创建环境对象 env = luasql.mysql() --连接数据库 conn = env:connect("数据库名 ...
- Github文件夹下载到本地
1.如图:需要将以下文件夹下载到本地. https://github.com/aspnet/Docs/tree/master/aspnet/mvc/overview/getting-started/i ...
- linux性能系列--网络
一.为啥网络监控不好做? 回答:网络是所有子系统中最难监控的了.首先是由于网络是抽象的,更重要的是许多影响网络的因素并不在我们的控制范围之内.这些因素包括,延迟.冲突.阻塞等 等.由于网络监控中, ...