抽象类
在介绍抽象类之前,我们先来看一段代码:
class Animal{
int age;
String name;
Animal(){} //Animal的构造函数
public void eatFood(){} //每个动物都有吃的食物
public void speaking(){} //每个动物都有它叫的声音
public void sleep(){ //每个动物都会睡觉,大多数都是闭眼睡觉
System.out.println("闭眼");
}
}
class Dog extends Animal{ //实现一个dog类继承Animal类
//实现父类Animal中eat()函数
public void eat(){//既是实现,也是重写
name="旺财";
System.out.println(name+"吃狗粮");
}
//实现父类Animal中speaking()函数
public void speaking(){
name = "旺财"
System.out.println(name+"汪汪的叫");
}
}
class Cat extends Animal{ //实现一个cat类继承Animal类
//实现父类Animal中eat()函数
void eat(){
name = "喵喵";
System.out.println("吃猫粮");
}
//实现父类Animal中speaking()函数
public void speaking(){
name = "喵喵"
System.out.println(name+"喵喵的叫");
}
}
我们发现在上面的Animal类中有两个方法eatFood方法和speaking方法,因为每个动物吃的食物和叫声是不一样的,所以他的函数具体是要由继承它的子类来实现,因此在父类中没有具体的方法体,但是还是会有方法体就是用{}括起来的部分,为了解决特殊情况,Java中使用抽象类来封装没有具体方法体的方法,
抽象类用关键字“abstract”修饰,即" abstract class 类名{ } ",其中抽象类中,我们可以将没有具体方法体的方法也定义成抽象的,如上面的eatFood方法和speaking方法我们可以这样定义:
public abstract void eatFood(); //每个动物都有吃的食物,不确定具体的方法体定义成抽象的方法体
public abstract void speaking(); //每个动物都有它叫的声音,不确定具体的方法体定义成抽象的方法体
由上面的代码我们可以看出,定义成抽象的方法是没有函数体的,就连{ }都省略了,这就是抽象方法的一个特点。虽然叫抽象类,其实与我们的普通的类就是多了一个抽象函数而已,其他普通类该有的方法,抽象类同样的都有,所以:抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类,且抽象类也可继承其他的普通类。
抽象类是不能被创建对象的,因为它可能存在不具体的方法,调用无意义,所以不会让它去创建对象,但是却存在构造方法,原因是抽象类是可以被继承的,只用作父类存在,继承它的子类在创建对象时,作为父类的抽象类要调用构造函数为子类对象中继承来的成员变量进行初始化,所有这就是构造方法的作用。
当然我们说抽象方法是没有具体的方法体的,只能存在于抽象类中,那继承抽象类的子类如何处理这些抽象方法呢?这里提供两种方法:一是子类是普通类,继承抽象类后要重写抽象类中的抽象函数;二是子类也定义为抽象类,这样继承而来的抽象函数就不用具体实现,由下一个普通类继承重写。
既然抽象类是要被继承才能发挥类的作用,因此抽象类不能与以下几个关键字共存:①final,用该关键字修饰的类表示该类不能被继承;②private,被此关键字修饰,子类继承不到该函数或者类;③ static,不能创建对象,调用没意思
接口
前面我们介绍了抽象类,发现普通类中存在抽象函数,因此定义成抽象类,那么如果发现一个抽象类中全都是抽象函数,此时我们可以将该抽象类定义成一个接口,用关键字 " interface "修饰,即:interface 接口名{ 抽象函数和静态常量属性}。
接口是抽象类的另外一种表现形式,本质上是从抽象类演变过来的,其中在接口当中:属性默认 public static final;函数默认 public abstract;与抽象类不同之处在于,抽象类表示的还是类 有继承关系,接口表示的则不是类,那么意味着接口是不能创建对象的,类与接口之间实现关系,而接口是不能继承类的,但是接口可以继承接口且还可以多继承,原因是接口当中的函数没有具体的实现,不会像继承那样产生调用歧义,具体方法由子类去实现。具体表现形式:
interface A{ } //接口用interface修饰
interface B{ }interface C extends B,A{ } //接口之间可以多继承
class D implements A { } //类与接口是实现的关系
接口与抽象类的作用
抽象类适用于一个类中部分方法需要靠子类去实现,但是还存在一些方法是所有子类都有的具体行为;
接口则是对类的功能进行拓展同时也作为传递的中间者,接口的存在向外界提供了统一的接入规范,
我们来看两个实例:
class Demo04{
public static void main(String[] args){
金毛 s=new 金毛();
s.导盲();
拉布拉多 l=new 拉布拉多();
l.缉毒();
黑背 h=new 黑背();
h.缉毒();
h.导盲();
}
}
abstract class Animal{ //定义一个动物的抽象类
public int age; //动物都存在年龄的属性
public int name; //动物都存在名字的属性
public abstract void eat(); //动物都存在吃它相应的食物的方法,是抽象的,具体由子类实现
public abstract void speak(); //动物都存在相应的叫声方法,是抽象的,具体由子类实现
public void sleep(){ //绝大多数动物都是闭眼睡觉的,这是共有方法
System.out.println("闭眼睡觉...");
}
}
class Dog extends Animal{ //定义一个狗的类继承动物类
public void eat(){ //具体实现的抽象方法,所有狗肯定会吃狗粮
System.out.println("狗吃狗粮...");
}
public void speak(){ //所有狗也会汪汪的叫
System.out.println("汪汪汪...");
}
}
interface 缉毒功能{ //狗会缉毒但不是所有狗都会缉毒
public abstract void 缉毒(); //具体怎么缉毒也是具体的狗实现的方法
}
class 拉布拉多 extends Dog implements 缉毒功能{ //定义一个拉布拉多狗的类它有狗的共有属性因此继承了Dog类,它会缉毒也实现了缉毒的功能
public void 缉毒(){ //拉布拉多具体的缉毒方法
System.out.println("拉布拉多在缉毒...");
}
}
interface 导盲功能{ //同样狗会导盲但不是所有狗都会导盲
void 导盲(); //具体怎么导盲也是具体的狗实现的方法
}
class 金毛 extends Dog implements 导盲功能{ //定义一个金毛的类它有狗的共有属性因此继承了Dog类,它会导盲也实现了导盲的功能
public void 导盲(){ //金毛具体的导盲方法
System.out.println("金毛在导盲...");
}
}
class 黑背 extends Dog implements 缉毒功能,导盲功能{ //定义一个黑背的类它有狗的共有属性因此继承了Dog类,它会导盲和缉毒,同时实现了导盲和缉毒的功能
public void 缉毒(){
System.out.println("黑背在缉毒...");
}
public void 导盲(){
System.out.println("黑背在导盲...");
}
}
class Bird extends Animal{ //鸟也是动物
public void eat(){ //鸟吃的是虫子
System.out.println("鸟吃虫子...");
}
public void speak(){ //鸟的叫声
System.out.println("叽叽喳...");
}
}
class Demo07{
public static void main(String[] args){
Mouse mouse=new Mouse(); //创建一个鼠标对象
KeyBoard keyboard=new KeyBoard(); //创建一个键盘对象
Computer com=new Computer(); //创建一个电脑对象
com.getConnect(mouse); //链接USB接口将鼠标对象和键盘队形分别传入,相当于接口上分别插入了键盘和鼠标对象
com.getConnect(keyboard);
}
}
class Computer{ //定义一个电脑的类
//获取 符合USB规范的设备 的连接
//USB device=new Mouse();
//这里USB device只是定义一个USB接口的引用,并没有创建对象,创建对象的是实现接口的子类,这里就是多态的体现
public void getConnect(USB device){ //每个电脑都有一个use的接口,我们需要获得另一个use的插入对象
device.doSomething(); //然后用获得的插入对象去对电脑进行操作
}
}
interface USB{ //这是一个use的接口
public void doSomething(); //接口具体做的事是由具体插入对象实现的
}
class Mouse implements USB{ //定义一个鼠标类实现插入的接口
public void doSomething(){ //鼠标有它相应的操作
System.out.println("鼠标连接,开始使用鼠标...");
}
}
class KeyBoard implements USB{ //定义一个键盘类实现插入的接口
public void doSomething(){ //键盘有它相应的操作
System.out.println("键盘连接,开始使用键盘...");
}
}
class Demo08{
public static void main(String[] args){
Button b1=new Button(); //按钮的对象——登录.........
b1.setAction(new LoginAction()); //将具体的按钮对象传进按钮中
b1.click(); //点击该按钮实现相应的动作
Button b2=new Button();//注册........
//匿名实现子类的匿名对象
b2.setAction(new ButtonAction(){ //这里创建了一个按钮动作接口的对象,显然是无法创建的,也没有他相应的子类,其实这里就已经创建了一个类去实现了接口,只是我们不知道这个类叫啥,然后调用父类的构造函数,创建子类对象,实现接口中没有具体实现的方法
public void doSomething(){
System.out.println("开始注册");
}
}); //注意这是写在括号里面的一段代码,上面的登录一样可以这样写
b2.click();
Button b3=new Button();
b3.click();
}
}
interface ButtonAction{ //按钮动作接口,具体动作由子类实现
public void doSomething();
}
class LoginAction implements ButtonAction{ //登录按钮实现按钮动作接口
public void doSomething(){ //点击登录登录按钮,进入登录界面
System.out.println("开始登录");
}
}
class Button{
private ButtonAction ba;
//将按钮要做的事情传递进来
//ButtonAction ba=new LoginAction();
public void setAction(ButtonAction ba){
this.ba=ba; //将传进来的按钮动作接口引用给当前按钮动作接口引用
}
//当点击时需要做事情
public void click(){
if(ba==null){ //如果没有按钮传递进来,相当于什么都没做
System.out.println("啥也没干");
return;
}
ba.doSomething(); //有按钮传递进来,就做该按钮相应的事情
}
}