Java中的抽象类、接口和多态
一、抽象类
抽象类就是用关键字abstract修饰的类,它有构造器,但是不能被实例化,可以被继承。抽象类可以把子类中相同的代码和方法声明抽取到父类中,这样能更好地支持多态,提高代码的灵活度,并且可以强制子类重写抽象方法。反过来,在我们不知道未来的业务该怎么实现时,可以定义抽象类和方法声明,让子类去继承,这样方便扩展业务
什么是抽象方法?
抽象方法就是用abstract修饰的方法,定义在抽象类中的抽象方法没有方法体,并且后面要加分号
注意事项:
1、抽象类中不一定要有抽象方法,但一个类中定义了抽象方法,那么这个类就一定要定义成抽象类
2、一个类继承了抽象类,就一定要重写父类中所有的抽象方法,除非这个子类也是抽象类,就不会强制要求重写抽象方法
3、抽象类有无参构造方法,但无法创建对象,需要通过多态的形式创建子类对象从而使用重写的抽象方法
abstract class Father {
//抽象方法
public abstract void print();
}
class Son extends Father {
//重写的抽象方法
@Override
public void print() {
System.out.println("我是Son类的方法");
}
}
什么是模版方法?
模版方法是为了解决多个类中方法里代码的重复而设计的方案
模版方法的设计:
1、定义一个抽象类
2、在抽象类中定义一个用final修饰的普通方法(模版方法),方法体中书写重复的代码
3、定义一个抽象方法,让继承抽象类的子类重写这个方法,里面书写子类特殊代码
4、在模版方法中合适的位置调用重写的抽象方法
public class Test {
public static void main(String[] args) {
Employee coder = new Coder();
Employee cooker = new Cooker();
coder.work();
System.out.println("--------------------");
cooker.work();
}
}
abstract class Employee{
//定义模版方法
public final void work() {
//相同代码
System.out.println("我上班啦~~~");
//特有的代码
myWork();
//相同代码
System.out.println("终于下班了~~~");
}
public abstract void myWork();
}
class Coder extends Employee {
//重写方法
@Override
public void myWork() {
System.out.println("上班打代码了~~");
}
}
class Cooker extends Employee {
//重写方法
@Override
public void myWork() {
System.out.println("炒菜炒到冒烟了~~");
}
}
二、接口
什么是接口?
接口是一种类似于抽象类的结构,它用interface修饰,是一种特殊的结构。接口的定义的变量都是常量,需要在定义的时候赋值,如果定义没有任何修饰符所修饰的方法时,方法前面默认会用public abstract修饰,不能随意的改变修饰符,不然会报错
interface USB{
//方法前面默认用public abstract修饰
void connect();
}
接口的好处?
1、接口的实现类强制重写接口中的抽象方法,并且实现类可以同时实现多个接口,弥补了继承结构中单继承的不足,可以让一个类具有更多的身份
2、让程序面向接口进行编程,让程序员更方便的切换不同的业务
3、接口比较纯粹,我们在接口中一般都是定义抽象方法
public class Test {
public static void main(String[] args) {
GoChina china = new GO();
GoRussia russia = new GO();
china.gotoChina();
System.out.println("--------------------");
russia.gotoRussia();
}
}
interface GoChina {
void gotoChina();
}
interface GoRussia {
void gotoRussia();
}
class GO implements GoChina,GoRussia {
@Override
public void gotoChina() {
System.out.println("去中国旅行~~");
}
@Override
public void gotoRussia() {
System.out.println("去俄罗斯旅行~~");
}
}
接口JDK8增加的新特性:
1、接口中可以用default的修饰方法,表示默认方法,实现类不需要重写这个方法,并且通过实现类的对象来调用方法
2、接口中用static修饰的方法表示静态方法,实现类也不能重写这个方法,并且只能通过接口名来调用这个方法
3、接口中用private修饰的方法表示私有方法,不能被实现类重写,一般只用在接口中的默认方法里
interface USB {
//默认方法
default void connect(){
test();
System.out.println("连接上了键盘...");
}
//静态方法
static void exit() {
System.out.println("拔出了键盘....");
}
//私有方法
private void test() {
System.out.println("测试一下键盘的性能....");
}
}
三、多态
什么是多态?
多态是继承或实现后的一种现象,具体表现为对象多态和行为多态,成员变量没有多态。可以把相同的代码抽取到父类中,使用父类类型作为形参,可以接收一切的子类,扩展性更强,在多态的形式下,右边的代码是解耦的,更便于扩展和维护
多态的条件:
1、继承或者实现
2、子类重写父类中的方法
3、父类对象指向子类引用
向上转型:父类 对象名 = new 子类() 可以用父类对象来接收任意子类对象,实现更加的灵活,但是此对象不能调用子类中特有的方法
向下转型:子类 对象名 = (子类)目标对象
向下转型就是为了解决向上转型的不足而设计的,但前提是目标对象本身就是这个子类创建出来的对象,对象经过向下转型后,就可以使用子类中特有的方法了
注意事项:向下转型编译的时候就算强制转换为兄弟类型也不会报错,只是运行的时候会报错,所以向下转型之前要用instanceof来判断一下数据类型
public class Test {
public static void main(String[] args) {
//向上转型,使用不了子类特有的方法
Animal dog = new Dog();
dog.eat();
System.out.println("--------------------");
//向下转型,可以使用子类特有的方法
Dog dog1 = (Dog) dog;
dog1.lookHome();
//错误的向下转型,编译时没问题,运行时会报错
Cat cat = (Cat) dog;
}
}
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头~~");
}
public void lookHome() {
System.out.println("狗看家~~");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("小猫吃鱼~~");
}
}
四、补充:final关键字
1、使用final关键字修饰的变量不能二次赋值
2、使用final关键字修饰的方法不能被重写
3、使用final关键字修饰的类不能被继承
4、使用final static修饰的变量叫做常量,在定义的时候就要赋值,并且永远也不能被改变,在开发中我们把常用的数据定义成常量,这样我们就可以避免开发时重复的写这个数据,其原理是编译的时候任何出现常量的地方,都会宏替换成常量保存的数据
final class Student {
public final static String schoolName = "清华大学";
public final String getSchoolName() {
return schoolName;
}
}