前言
抽象类和接口是Java学习中比重要的一部分,今天我们就一起来学习一下他们!
一、抽象类是什么?
在学过JAVA的继承和多态之后,我们会有这样的思考,在继承的层次结构中,每个从父类继承而来的子类都是对父类的更加详细的演化,那么反过来呢?子类向上追随自己的父类,父类越来越简化和抽象。有时候,一个父类设计得非常抽象,以至于他没有任何实例。像这样的类我们称它为抽象类 (abstract class)
举个例子 图形类(Geometry)代表几何图形,它便是一个抽象类,他没有什么实例对象,他的getArea方法也没有任何意义。因为无法确定是什么具体的形状,但几何图形又都有面积这个共性,所以每个子类都要重写getArea方法。
1、抽象方法
通过关键字abstract 将抽象类的中的方法定义为抽象方法
抽象方法是出现在父类中的一种方法,要求在子类中被重写
一个抽象类只有方法头,没有方法主体
抽象方法的定义格式: 访问修饰符 abstract 返回类型 方法名(参数列表);
例如 public abstract void getArea();
包含抽象方法的类就是抽象类
必须用abstract 声明
如果子类没有重写父类的抽象方法,编译器会报错
抽象方法会确保子类会实现这个方法
2、再谈抽象类
- 若有抽象方法 , 则类必须以
abstract 关键字声明为抽象类 - public abstract class 类名
- 抽象类可以包含零至多个普通方法(
注意:抽象类是可以有普通方法的 ),也可以包含零至多个抽象方法(抽象类中的不论普通方法还是抽象方法对方法数量都是没有要求的 ) - 不论抽象类是否含抽象方法,其余都不允许实例化,即不能
创建抽象类的对象,因为其描述的是抽象概念。它只能作 为其他类的基类。 - 若父类是抽象类,且子类不想成为抽象类,则子类必须将
父类中的所有抽象方法重写为带方法体的普通方法,否则 子类仍必须是抽象类
3、抽象类实例学习
拍卖会的时候,拍卖师负责观察竞价者中最高的出价,并将此价格公布给其他的竞价者,此模式可以构建一个抽象类模型
步骤一
import java.util.ArraList;
import java.util.List;
public class Subject{ (1)
private ArrayList<Observe>observes = new ArrayList<Observe>();整体-部分
private int state; 主题-观察者
public int getState(){
return state;
}
public setState(int state){ (3)状态变化-通知观察者
this.state = state;
notifyAllObserves();
}
public void attach(Observer observer){ (2)整体-部分:聚合
observers.add(observer); 主题聚合了多个观察者
}
public void notifyAllOberserves(){
for (Oberserver observer : observers){ (4)访问具体观察者
observer.update(); 利用多态实现;通过observer访问继承类的重写方法
}
}
}
步骤二
public abstract class Obersver{
protected Subject subject; 观察者-抽象类;需要通过继承重写抽象方法
public abstract void update();
}
步骤三
创建实体观察者类
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject ;
this.subject.attach(this); 将自己注册到主题类中,使得主体能通知
}
@override
public void update(){
System.out.println("Binary String : " + Integer.toBinaryString(subject.getState()));
}
}
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject ;
this.subject.attach(this);
}
@override
public void update(){
System.out.println("Octal String : " + Integer.toOctalString(subject.getState()));
}
}
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject ;
this.subject.attach(this);
}
@override
public void update(){
System.out.println("Hex String : " + Integer.toHexString(subject.getState()).toUpdateCase());
}
}
步骤四 使用subject 和实体观察对象。
public class OberverPatternDemo{
public static void mian(String[] args){
Subject suject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(suject);
System.out.println("First state change : 15");
subject.setState(15);
System.out.println("Second state change : 10");
subject.setState(10);
}
}
步骤五
输出结果 这个例子中,Observer为抽象类,它拥有一个抽象方法,它的子类BinaryObserver,OctalObserver,HexaObserver,在自己的类中重写了update方法,并且可以有自己的实例对象。
二、接口
1、什么是接口
接口是一种与类类似的结构注意:接口是一种结构 ,用于为对象定义共同的操作。
接口定义格式
public interface 接口名称{
(方法头···)
}
举个例子
public interface Edible{
public abstract String hoeToEat();
}
- 接口中所有方法都是public 抽象方法
- 一个类可以实现一个或者多个接口
- 接口和所有方法都是抽象方法的抽象类非常类似(它不能被实例化,并且接口中的所有方法都要被重写
注意:所有方法都要被重写 ) - 接口的作用是为了给其他类提供行为说明
- 一个接口看起来就像一个类,除了:
关键字interface 替换了关键字 class, 以及 接口中的方法只有方法头加分号结尾,没有方法主体 。
2、接口的属性
- 一个接口可以有属性:
在接口中的所有属性都为 public static final,所有方法都为public abstract(也就是说接口的属性是在定义接口的时候就已经固定下来的,下面实现该接口的类也会拥有接口的属性,并且无法改变,因此在定义接口时就要赋初值 ) Java 允许忽略这些修饰符。 例如
public interface Doable
{
public static final int FIELD1 = 1, FIELD2 = 2;
public abstract void p();
}
在这个接口中, FIELD1 和 FIELD2 是 public final static int 变量。
**等价于**
public interface Doable
{
int FIELD1 = 1, FIELD2 = 2;
void p();
}
注意:尽管public 在接口定义时可以省略,但是在子类实现方法时必须定义为public
任何实现这个接口的类都可以访问 这些变量
3、接口的实现
- 如果一个类要实现接口,它需要在类头中使用==implements ==关键字
实现多接口
- 一个类只能从一个基类派生
Java 允许一个类实现多个接口 - 当一个类实现多个接口,它必须实现所有接口中的方法
- 接口名之间用逗号分隔
例如
public class MyClass implements Interface1, Interface2,Interface3
接口样例
Cloneable接口指定了一个对象可以被克隆
步骤一
创建一个接口
public interface Image{
void display();
}
步骤二
创建实现接口类的实体类
public RealImage implements Image{
public String Filename;
public RealImage(String Filename){
this.Filename = Filename;
loadFromDisk(Filename);
}
@overrride
public void display(){
System.out.println("Displaying " + Filename);
}
private void loadFromDisk(String Filename){
System.out.println("Loading " + Filename);
}
}
public class ProxyImage implements Image{
private RealImage realImage;
private String Filename;
public ProxyImage(String Filename){
this.Filename = Filename;
}
@override
public void display(){
if(realImage == null){
realImage = new RealImage(Filename);
}
realImage.display();
}
}
步骤三
当被请求时ProxyImage来获取RealImage类的对象
public class ProxyPatternDemo{
public static void mian(String[] args){
Image image = new ProxyImage("test_10mb.jpg");
image.display();
system.out.println("");
image.display();
}
}
步骤四
输出结果
三、 抽象类和接口的异同
比较点 | 抽象类 |
---|
关键字 | abstract | 变量 | 无限制 | 方法 | 既可以有普通方法,也可以有抽象方法 | 继承/实现 | 只能被类或抽象类继承 | 多重继承 | 不支持 | 构造方法 | 子类通过构造方法链调用构造方法,抽象类不能用new操作符实例化 |
比较点 | 接口 |
---|
关键字 | interface | 变量 | 必须是public static final | 方法 | 只含抽象方法,必须是public | 继承/实现 | 既可以被接口继承也可以被类或者抽象类继承 | 多重继承 | 支持继承多个父接口 | 构造方法 | 没有构造方法 |
总结
Java中的抽象类和接口都是为了更好的实现类的作用,接口相当于给抽象类或者是类指明一个方向,具体的实现操作需要具体的类内部自己实现更细微的操作。
感谢阅读!!!!!
|