抽象类
概述
- 定义:
- 类和类之间具有某些共同特征,将这些共同特征抽取出来,使用一个新的类来接收,这个类就是抽象类
- 因为是类的抽象,所以抽象类无法创建对象
- 类型
- 抽象类数据引用数据类型
- 语法
- [修饰符列表] abstract class 类名 {类体}
- 实例
package Day12抽象类和接口;
public class Test01 {
public static void main(String[] args) {
//new User(); //java: Day12抽象类和接口.User是抽象的; 无法实例化
}
}
abstract class User{
String name;
public User() {
}
public User(String name) {
this.name = name;
}
}
抽象类的构造方法
- 抽象类因为不能被实例化,所以抽象类生来就是被继承的
- final 和 abstract 不能联合使用,这两个关键字对象
- 抽象类的子类也可以是抽象类
- 抽象类有构造方法,这个构造方法是给子类使用的
package Day12抽象类和接口;
public class Test01 {
public static void main(String[] args) {
//new User(); //java: Day12抽象类和接口.User是抽象的; 无法实例化
Vip vip = new Vip("张三");
}
}
abstract class User{
String name;
public User() {
}
public User(String name) {
this.name = name;
}
}
class Vip extends User{
public Vip() {
super();
}
public Vip(String name) {
super(name);
}
}
//抽象类的子类也可以是抽象类
abstract class Normal extends User{
public Normal() {
super();
}
public Normal(String name) {
super(name);
}
}
//final 和 abstract 修饰同一个类
//abstract final class Person{}
//java: 非法的修饰符组合: abstract和final
抽象方法
- 定义
- 没有实现的方法,没有方法体的方法
- public abstarct void doSome();
- 特点
- 没有方法体,以分号结尾
- 修饰符列表中有 abstract 关键字
- 实例
package Day12抽象类和接口;
public class Test02 {
public static void main(String[] args) {
Person.doOther();
Chinese chinese = new Chinese();
chinese.shouldDo();
chinese.doSome();
}
}
abstract class Person{
//抽象方法
public abstract void doSome();
//实例方法 —— 因为抽象类不能实例化对象,所以实例方法是无法实现的,但是可以用子类继承实现
public void shouldDo(){
System.out.println("shouldDo..");
}
//静态方法
public static void doOther(){
System.out.println("doOther...");
}
}
class Chinese extends Person{
@Override
public void doSome() {
System.out.println("doSome...");
}
@Override
public void shouldDo() {
super.shouldDo();
}
}
所以可以看出:抽象类中不一定有抽象方法,但是抽象方法一档在抽象类中
非抽象类继承抽象类必须实现抽象方法
- 强行规定,否则会报错
package Day12抽象类和接口;
public class Test03 {
public static void main(String[] args) {
American american = new American();
american.doSome();
}
}
abstract class People{
public abstract void doSome();
}
class American extends People{
//java: Day12抽象类和接口.American不是抽象的, 并且未覆盖Day12抽象类和接口.People中的抽象方法doSome()
@Override
public void doSome() {
System.out.println("doSome...");
}
}
abstract class Japanese extends People{
//子类也是抽象类的时候,就不需要实现父类的抽象方法
}
- 面对抽象编程,不面向具体编程,降低程序的耦合度,提高程序的扩展力
- 符合OCP原则
- 编译的时候,doSome()方法是People的
- 运行的时候。doSome()方法是American的
- 若子类也是抽象类,就不需要实现父类的抽象方法
接口
概述
- 接口是一种“引用数据类型”
- 接口是完全抽象的
- 语法:[修饰符列表] interface 接口名 { }
- 接口支持多继承
- 接口中只有 常量 和 抽象方法
- 接口中所有元素都是 公开的
- 接口中抽象方法的public abstract 可以省略
- 接口中常量的public static final 可以省略
- 接口中方法不能有方法体
- 实例
package Day12抽象类和接口;
public class Test04 {
public static void main(String[] args) {
}
}
interface A{}
interface B{}
//接口支持继承
interface C extends A,B{}
interface MyMath{
//常量
public static final double PI = 3.1415;
double PAI = 3.1415;
//抽象方法
public void doSome1();
void doSome();
public int sub(int a, int b);
int sum(int a, int b);
//方法不能有方法体
//public void doOther(){} //java: 接口抽象方法不能带有主体
}
类和接口的关系
- 类和类之间叫做继承,类和接口之间叫做实现
- 也可以看作是继承
- 实现需要关键字:implements
- 当一个非抽象类实现接口的时候,必须将接口中的所有方法全部重写
package Day12抽象类和接口;
public class Test05 {
public static void main(String[] args) {
Kkx k = new Kkx();
k.doSome();
}
}
interface Bbc{
void doSome();
}
class Kkx implements Bbc{
//java: Day12抽象类和接口.Kkx不是抽象的, 并且未覆盖Day12抽象类和接口.Bbc中的抽象方法doSome()
@Override
public void doSome() {
System.out.println("doSome..");
}
}
接口和多态联合使用
package Day12抽象类和接口;
public class Test06 implements MyMath1{
@Override
public int sum(int a, int b) {
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
public static void main(String[] args) {
//多态和接口联合使用
MyMath1 m = new Test06();
int sub = m.sub(1, 1);
System.out.println(sub);
int sum = m.sum(1, 1);
System.out.println(sum);
}
}
interface MyMath1{
double PI = 3.1415;
int sum(int a, int b);
int sub(int a, int b);
}
一个类实现多个接口
- 接口和接口之间支持多继承,那么一个类可以实现多个接口吗?
- 可以的
- 这种机制弥补了Java中类不能多继承的缺点
- 子类需要将接口中方法全部实现(因为接口中的方法都是抽象想法)
- 注
- 无论向上转型还是向下转型,两种类型之间必须要有继承关系,这句话在接口这里并不适用
- 但是向下转型的时候还是需要使用 instanceof 进行判断
- 实例
package Day12抽象类和接口;
public class Test07 {
public static void main(String[] args) {
//接口的多态
Fly fly = new Bird();
Speak speak = new Parrot();
Glissade glissade = new Penguin();
fly.fly();
speak.speak();
glissade.glissade();
//直接向下转型是可以的
Speak speak1 = (Speak) fly;
speak1.speak();
//不使用 instanceof 可能出现的问题:java.lang.ClassCastException
Move move = new Elephant();
// Kill kill = (Kill)move;
/*
* 编译不会报错,但是运行有问题
* 因为:move是Elephant对象,而Elephant和Kill没有关系,所以报错
* 之前失败是因为Animal实现了Speak、FLying、Glissade三个接口,
* 然后Bird、Parrot、Penguin又继承了Animal类,
* 所以创建的对象是和三个接口都有关系的
* 导致没有报错
* */
//上述情况使用instanceof
if (move instanceof Kill){
Kill kill = (Kill)move;
System.out.println("向下转型成功");
}
}
}
interface Kill{}
interface Move{}
class Elephant implements Move{
}
interface Fly{
void fly();
}
interface Speak{
void speak();
}
interface Glissade{
void glissade();
}
interface Trait extends Fly,Speak,Glissade{}
class Animal implements Fly,Speak,Glissade{
@Override
public void fly() {
}
@Override
public void speak() {
}
@Override
public void glissade() {
}
}
class Bird extends Animal{
@Override
public void fly() {
System.out.println("鸟儿可以飞");
}
}
class Parrot extends Animal{
@Override
public void speak() {
System.out.println("鹦鹉可以说话");
}
}
class Penguin implements Glissade{
@Override
public void glissade() {
System.out.println("企鹅可以滑行");
}
}
extends和implement同时出现
- 某个类继承了父类,且实现了接口,创建对象的时候,使用的接口,则只能使用接口中的方法,反之亦然(利用了多态机制)
- 怎么才能打破上述情况 —— 向下转型
- 实例
package Day12抽象类和接口;
public class Test08 {
public static void main(String[] args) {
Jump cat = new Cat();
cat.jump();
Pet cat1 = new Cat();
cat1.eat();
cat1.play();
//向下转型
Pet cat2 = (Pet)cat;
cat2.play();
}
}
interface Jump{
void jump();
}
class Pet{
public void eat(){}
public void play(){}
}
class Cat extends Pet implements Jump{
@Override
public void eat() {
System.out.println("猫猫吃鱼");
}
@Override
public void play() {
System.out.println("猫猫玩毛球");
}
@Override
public void jump() {
System.out.println("猫猫可以跳得很高");
}
}