一、抽象类和抽象方法
- 区分抽象方法和普通方法
1)当一个方法被abstract修饰时,该方法成为抽象方法
2)抽象类所在的类必须定义为抽象类
3)抽象方法不会有具体的实现,而是在抽象类的子类中通过方法重写进行实现
4)定义抽象方法语法:
[访问修饰符] abstract <返回类型> <方法名>([参数类表])
5)区别:
抽象方法需要用abstract修饰,普通方法不需要;抽象方法没有方法体 - 区分普通类和抽象类
1)当一个类被abstract修饰时被称为抽象类
2)定义抽象类:abstract class <类名>{ }
3)区别:
抽象类需要用abstract修饰,普通类不需要;
普通类可以实例化,抽象类不能被实例化(但可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例) - 抽象类结构
public abstract class 类名{
修饰符 abstract 返回值类型 方法名();
修饰符 返回值类型 方法名(){
方法体
}
} - 抽象类和抽象方法的使用:
抽象方法只能定义在抽象类中,抽象类中可以包含抽象方法和普通方法及普通类包含的一切成员;
如果子类没有实现父类的所有抽象方法,则子类必须定义为抽象类;
没有抽象构造方法,也没有抽象静态方法;
抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
package com.abstractInterface;
public abstract class Base {
//抽象类中可以没有抽象方法,但包含了抽象方法的类就必须被定义为抽象类
public abstract void method1();
public abstract void method2();
public void method3(){}
//没有抽象的构造方法
//public abstract Base(){}
//没有抽象的静态方法
//static abstract void method4();
public Base(){
System.out.println("父类的无参构造方法");
}
static void method4(){
System.out.print("静态方法表示类所特有的功能,这种功能的实现不依赖于类的具体实例,也不依赖于它的子类。因此,当前类必须为静态方法提供实现");
}
}
package com.abstractInterface;
//如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类
public abstract class Sub1 extends Base {
public void method1() {
System.out.println("重写父类的method1");
}
}
package com.abstractInterface;
//否则就必须实现父类的所有抽象方法
public class Sub2 extends Base {
public Sub2(){
System.out.println("子类的无参构造方法");
}
@Override
public void method1() {
System.out.println("重写父类的抽象方法method1");
}
@Override
public void method2() {
System.out.println("重写父类的抽象方法method2");
}
}
public class Test {
public static void main(String[] args) {
//抽象类不允许实例化
//Base base=new Base();
//抽象类中可以有非抽象的构造方法,创建子类的实例时可能调用
//抽象类不能被实例化,但可以创建一个引用变量,其类型是一个抽象类,指向非抽象的子类实例
Base sub=new Sub2();
sub.method1();
sub.method4();
}
}
二、抽象类的优势
如图,设计一个抽象类,它有两个普通方法:飞行(弹射飞)和叫(嗷嗷),还有一个抽象方法攻击。分裂鸟和火箭鸟为这个抽象类的子类。
分裂鸟和火箭鸟都继承了父类的飞行和叫的方法,并重写了父类的攻击方法(两种鸟的攻击方式不同)。
总结:抽象类中已经实现的方法可以被其子类使用,使得代码可以被复用;同时提供了抽象方法,保证了子类具有自身的独特性
三、抽象类的局限性
"愤怒的小鸟"的游戏中,分裂鸟和火箭鸟的叫声都是“嗷嗷”,但是红色鸟和炸弹鸟飞出来后是“渣渣”叫,胖子鸟飞出来后干脆不叫,所以类图做如下修改:
此时,使用抽象类就会出现以下问题:1.叫的方法不在通用;2.子类继承鸟抽象类后,写出来的叫的方法可能会出现代码重复的情况,如红色鸟和炸弹鸟都是“喳喳“叫。
问题1,可以将叫方法给抽象方法,由其子类去具体实现;但这样会造成代码冗余的问题,如这里的分裂鸟和火箭鸟的叫方法也会一样,也就是问题2会更加突出。
为解决上述问题,最理想的方法是使用接口。
四、接口
生活中,常见的如USB接口有以下特点:USB接口本身没有实现任何功能;USB接口规定了数据传输的要求;USB接口可以被多种USB设备实现
- 接口概念
java中接口的作用和生活中的接口类似,他提供一种约定,是的实现接口的类早形式上保持一致。
如果抽象类中所有的方法都是抽象方法,就可以使用java提供的接口来表示,所以,从这个角度来讲,接口是一种特殊的”抽象类“,但两者语法和设计理念都不同 - 定义和实现一个简单的接口
接口是一个不能实例化的类型,需要注意:
1)接口:接口中不能有构造方法;
接口使用interface修饰符,访问修饰符只能是public,且可选;
接口成员可以是全局变量和公共的抽象方法(默认用 public 修饰);
接口中的变量都是静态常量(public static final),并必须指定初始值;
2)实现接口:实现接口用implements关键字;
实现接口的类必须实现接口中定义的所有抽象方法,否则必须定义为抽象类;
接口的实现类中允许包含普通方法;
实现类可以实现多各接口;package com.interfaceDemo; /** * USB接口。 * @author yu */ public interface UsbInterface { /** * USB接口提供服务。 */ void service(); }
package com.interfaceDemo; /** * U盘。 * @author yu */ public class UDisk implements UsbInterface { public void service() { System.out.println("连接USB口,开始传输数据。"); } }
package com.interfaceDemo; /** * USB风扇。 * @author yu */ public class UsbFan implements UsbInterface { public void service() { System.out.println("连接USB口,获得电流,风扇开始转动。"); } }
package com.interfaceDemo; /** * 测试类。 * @param args */ public class Test { public static void main(String[] args) { //1、U盘 UsbInterface uDisk = new UDisk(); uDisk.service(); //2、USB风扇 UsbInterface usbFan= new UsbFan(); usbFan.service(); } }
- 更复杂的接口
1)接口本身也可以继承接口:
[修饰符] interface 接口名 extends 父接口1,父接口2,....{
常量定义;
方法定义;
}
2)一个普通类只能继承一个父类,但能同时实现多个接口,也可以同时继承抽象类和实现接口:
class 类名 extends 父类名 implements 接口1,接口2,....{
类的成员;
}
package com.interfaceDemo; /** * 鸟叫的接口 * @author yu */ public interface ShoutAbility { /** * USB接口提供服务。 */ public void shout(); //鸟叫的抽象方法 } /****************************************/ package com.interfaceDemo; /** * 嗷嗷叫 * @author yu */ public class AoShout implements ShoutAbility { public void shout() { System.out.println("嗷嗷。。。。。"); } } /******************************************/ package com.interfaceDemo; /** * USB风扇。 * @author yu */ public class ZhaShout implements ShoutAbility { public void shout() { System.out.println("喳喳。。。。。"); } } /******************************************/ package com.interfaceDemo; /* * 无叫声 */ public class NoShout implements ShoutAbility{ public void shout(){ //无叫声 } } /******************************************/ package com.interfaceDemo; /* * 鸟类 */ public abstract class Bird { ShoutAbility shoutAbility; //鸟叫的方式 String birdName; //鸟的名字 //构造方法,用来初始化鸟叫的行为 //构造方法 // public Bird(String birdName){ // this.birdName = birdName; // } public Bird(ShoutAbility shoutAbility,String birdName){ this.shoutAbility = shoutAbility; this.birdName = birdName; } //叫 public void Shout(){ shoutAbility.shout(); } //飞行 public void fly(){ System.out.println(this.birdName+"弹射飞!"); } //攻击 public abstract void attrack(); } /********************************/ package com.interfaceDemo; /* * 分裂鸟 */ public class SplitBird extends Bird{ //构造方法 public SplitBird(ShoutAbility shoutAbility,String birdName){ super(shoutAbility,birdName); } //重写分裂方法 public void attrack(){ System.out.println("分裂攻击!"); } } /************************************/ package com.interfaceDemo; /* * 火箭鸟 */ public class RocketBird extends Bird{ public RocketBird(ShoutAbility shoutAbility,String birdName){ super(shoutAbility,birdName); } public void attrack(){ System.out.println("加速冲撞!"); } } /********************************************/ package com.interfaceDemo; /* * 红色鸟 */ public class RedBird extends Bird{ //构造方法 public RedBird(ShoutAbility shoutAbility,String birdName){ super(shoutAbility,birdName); } //重写分裂方法 public void attrack(){ System.out.println("普通攻击!"); } } /******************************************/ package com.interfaceDemo; /* * 炸弹鸟 */ public class BombBird extends Bird{ //构造方法 public BombBird(ShoutAbility shoutAbility,String birdName){ super(shoutAbility,birdName); } //重写分裂方法 public void attrack(){ System.out.println("爆炸攻击!"); } } /********************************************/ package com.interfaceDemo; /* * 胖子鸟 */ public class FatBird extends Bird{ //构造方法 public FatBird(ShoutAbility shoutAbility,String birdNme){ super(shoutAbility,birdNme); } //重写分裂方法 public void attrack(){ System.out.println("扔蛋攻击!"); } } /********************************************/ package com.interfaceDemo; import java.text.Bidi; /** * 测试类。 * @param args */ public class Test { public static void main(String[] args) { ShoutAbility shoutAbility = new AoShout(); //嗷嗷叫 ShoutAbility shoutAbility1 = new ZhaShout(); //喳喳叫 ShoutAbility shoutAbility2 = new NoShout(); //无叫声 Bird bird = new SplitBird(shoutAbility,"分裂鸟"); bird.fly(); bird.Shout(); bird.attrack(); Bird bird1 = new RocketBird(shoutAbility,"火箭鸟"); bird1.fly(); bird1.Shout(); bird1.attrack(); Bird bird2 = new RedBird(shoutAbility1,"红鸟"); bird2.fly(); bird2.Shout(); bird2.attrack(); Bird bird3 = new BombBird(shoutAbility1,"爆炸鸟"); bird3.fly(); bird3.Shout(); bird3.attrack(); Bird bird4 = new FatBird(shoutAbility2,"胖子鸟"); bird4.fly(); bird4.Shout(); bird4.attrack(); } }
- 面向对象的设计原则
1)摘取代码中变化的行为,形成接口
2)多用组合,少用继承
3)针对接口编程,不依赖于具体实现:具体代码实现中,体现在方法参数尽量使用接口,方法的返回值尽量使用接口,属性类型尽量使用接口等
4)针对扩展开放,针对改变关闭:项目中需求发生变化,应添加一个新的接口或类,而不要去修改源码
总的来说,接口和抽象类是实现堕胎的2种重要方式,是面向对象设计的基础