Java问题解读系列之基础相关---抽象类和接口
今天来说一波自己对Java中抽象类和接口的理解,含参考内容:
一、抽象类
1、定义:
public abstract class 类名{}
Java语言中所有的对象都是用类来进行描述,但是并不是所有的类都是用来描述对象的。我所理解的抽象类其实就是对同一类事物公共部分的高度提取,这个公共部分包括属性和行为。比如牛、羊、猪它们的公共属性是都有毛,公共行为是都哺乳,所以我们可以把公共部分抽象成一个哺乳类,含有属性毛和行为哺乳,当牛、羊、猪继承了哺乳类后也就有了哺乳的功能,至于怎么完成这个功能就需要自己去实现了。
2、特点
(1)被Abstract关键字修饰的类是抽象类;
(2)含有抽象方法的类一定是抽象类,但是抽象类不一定含有抽象方法;且抽象方法必须是public或protected,否则不能被子类继承。默认为public。
(3)抽象方法中不能有实现,否则编译报错;
(4)抽象类中可以定义自己的成员变量和成员方法;
(5)子类继承抽象类时,必须实现抽象类中的所有抽象方法,否则该子类也要被定义为抽象类;
(6)抽象类不能被实例化。
3、验证以上规定是否确实如其所述
这是我在word中编辑的一张验证表,把它截成图片放在这里:
从上图的验证结果来看,那些理论都是正确的
二、接口
1、定义:
public interface 接口名{}
接口是用来提供方法的。按我的理解,它是对多个类公共行为的高度提取,比如所有的动物它们的公共行为是吃和睡,那么我们就可以将这两个行为提取出来封装在一个接口中,当某个动物需要执行这个行为的时候只要调用该接口,然后在自己的类里面完成具体实现就行。这样理解好像跟抽象类没什么区别,那再看下面的这个例子。如果把这两个行为放在抽象类中,但是该抽象类中还有一个爬的行为,此时当一种爬行动物,比如蛇,当它继承这个类的时候,会实现吃、睡、爬行这三个方法,于是它便有了吃、睡、爬的功能;但是如果一个飞行类的动物如鸟,当它继承了这个方法的时候,同样的也有了吃、睡、爬的功能,很明显,爬不是它需要的功能,这就有点词不达意了,但是当他们继承了只有吃、睡的接口,就有了吃、睡的基本功能,至于爬和飞,可以抽象出来放在抽象类中,按需继承,按需实现自己需要的功能就OK了。
2、特点:
(1)接口中可以有自己的成员变量,但会被隐式地指定为public staic final,而且也只能是public staic final的,接口中所有的方法都是抽象方法,都会被隐式地指定为public abstract的。
(2)接口中只定义抽象方法,没有具体的实现;
(3)实现接口的类必须实现接口中定义的所有方法;
3、验证以上理论是否正确
同样,验证出上面的理论都是对的!
三、抽象类和接口的区别:
1、抽象类中可以有自己的成员方法及它们的具体实现;接口中只能含有抽象方法;
2、抽象类中可以含有各种类型的成员变量;接口中的成员变量只能是public static final的;
3、一个类只能继承一个抽象类,但可以实现多个接口;
4、抽象类中可以含有静态代码块和静态方法;接口中不能定义静态代码块和静态方法;
验证一个类只能继承一个抽象类,但能实现多个接口
首先,定义两个抽象类:一个Mummals哺乳类,一个Crawler爬行类
/**
* @createtime 2017年3月17日 上午10:33:27
* @description 哺乳类
*/
public abstract class Mammals {
public String foods; public abstract void nurse(); public void eat(String food){
this.foods = food;
System.out.println("吃"+foods);
}
}
/**
*
* @createtime 2017年3月17日 上午11:23:09
* @description 定义一个抽象类--爬行类
*/
public abstract class Crawler { public abstract void crawl();
}
其次,定义两个接口:一个是BaseAction基础接口;一个是SpecialAction特殊接口
/**
*
* @createtime 2017年3月17日 上午11:03:42
* @description 定义一个名为基本行为的接口
*/
public interface BaseAction { public String name = ""; public void eat(); public void sleep();
}
/**
* @createtime 2017年3月17日 上午11:24:56
* @description 定义一个接口用来实现特殊行为
*/
public interface SpecialAction { public void study();
}
然后,定义一个基础类People,继承Mummals类,实现BaseAction接口和SpecialAction接口
/**
* @createtime 2017年3月17日 上午11:25:48
* @description 定义一个普通的类--人类,继承哺乳类,实现基础接口和特殊接口
*/
public class People extends Mammals implements BaseAction,SpecialAction{ @Override
public void study() {
// TODO Auto-generated method stub } @Override
public void eat() {
// TODO Auto-generated method stub } @Override
public void sleep() {
// TODO Auto-generated method stub } @Override
public void nurse() {
// TODO Auto-generated method stub } }
可以看出,一个子类是可以实现多个接口的
最后,让基础类People,同时继承Mummals类和Crawler类
/**
* @createtime 2017年3月17日 上午11:25:48
* @description 定义一个普通的类--人类,继承哺乳类,实现基础接口和特殊接口
*/
public class People extends Mammals,Crawler{
@Override
public void nurse() {
// TODO Auto-generated method stub } }
可以看到报的错惨不忍睹:
其实这个问题很显然,人类是哺乳动物而不是爬行动物,如果一个子类能够同时继承多个类,说明该子类属于多种类型,就像人既是哺乳动物,又是爬行动物,明显违背自然规律,所以一个子类只能继承一个抽象类。但是人既有所有动物哺乳动物都有的吃和睡等基础行为之外,还有着自己特殊的思考行为,所以公共的行为通过实现公共接口完成,而特殊的行为通过实现特殊接口来完成,这样就不矛盾了。(以上纯属个人观点,如有问题,望您能给你指正,谢谢了~)
四、举例
下面我以JFinal这个框架为例,来说说大神们是怎样使用抽象类和方法的,借鉴别人才能提高自己。
1、抽象类
JFinal中,我觉得最重要的抽象类应该是Controller了。
Controller是业务逻辑实现的关键抽象类,是MVC模式的控制中心,就像人的大脑。所有的类要想完成请求-响应的整个过程,都必须依赖这个类,看下面部分代码:
Controller类中既有成员变量也有成员方法,成员变量是我们写代码时,几乎所有的自定义控制类都要使用的http请求、响应相关的一些对象,如HttpServletReqquest、HttpServletResponse等,而成员方法又为我们提供了获取这些对象的行为,除此之外,还有很多实用的方法,如获取前端请求参数、返回响应结果、上传文件、验证等大量的方法,但是这个抽象类中,作者(詹波)并没有写抽象方法,可能有人会问,如果没有抽象方法,何不把它定义成普通类来继承?其实刚开始我也是这样想的,但是仔细想了一下,作者可能是想利用抽象类不能被实例化的这个功能,于是问题又出来了,为什么不让该类被实例化呢?
经过调研,我看到这样一篇文章,讲的是JDK中抽象方法不含抽象类的例子:
http://blog.csdn.net/fancylovejava/article/details/24804541,文章中说之所以它所提到的抽象类没有抽象方法,是因为里面所有的成员方法都是通过构造函数来进行传值,对于这样一个类,我们实例化它是没有意义的。于是按此逻辑看了一下Controller类,发现里面的方法基本上也都是通过构造函数来传参的,可以印证它这种说法,但是再仔细想一想,我们为什么要实例化一个类呢?不就是为了创建一个具体的对象吗。记得前面讲类是说过这么一句话,“Java中所有的对象都是通过类来描述,但并不是所有的类都是用来描述对象的”,我觉得用这句话来解释Controller是不含抽象方法的抽象类再合适不过。
首先,这个类并不是为了描述某个具体的对象而创建,它的作用是提取出所有能够被实例化的类的公共部分,这样可以减少代码量;
其次,它没有抽象方法,所有的成员方法都有实现,而这些实现也是解决了所有处理业务逻辑的类会用到的操作方法。没有抽象类,是因为没有合适的公共行为为所有业务类所有。
2、接口
Jfinal中的主要接口是插件接口IPlugin
它的源码如下:
package com.jfinal.plugin; /**
* IPlugin
*/
public interface IPlugin {
boolean start();
boolean stop();
}
这里面只有两个抽象方法,start()和stop()
而实现它的类有很多,主要是ActiveRecordPlugin和C3pPlugin这两个,它们分别是数据库访问插件和数据库连接池插件,很明显,这两个类在实现IPlugin接口的时候,都实现了start()方法和stop()方法,start()用来启动插件,stop()用来停用插件,在C3p0Plugin中启用插件,开始连接数据库;在ActiveRecordPlugin中启动插件,开始访问数据库;源代码如下:
C3p0Plugin:
public boolean start() {
if (isStarted)
return true; dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
try {dataSource.setDriverClass(driverClass);}
catch (PropertyVetoException e) {dataSource = null; System.err.println("C3p0Plugin start error"); throw new RuntimeException(e);}
dataSource.setMaxPoolSize(maxPoolSize);
dataSource.setMinPoolSize(minPoolSize);
dataSource.setInitialPoolSize(initialPoolSize);
dataSource.setMaxIdleTime(maxIdleTime);
dataSource.setAcquireIncrement(acquireIncrement); isStarted = true;
return true;
}
ActiveRecordPlugin:
public boolean start() {
if (isStarted) {
return true;
}
if (configName == null) {
configName = DbKit.MAIN_CONFIG_NAME;
}
if (dataSource == null && dataSourceProvider != null) {
dataSource = dataSourceProvider.getDataSource();
}
if (dataSource == null) {
throw new RuntimeException("ActiveRecord start error: ActiveRecordPlugin need DataSource or DataSourceProvider");
}
if (config == null) {
config = new Config(configName, dataSource);
} if (dialect != null) {
config.dialect = dialect;
}
if (showSql != null) {
config.showSql = showSql;
}
if (devMode != null) {
config.devMode = devMode;
}
if (transactionLevel != null) {
config.transactionLevel = transactionLevel;
}
if (containerFactory != null) {
config.containerFactory = containerFactory;
}
if (cache != null) {
config.cache = cache;
} new TableBuilder().build(tableList, config);
DbKit.addConfig(config);
Db.init();
isStarted = true;
return true;
}
以上就是自己对Java中的抽象类和接口的理解和认识,突然认识到这些用法都比较适合写框架时使用,平时做开发很少用到,或者说我没用到过,看来高级的东西还是要靠基础理论啊!
下面附上本次调研有用的一些文章链接:
1、Java接口和抽象类的区别:http://www.cnblogs.com/NewDolphin/p/5397297.html
2、抽象类没有抽象方法的例子:http://blog.csdn.net/fancylovejava/article/details/24804541
3、Java实例化对象的过程:http://www.cnblogs.com/funfei/p/5679357.html
Java问题解读系列之基础相关---抽象类和接口的更多相关文章
- Java问题解读系列之基础相关---含继承时的执行顺序
今天来研究一下含继承.静态成员.非静态成员时Java程序的执行顺序: 一.不含继承,含有静态变量.静态代码块 创建一个子类,该类包含静态变量.静态代码块.静态方法.构造方法 /** * @create ...
- Java问题解读系列之String相关---String类为什么是final的?
今天看到一篇名为<Java开发岗位面试题归类汇总>的博客,戳进去看了一下题目,觉得有必要夯实一下基本功了,所以打算边学边以博客的形式归纳总结,每天一道题, 并将该计划称为java问题解读系 ...
- Java问题解读系列之IO相关---Java深拷贝和浅拷贝
前几天和棒棒童鞋讨论Java(TA学的是C++)的时候,他提到一个浅拷贝和深拷贝的问题,当时的我一脸懵圈,感觉自己学Java居然不知道这个知识点,于是今天研究了一番Java中的浅拷贝和深拷贝,下面来做 ...
- Java问题解读系列之String相关---String、StringBuffer、StringBuilder的区别
今天的题目是String.StringBuffer和StringBuilder的区别: 首先还是去官方的API看看对这三种类型的介绍吧,Go...... 一.继承类和实现接口情况 1.String类 ...
- Java问题解读系列之String相关---String类的常用方法?
今天的题目是:String类的常用方法? 首先,我们在eclipse中定义一个字符串,然后使用alt+/就会出现String类的所有方法,如下图所示: 下面我就挑选一些常用的方法进行介绍: 首先定义两 ...
- Java基础之抽象类与接口
Java基础之抽象类与接口 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的时候 ...
- 关于Java中的对象、类、抽象类、接口、继承之间的联系
关于Java中的对象.类.抽象类.接口.继承之间的联系: 导读: 寒假学习JavaSE基础,其中的概念属实比较多,关联性也比较大,再次将相关的知识点复习一些,并理顺其中的关系. 正文: 举个例子:如果 ...
- “全栈2019”Java第六十六章:抽象类与接口详细对比
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 程序猿的日常——Java基础之抽象类与接口、枚举、泛型
再次回顾这些基础内容,发现自己理解的又多了一点.对于一些之前很模糊的概念,渐渐的清晰起来. 抽象类与接口 抽象类通常是描述一些对象的通用方法和属性,并且默认实现一些功能,它不能被实例化.接口仅仅是描述 ...
随机推荐
- [JZOJ3168] 【GDOI2013模拟3】踢足球
题目 描述 题目大意 有两个队伍,每个队伍各nnn人. 接到球的某个人会再下一刻随机地传给自己人.敌人和射门,射门有概率会中. 每次射门之后球权在对方111号选手. 某个队伍到了RRR分,或者总时间到 ...
- ActiveMQ 知识点
消息队列高可用 持久化,事务,签收,zookeeper+replicated-leveldb-store的主从集群 异步发送 同步发送: 明确指定同步发送 未使用事务的前提下,发送持久化消息(会使用同 ...
- springboot让内置tomcat失效
一.POM(去除内嵌tomcat后,需要添加servlet依赖) <dependency> <groupId>org.springframework.boot</grou ...
- Delphi的日志库
1. 安装 Log4D下载: 官网地址 LoggerPro下载 GitHub地址 特点: log4d简单易用.性能稳定 LoggerPro貌似功能很强大,只是没有详细的文档,懒得翻源码 安装步骤 Lo ...
- 批量插入或更新操作之ON DUPLICATE KEY UPDATE用法
实际的开发过程中,可能会遇到这样的需求,先判断某一记录是否存在,如果不存在,添加记录,如果存在,则修改数据.在INSERT语句末尾指定ON DUPLICATE KEY UPDATE可以解决这类问题. ...
- 《数据结构与算法分析——C语言描述》ADT实现(NO.05) : 散列(Hash)
散列(Hash)是一种以常数复杂度实现查找功能的数据结构.它将一个关键词Key,通过某种映射(哈希函数)转化成索引值直接定位到相应位置. 实现散列有两个关键,一是哈希函数的选择,二是冲突的处理. 对于 ...
- for update行级锁的作用
1.for update叫排它锁,是一种行级锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该表中的数据行,则 ...
- 2018-12-21-WPF-弹出-popup-里面的-TextBox-无法输入汉字
title author date CreateTime categories WPF 弹出 popup 里面的 TextBox 无法输入汉字 lindexi 2018-12-21 18:10:30 ...
- HBase Master-status
- Gartner首推机密计算:阿里云名列其中
近日,全球信息技术研究机构Gartner发布了2019年云安全技术成熟度曲线报告(Gartner, Hype Cycle for Cloud Security, 2019, Jay Heiser, S ...