面向对象程序设计中,类继承的主要作用的扩充已有类的功能。子类可以根据自己的需要选择是否要覆写父类中的方法,所以一个设计完善的父类是无法对子类做出任何强制性的覆写约定。为了解决这样的设计问题,提出抽象类的概念,抽象类与普通类相比唯一增加的就是抽象方法的定义,同时抽象类在使用时要求必须被子类所继承,并且子类必须覆写全部抽象方法。
抽象类基本定义
抽象类需要使用abstract class进行定义,并且在一个抽象类中也可以使用abstract关键字定义若干个抽象方法,这样抽象类的子类就必须在继承抽象类时强制覆写全部抽象方法。
abstract class Message {
private String type;
// 定义抽象方法,抽象方法只定义方法名,没有方法体
public abstract String getConnectInfo();
// 普通方法
public void setType(String type) {
this.type = type;
}
public String getType() {
return this.type;
}
}
使用抽象类
class NetMessage extends Message {
@Override
public String getConnectInfo() {
return '获取【' + super.getType() + '】消息连接……'
}
}
class JavaDemo {
public static void main(String[] args) {
Message msg = new NetMessage();
msg.setType('UITHML');
System.out.println(msg.getConnectInfo());
}
}
抽象类最大的特点就是无法自己直接进行对象实例化操作,所以在实际项目开发中,抽象类的主要目的是进行过度操作。当你要使用抽象类进行实际开发的时候,往往都是在你设计中选哟解决类继承问题时所带来的代码重复问题。
抽象类相关说明
- 抽象类必须由子类继承,所以在定义时不允许使用final关键字定义抽象类或抽象方法。
- 抽象类中可以可以定义成员属性和普通方法,为了可以为抽象类中的成员属性初始化,可以在抽象类提供构造方法。子类在继承抽象类时会默认调用父类的无参构造,如果抽象类没有提供无参构造方法,则子类必须通过super()的形式调用指定参数的构造方法。
- 抽象类中允许没有抽象方法。
- 抽象类中可以提供static方法,并且该类方法不受到抽象类实例化对象的限制。
- 抽象类只能被继承,不能使用new关键字实例化。
包装类
Java是一门面向对象的编程语言,所有的设计都是围绕着对象这一核心概念展开,但与这一设计有所违背的就是基本数据类型(byte、short、int、long、float、double、char、boolean),所以为了符合这一特点可以利用类的结构对基本数据类型进行包装。
class Int {
private int data;
public Int(int data) {
this.data = data;
}
public int intValue() {
return this.data;
}
}
class JavaDemo {
public static void main(String[] args) {
Object obj = new Int(10); // 【装箱操作】将基本数据类型保存在包装类中
int x = ((Int) obj).intValue(); // 【拆箱操作】从包装类对象中获取基本数据类型
}
}
本程序定义了一个int包装类,并且在类中存储有int数据信息,利用这样的包装处理就可以使用Object类来进行基本数据类型的接受,从而实现参数的完全统一处理。
Java中包装类可以分为两种类型。
- 对象型包装类(Object直接子类):Boolean、Character。
- 数值型包装类(Number直接子类):Byte、Short、Integer、Long、Float、Double。
装箱与拆箱
基本数据类型的包装类都是为了基本数据类型转换为对象引用而提供的,这样对于基本数据类型与包装类之间就有了以下的转换操作关系。
数据装箱:将基本数据类型保存到包装类中,一般可以利用包装类的构造方法完成。
数据拆箱:从包装类中获取基本数据类型。
数据类型转换
在项目编写中往往需要提供有交互式的运行环境,即需要根据用户输入内容的不同来进行不同的处理,但是在Java程序中所有输入的内容都会利用String类型来描述,所以就需要通过包装类来实现各自不同数据类型的转换。
class JavaDemo {
public static void main(String[] args) {
String str = '123'; // 声明字符串数值
String str1 = 'true'; // 声明字符串true
int num = Integer.parseInt(str); // 字符串转换成int
boolean flag = Boolean.parseBoolean(str); // 字符串转换成Boolean,结果为false
boolean flag1 = Boolean.parseBoolean(str1); // true
}
}
字符串转换成boolean型数据时,如果字符串的组成时true或false则可以按照要求进行转换,如果不是,则为了避免程序出错,会统一转换为false。
接口
接口在实际开发中是由一种比抽象类更为重要的结构组成,接口的主要特点在于其用于定义开发标准。
在Java中接口属于一种特殊的类,需要通过interface关键字进行定义,在接口中可以定义全局变量、抽象方法(必须是public访问权限)、default方法和static方法。
定义标准接口
interface IMessage {
public static final String INFO = 'www.uihtml.cn'; // public static final可省略
public abstract String getInfo(); // abstract可省略
}
本程序定义了一个IMessage接口,由于接口中存在有抽象方法,所以无法被直接实例化,其实用原则如下:
- 接口需要被子类实现,子类利用implements关键字可以实现多个父接口。
- 子类如果不是抽象类,那么一定呀覆写接口中的全部抽象方法。
- 接口对象可以利用子类对象的向上转型进行实例化。
class MessageImpl implements IMessage {
@Override
public String getInfo() {
return 'www.uihtml.cn'
}
}
class JavaDemo {
public static void main(String[] args){
IMessage msg = new MessageImpl(); // 向上转型,子类实例化父接口
System.out.println(msg.getInfo());
}
}
子类可以继承父类也可以实现父接口
class 子类 [extends 父类] [implements 接口1,接口2,...] {}
如果出现混合应用,则要采用先继承(extends)再实现(implements)的顺序完成,同时一定要注意,子类接口的最大特点在于可以同时实现多个父接口,而每一个子类只能通过extends继承一个父类。
interface IMessage {
public static final String INFO = 'www.uihtml.cn';
public abstract String getInfo();
}
interface IChannel {
public abstract boolean connect();
}
abstract class NetMessage {
public abstract boolean getNetConnect();
}
class MessageImpl extends NetMessage implements IMessage,Ichannel {
@Override
public boolean connect() {
return true;
}
@Override
public boolean getNetConnect() {
return true;
}
@Override
public String getInfo() {
if (this.connect()) {
if(this.getNetConnect()) {
return '【网络正常,链接到uihtml.cn】';
} else {
return '【网络异常,无法链接到uihtml.cn】';
}
}
return '【默认消息】' + IMessage.INFO;
}
}
class JavaDemo {
public static void main(String[] args) {
IMessage msg = new MessageImpl();
System.out.prinltn(msg.getInfo());
}
}
Java中的extends关键字除了具有类继承的作用外,也可以在接口上使用,以实现接口的继承关系,并且可以同时实现多个父接口。
interface IMessage {
public static final String INFO = 'www.uihtml.cn';
public abstract String getInfo();
}
interface IChannel {
public boolean connect();
}
interface IService extends IMessage,IChannel {
public String service();
}
class MessageService implements IService {
@Override
public boolean connect() {
return true;
}
@Override
public String getInfo() {
return IMessage.INFO;
}
@Override
public String service() {
return '服务消息:www.uihtml.cn';
}
}
本程序在定义IService接口时,让其继承了IMessage、IChannel两个父接口,这样IService接口就有了两个父接口定义的所有抽象方法。
接口时面向对象程序设计中最为重要的话题,在实际项目中的核心用处是实现方法名称的暴露与子类的隐藏。
接口定义加强
在接口中使用default定义普通方法
interface IMessage {
public String message();
// 定义普通方法,该方法可以被子类继承或覆写
public default boolean connect() {
System.out.println('建立默认订阅消息通道连接');
return true;
}
}
class MessageImpl implements IMessage {
@Override
public String message() {
return 'www.uihtml.cn';
}
}
class JavaDemo {
public static void main(String[] args) {
IMessage msg = new MessageImpl();
if (msg.connect()) {
System.out.println(msg.message());
}
}
}
本程序在IMessage接口中利用default定义了普通方法,这样接口中的组成就不再只有抽象方法,同时这些default定义的普通方法也可以直接被子类继承。
接口中定义普通方法的意义在于:便于扩充接口功能,同时简化设计结构。
在接口中定义static方法
使用default定义的普通方法需要通过接口实例化对象才可以调用,而为了避免实例化对对象的依赖,在接口中也可以使用static定义方法,此方法可以直接利用接口名称调用。
interface IMessage {
// 定义抽象方法
public String message();
// 定义普通方法
public default boolean connect() {
System.out.println('建立默认消息订阅连接通道');
return true;
}
// 定义static方法,可以通过接口名称直接调用
public static IMessage getInstance() {
return new MessageImpl();
}
}
class MessageImpl implements IMessage{
@Override
public String message() {
if(this.connect()) {
return 'www.uihtml.cn'
}
return '没有消息需要发送'
}
}
class JavaDemo {
public static void main(String[] args) {
IMessage msg = IMessage.getInstance();
System.out.println(msg.message());
}
}
定义接口标准
interface IUSB {
public boolean check();
public void work();
}
class Computer {
public void plugin(IUSB usb) {
if (usb.check()) {
usb.work();
} else {
System.out.println('硬件出现问题,无法工作……');
}
}
}
class Keyboard implements IUSB {
@Override
public boolean check() {
return true;
}
@Override
public void work() {
System.out.println('通过键盘,键入网址:www.uihtml.cn');
}
}
class JavaDemo {
public static void main(String[] args) {
Computer computer = new Computer();
computer.plugin(new Keyboard());
}
}
抽象类与接口的区别
区别 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract class | interface |
组成 | 常量、变量、抽象方法、普通方法、构造方法 | 全局常量、抽象方法、普通方法、静态方法 |
权限 | 可以使用各种权限 | 只能是public |
关系 | 一个抽象类可以实现多个接口 | 接口不能继承抽象类,却可以继承多接口 |
使用 | 子类使用extends继承抽象类 | 子类使用implements实现接口 |
设计模式 | 模板设计模式 | 工厂设计模式、代理设计模式 |
局限 | 一个子类只能够继承一个抽象类 | 一个子类可以实现多个接口 |
原创文章,作者:ZERO,如若转载,请注明出处:https://www.edu24.cn/course/java/java-abstract-class-interface.html