内容来自《第一行代码》,很简单易懂
2.抽象类应用—模板设计模式
在本程序中定义抽象类A 的时候根本不知道具体要实现的子类是什么,但是强制子类来覆写print(),当调用fun()方法时,执行的一定是被子类所覆写的抽象方法,具体子类怎么实现由子类来决定。
abstract class A { //定义一个抽象类
public void fun(){ //此为普通方法
this.print(); //在普通方法中直接调用抽象方法
}
public abstract void print(); //此为抽象方法
}
class X extends A{ //抽象类必须有子类
public void print(){
System.out.println("更多课程请访问:www.yootk.com");
}
}
public class TestDemo{
public static void main(String args[]){
A a = new X(); //通过子类实例化抽象类对象
a.fun(); //抽象类中的普通方法
}
}
再对上面的例子进行扩写。
abstract class Action{//定义一个抽象的行为类,行为不是具体的
//定义常量必须保证两个内容相加的结果不是其他行为,例如:EAT + SLEEP 的结果是6,不会和其他值冲突
public static final int EAT = 1; //吃
public static final int SLEEP = 5; //睡
public static fianl int WORK = 7;//工作
//控制操作的行为,所有的行为都通过类中的常量描述,可以使用 EAT,SLEEP,WORK,或者叠加使用,例如:边吃边工作,使用EAT+Work来描述 @param flag 操作的行为标记//
public void command(int flag){
switch(flag){ //switch只支持数值判断,而if支持条件判断
case EAT: //当前为吃的操作
this.eat(); //调用子类中具体的吃方法
break;
case SLEEP:
this.sleep();
break;
case WORK:
this.work();
break;
case SLEEP + WORK; // 组合方法
this.sleep();
this.work();
break;
}
}
public static void eat(); //定义子类的操作标准
public static void sleep();
public static void work();
}
class Robot extends Action{//定义机器人的行为子类
public void eat(){//覆写行为操作
System.out.println("机器补充能量");
}
public void sleep(){//此方法不需要但必须覆写,所以方法为空
}
public void work(){
System.out.println("机器要工作");
}
}
class Human extends Action{
public void eat(){
System.out.println("人类要吃东西");
}
public void sleep(){
System.out.println("人类要睡觉");
}
public void work(){
System.out.println("人类要工作");
}
}
calss Pig extends Action{
public void eat(){
System.out.println("猪要吃东西");
}
public void sleep(){
System.out.println("猪要睡觉");
}
public void work(){
}
}
public class TestDemo{
public static void main(String args[]){
fun(new Robot());//传递机器人行为子类
fun(new Human());//传递人类行为子类
fun(new Pig());//传递猪的行为子类
}
//执行具体的操作行为,假设本处只执行EAT,SLEEP,WORK,3个行为
//@param act 具体的行为对象
public static void fun(Action act){
act.command(Action.EAT);
act.command(Action.SLEEP);
act.command(Action.WORK);
}
}
接口:抽象类可以由子类实现对父类方法的覆写,但是抽象类有一个缺陷,就是只能单继承,为了解决单继承这个缺点,定义了接口这个概念。同时在开发过程中为了将具体代码的实现细节对调用处进行隐藏,也可以用接口来进行方法视图的描述。
interface A {//定义接口
public static final String MSG = "YOOTK";//全局变量
public static void print();//抽象方法
}
省略写法:
interface A{
String MSG = "HELLO";
void print();
}
(1)接口是一种特殊的类,由抽象方法和全局变量组成。上述程序定义了一个接口A,一个抽象方法(print())和一个全局变量(MSG)。
(2)由于接口中含有抽象方法,所以不能直接使用关键字new进行实例化操作,因此接口具有以下使用原则:
1)接口必须有子类,但是此时一个子类可以使用implements关键字实现多个接口,避免单继承局限。
2)接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法。
3)接口的对象可以利用子类对象的向上转型进行实例化操作。
4)接口就是用来被继承和实现的,所以修饰符一般是public.
一个简单的继承的例子:
interface A{ //定义接口
public static final Sring MSG = "YOOTK";//全局常量
public abstract void print(); //抽象方法
}
interface B{
public abtract void get();
}
class X implements A,B{
public void print(){
System.out.println("A接口的抽象方法!");
}
public void get(){
System.out.println("B接口的抽象方法!");
}
}
public class TestDemo{
public static void main(String args[]){
X x = new X();
A a = x;
B b = x;
a.print();
b.get();
System.out.println(A.MSG);
}
}
程序执行结果:
A接口的抽象方法!
B接口的抽象方法!
YOOTK
(3)一个程序既要实现继承抽象类又要实现接口,那么应该采用先继承后实现接口的顺序完成。
(4)接口里面可以定义普通内部类,抽象内部类,内部接口。
学习过程中遇到的补充知识1:java中,instanceof运算符的前一个操作符是一个引用变量,后一个操作数通常是一个类(可以是接口),用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是返回true,否则返回false。
补充知识2:Spring开发框架的设计核心理念《第一行代码》的书中p249已经为读者分析了new关键字在直接实例化接口上所带来的问题。实际上这种耦合问题在很多项目开发中都会出现,很多开发者在面对这种耦合问题时,往往会采用大量结构设计进行回避,可是这样的代码维护成本太高了。所以在java开发中有一个spring框架,其核心就是解决这种代码耦合问题。