面向对象-抽象
目录
什么是抽象类
抽象类就是由类与类之间进行共性抽取,进一步抽象而形成的。
1.1、abstract关键字
abstract抽象修饰符可以修饰方法和类,使用abstract修饰符修饰的方法称为抽象方法,使用abstract修饰符修饰的类称为抽象类。在抽象方法中是没有方法体的,并且以分号结尾。例如我们定义一个交通工具停止方法,如下:
public class Transport{
//定义抽象方法
public abstract void stop();
}
1.2、抽象类的定义
抽象类的语法格式
[修饰符列表] abstract class 类名{类体}
当一个类中具有抽象方法时,该类就被视为一个抽象类。
注意:抽象类不能创建对象也就是不能给抽象类创建类的实例(抽象类不能用new创建对象)
Transportation t=new Transportation();//错误的
Transportation t=new Car();//正确
1.3、抽象类的特点
- 抽象类不能被实例化,只能由子类继承由子类实例化;但是抽象类中有构造方法,这个构造方法是给抽象类的非抽象子类提供的。
- 抽象类的子类可以是抽象类也可以是非抽象类
- final和abstract不能同时使用,他们是对立的(被final修饰类不能有子类,被abstract修饰的类只有子类继承才能实例化对象)
1.4、 抽象方法的特点
- 抽象方法以";"结尾
- 抽象方法被abstract关键字修饰
- 抽象方法由非抽象子类来实现
抽象类与抽象方法的关系
- 抽象类中不一定有抽象方法,但抽象方法一定要写在抽象类中。
- 非抽象子类继承抽象类,要求非抽象子类必须重写抽象类中的所有抽象方法。
1.5、抽象方法的限制
- final方法不能为抽象方法,这是因为final的方法不能被重写,但是抽象方法必须经过子类重写才能被使用
- 私有方法不能被定义为抽象方法,私有方法并不能被子类继承,而抽象方法必须被子类继承,然后重写实现。
- 静态方法不能被定义为抽象方法,因为抽象方法所在的抽象类是不能创建对象的,也就是不能够被实例化的。但是静态方法是可以通过类名调用,这样调用抽象方法是没有任何意义的
- 抽象类的构造器存在的意义,为了约定子类的构造器必须和父类要匹配
- 一个类如果继承了一个抽象类,就必须重写这个抽象类所有的抽象方法
二、接口
2.1、接口的定义
接口和父类有很多相似的地方,在程序中也是这样的,但是他们表示的含义完全不同。但是接口对外提供的是一个窗口的功能,子类可以同时接收多个接口,而一个子类只能有一个父类,interface是定义接口的关键字,当有该关键字时,就表示这里定义的是一个接口,和class命名的规则相同。abstract关键字并不是必须的,如果定义时不给出系统也会自动加上。当一个类实现一个接口时,需要使用implements关键字,后面跟上接口名,位置是和extends关键字继承父类一样的。接口的定义和实现:
[abstract] interface<J接口名>{
//定义在接口中的方法与成员变量
}
2.2、接口的基础语法
- 接口是一种引用数据类型,编译后生成字节码文件。
- 接口是完全抽象的(类是半抽象的),或者说接口是一种特殊的抽象类。
- 接口与接口之间支持多继承。
- 接口中只包含常量和抽象方法(java7之前)。
- 接口中所有的元素都是被public修饰的。
- 接口中的抽象类在定义时可以省略"public abstract"。
- 接口中的抽象类不可以省略方法体。
- 接口中的常量在定义时可以省略"public static final"。
- 一个非抽象类实现了接口,要求这个类重写接口中所有的抽象类(抽象类可以不重写)
- 一个类可以实现多个接口
- extends和implements可以共存,语法格式是:[修饰符列表] 类名 extends 类名 implement 接口名{}
2.3、向下转型问题
- 要求类与类之间必须有继承关系,没有继承关系编译器会报错
- 如果两个类之间有继承关系可以通过编译期,但是在运行期也可能出现ClassCaseException
public class Test2 {
public static void main(String[] args){
D d = new A();
B b = (B)d;
}
}
class A extends D{}
class B extends D{}
class D{}
在编译期,编译器检测到D的子类有A和B。所以将D类型的d转换成B类型编译器会认为是合法的(骗过编译器)。但是在运行期检测到d实际是A类型,而A类型与B类型没有继承关系(A不是B),无法转换。所以在此处抛出CaseException
接口与接口之间的向下转型
接口与接口之间没有继承关系也可以进行转型,只不过会在运行期可能会出现ClassCaseException
public class Test3 {
//接口与接口之间的转型
public static void main(String[] asrgs){
D d = new A();
E e = new B();
E e2 = (E)d;
}
}
class A implements D{public void method1(){}}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
运行结果如下,可以看出接口与接口之间没有继承关系可以通过编译期,但是在运行期间可能会出现ClassCaseException
在编译期,编译器检查到d是D类型;在运行期,检测到d实际是A类型,而A类型与E类型没有实现关系(A不像E),所以此处会出现异常。那么如果A类型与同时与D类型和E类型有实现关系在运行期间就不会出现ClassCase异常么,我们来看以下代码
public class Test3 {
//接口与接口之间的转型
public static void main(String[] asrgs){
D d = new A();
E e = new B();
E e2 = (E)d;
}
}
class A implements D,E{
public void method1(){}
public void method2(){}
}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
运行结果如下,可以看出如果一个类同时实现了多个接口,哪怕这些接口之间没有继承关系,这些接口之间也能彼此进行转型,同时能通过编译期和运行期
当然这么转型后实现类只能调用转型后接口中的方法,否则无法通过编译期。
类与接口之间的向下转型
- 如果类与接口之间没有实现关系编译期会报错
- 如果类与接口之间有实现关系,在运行期间可能会出现ClassCaseException
2.4、抽象类与接口的区别
- 抽象类是半抽象的,接口时完全抽象的
- 抽象类中有构造方法,接口只能没有构造方法
- 接口与接口之间支持多继承,类与类之间只支持单继承
- 一个类可以实现多个接口,但一个抽象类只能继承一个类
- 接口中只允许有常量和抽象方法(java7之前)
2.5、接口在开发中的作用
面向接口编程,降低程序之间的耦合度,提高程序的扩展力
三、匿名实现类
public static void main(String[] args) {
Abstr01 a01 = new Abstr01() {
@Override
public void show() {
System.out.println("重写过后的show方法");
}
};
a01.show();
}