面向对象(六)

一、抽象类
1.抽象类概述
回想前面我们的猫狗案例,提取出了一个
动物类。并且我们在前面也创建过了动物
对象,其实这是不对的。为什么呢?因为,
我说动物,你知道我说的是什么动物吗?
只有看到了具体的动物,你才知道,这是
什么动物。所以说,动物本身并不是一个
具体的事物,而是一个抽象的事物。只有
真正的猫,狗才是具体的动物。同理,我们
也可以推想,不同的动物吃的东西应该是
不一样的,所以,我们不应该在动物类中
给出具体的体现,而是应该给出一个声明
即可。在java中,一个没有方法体的方法
应该定义为抽象方法,而类中如果有抽象
方法,该类必须定义为抽象类。
2.抽象类的特点
抽象类的概述:
动物不应该定义为具体的东西,而动物中
的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的
功能,而一个类中如果有抽象的功能,
该类也必须是抽象类。
抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类,必须定义为抽象类。
C:抽象类不能实例化。
因为他不是具体的。
抽象类有构造方法,但是不能实例化,构造方法的作用是什么呢?
用于子类访问父类数据的初始化。
D:抽象类的子类
a:如果不想重写抽象方法,该子类必须是一个抽象类
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是可以靠具体的子类实现的,是多态的方式。
(就是通过重写方法,然后向下转型来调用子类中的具体的实现的方法)
Animal a = new Cat();
多态用的最多的地方就是在抽象类中。

abstract class Animal{
    //抽象方法
    //public abstract void eat(){}//空方法体,这个会报错。抽象方法不能有主体
    public abstract void eat();//没有方法体

    public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal{

}

//子类不是抽象类,重写抽象方法
 class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }
}

class AbstractDemo{
    public static void main(String[] args){
        //错误: Animal是抽象的; 无法实例化
        //Animal a = new Animal();

        //通过多态的方式,实例化抽象类
        Animal a = new Cat();
        a.eat();
    }
}

3.抽象类的成员特点
抽象类的成员特点:
成员变量:既可以是变量也可以是常量。
构造方法:有,用于子类访问父类数据的初始化(不可以实例化)
成员方法:可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情
B:非抽象方法 子类继承的事情,提高代码的复用性。

abstract class Animal{
    public int num = 10;
    public final int num2 = 20;

    public Animal(){}

    public Animal(String name,int age){}

    public abstract void show();

    public void method(){
        System.out.println("method");
    }
}

class Dog extends Animal{
    public void show(){
        System.out.println("show dog");
    }
}

class AbstractDemo{
    public static void main(String[] args){
        //创建对象
        Animal a = new Dog();
        a.num = 100;
        System.out.println(a.num);
        //错误: 无法为最终变量num2分配值
        //a.num2 = 200;
        System.out.println(a.num2);
        System.out.println("----------");
        //错误: Dog不是抽象的, 并且未覆盖Animal中的抽象方法show()
        //a.show();
        a.show();
        a.method();
    }
}

4.抽象类的猫狗案例

/*
    猫狗案例
        具体事务:猫、狗
        共性:姓名,年龄,吃饭

    分析:从具体到抽象
        猫:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭(鱼)
        狗:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭(肉)
        因为有共性的内容,所以就提取了一个父类。动物。
        但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的。
        而方法是抽象的,类就必须定义为抽象类。
    实现:从抽象到具体
        动物类:
            成员变量:姓名,年龄
            构造方法:无参,带参
            成员方法:吃饭
        狗类:
            继承自动物类
            重写吃饭();
        猫类:
            继承自动物类
            重写吃饭();


*/

//定义抽象的动物类
abstract class Animal{
    //姓名
    private String name;
    //年龄
    private int age;

    public Animal(){}

    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }

    public int getAge(){
        return age;
    }

    public void setAge(int age){
        this.age = age;
    }

    public abstract void eat();
}

//定义具体的狗类
class Dog extends Animal{
    public Dog(){}

    public Dog(String name,int age){
        super(name,age);
    }

    public void eat(){
        System.out.println("狗吃肉");
    }
}

//定义具体的猫类
class Cat extends Animal{
    public Cat(){}

    public Cat(String name,int age){
        super(name,age);
    }

    public void eat(){
        System.out.println("猫吃鱼");
    }
}

//测试类
class AbstractDemo{
    public static void main(String[] args){
        //测试狗类
        //方式1
        Dog d = new Dog();
        d.setName("旺财");
        d.setAge(6);
        System.out.println(d.getName()+"---------"+d.getAge());
        d.eat();

        Dog d2 = new Dog("旺财",5);
        System.out.println(d2.getName()+"---------"+d2.getAge());
        d2.eat();

        //方式2
        Animal a = new Dog();
        a.setName("旺财");
        a.setAge(5);
        System.out.println(a.getName()+"-----"+a.getAge());
        a.eat();

        Animal a2 = new Dog("旺财",5);
        System.out.println(a2.getName()+"-----"+a2.getAge());
        a2.eat();

    }
}

5.抽象类中的小问题
一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义
A:可以,意义是可以不让外界创建对象。

抽象类不能和那些关键字共存
    private 冲突  private修饰的不能被继承,而abstract要求必须重写
    final   冲突  final修饰的不能被修改,而abstract要求必须重写
    static  无意义 abstract修饰的方法没有方法体,而用static修饰的方法还可以用类名
                    直接调用的,访问一个没有方法体的方法是毫无意义的。

二、接口
1.接口概述
接口概述:
继续回到我们的猫狗案例,我们想象狗
一般就是看门的,猫一般就是作为宠物,
对不。但是,现在有很多的驯养员或者
驯兽师,可以训练出,猫钻火圈,狗跳
高,狗做计算等。而这些额外的动作,
并不是所有猫或者狗一开始就具备的,这
应该属于经过特殊的培训训练出来的。对不,
所以,这些额外的动作定义到动物类中就
不合适,也不适合直接定义到猫或者狗中,
因为只有部分猫狗具备这些功能。所以,
为了体现事物功能的扩展性,java中就提供了
接口来定义这些额外功能,并不给出具体实现
,将来那些猫狗需要被培训,只需要这部分
猫狗把这些功能实现即可。
*/
接口只是事物功能的扩展,而并不是事物本身具备的功能,所以不能定义到事物的类中
作为方法。只能定义为接口。

2.接口的特点

/*
    接口的特点:
        A:接口用关键字interface表示  
            interface  接口名{}
        B:类实现接口用implements表示
            class 类名 implements 接口名{}
        C:接口不能实例化
            那么,接口如何实例化呢?
            按照多态的方式来实例化。
        D:接口的子类
            a:可以是抽象类,但是意义不大。
            b:可以是具体类,要重写接口中的所有抽象方法。(推荐方法)


        由此可见:
            A:具体类多态(几乎没有)
            B:抽象类多态(常用)
            C:接口类多态(最常用)

*/

//定义动物培训接口
/*
    由此可见,接口并不是实际意义上的一个类
    它仅仅是功能的扩展
*/
//定义一个接口
interface AnimalTrain{
    public abstract void jump();

}

//抽象类实现接口,这种方法不常见。
abstract class Dog implements AnimalTrain{

}

//具体类重写接口中的所有抽象方法,这种方法很常见。
class Cat implements AnimalTrain{
    public void jump(){
        System.out.println("猫可以跳高了");
    }
}

class InterfaceDemo{
    public static void main(String[] args){
        //AnimalTrain是抽象的,无法实例化
        //AnimalTrain at = new AnimalTrain();
        AnimalTrain at = new Cat();
        at.jump();
    }

3.接口的成员特点
成员变量:只能是常量,并且是静态的。
默认修饰符:public static final
完整格式:public static final int num = 20;
建议:自己手动给出
构造方法:接口没有构造方法
成员方法:只能是抽象方法
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:object
类object是类层次结构的根类,每个类都使用object作为超类

interface Inter{
    public int num = 10;
    public final int num2 = 20;

    //public Inter(){}//错误: 需要<标识符>

    //public void show(){}//错误: 接口方法不能带有主体
    //public abstract void show();

    public void show();//默认抽象的abstract
}

//接口名+ Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter{
    public InterImpl(){
        super();//既然父类接口没有构造方法,那么这里如何调用呢?
    }
}
*/

//因为所有的类都默认继承自object
class InterImpl extends Object implements Inter{
    public InterImpl(){
        super();
    }

    public void show(){}
}

//测试类
class InterfaceDemo{
    public static void main(String[] args){

        //创建对象
        Inter i = new InterImpl();
        System.out.println(i.num);//结果是10
        System.out.println(i.num2);//结果是20

        //i.num = 100;
        //i.num2 = 200;
        //System.out.println(i.num);//错误: 无法为最终变量num分配值
        //System.out.println(i.num2);//错误: 无法为最终变量num2分配值
        System.out.println(Inter.num);
        System.out.println(Inter.num2);
        System.out.println("--------------");   
    }
}

4.类与类,类与接口,接口与接口
类与类:只能单继承,可以多层继承
类与接口:
实现关系:可以是单实现,也可以是多实现
并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系:可以单继承,也可以多继承

interface Father{
    public abstract void show();

}

interface Mother{
    public abstract void show2();
}

interface Sister extends Father,Mother{

}

//class Son extends Object implements Father,Mother

//错误: Son不是抽象的, 并且未覆盖Father中的抽象方法show()
class Son extends Object implements Father,Mother{
    public void show(){
        System.out.println("show son");
    }

    public void show2(){
        System.out.println("show mother");
    }
}

class InterfaceDemo{
    public static void main(String[] args){
        //创建对象
        Father f = new Son();
        f.show();
        //f.show2();//报错

        Mother m = new Son();
        //m.show();//报错
        m.show2();
    }
}

5.抽象类和接口的区别
A:成员区别
抽象类:
成员变量:可以是变量,也可以是常量
构造方法:有
成员方法:可以是抽象的,也可以是非抽象的
接口:
成员变量:只可以是常量
成员方法:只可以是抽象的。
B:
类与类
继承 单继承
类与接口
实现 单实现,多实现
接口与接口
继承 单继承,多继承
C:设计理念区别**(这个很重要)
抽象类 被继承体现的是“is a”的关系 抽象类中定义的是该继承体系的共性功能。
接口 被继承体现的是“like a”的关系 接口中定义的是该继承体系的扩展功能。

6.加入调高的猫狗案例分析

/*
    猫狗案例   加入调高的额外功能

    分析:从具体到抽象
        猫:
            姓名,年龄
            吃饭,睡觉
        狗:
            姓名,年龄
            吃饭,睡觉

        由于有共性功能,所以,我们抽取出一个父类;
        动物:
            姓名,年龄
            吃饭();
            睡觉(){}
        猫:继承自动物
        狗:继承自动物

        跳高的额外功能是一个新的扩展功能,所以我们要
        定义一个接口
        接口:
            跳高
        部分猫:实现跳高
        部分狗:实现跳高

    实现:从抽象到具体

    使用:具体类  
*/

//定义跳高功能
interface Jumpping{
    public abstract void jump();
}

//定义动物类(抽象类)
abstract class Animal{
    private String name;
    private int age;

    public Animal(){}

    public Animal(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setAge(int age){
        this.age = age;
    }

    public int getAge(){
        return age;
    }

    //定义睡觉功能
    public void sleep(){
        System.out.println("睡觉喽!");
    }
    //定义吃饭功能,抽象方法
    public abstract void eat();
}

//定义猫类,继承自动物类
class Cat extends Animal{
    public Cat(){}

    public Cat(String name,int age){
        super(name,age);
    }

    public void eat(){
        System.out.println("猫吃鱼");
    }
}

//定义狗类,继承自动物类
class Dog extends Animal{
    public Dog(){}

    public Dog(String name,int age){
        super(name,age);
    }

    public void eat(){
        System.out.println("狗吃肉");
    }
}

//定义跳高猫类,继承自猫类,实现跳高接口
class JumpCat extends Cat implements Jumpping{
    public JumpCat(){}

    public JumpCat(String name,int age){
        super(name,age);
    }

    public void jump(){
        System.out.println("跳高猫");
    }
}


//定义跳高狗类,继承自狗类,实现跳高接口
class JumpDog extends Dog implements Jumpping{
    public JumpDog(){}

    public JumpDog(String name,int age){
        super(name,age);
    }

    public void jump(){
        System.out.println("跳高狗");
    }
}

class CatAndDog{
    public static void main(String[] args){

        JumpCat jc = new JumpCat();
        jc.setName("哆啦A梦");
        jc.setAge(3);
        System.out.println(jc.getName()+"-------"+jc.getAge());
        jc.eat();
        jc.sleep();
        jc.jump();

        System.out.println("-----------------------------");

        JumpCat jc2 = new JumpCat("加菲猫",2);
        System.out.println(jc2.getName()+"-------"+jc2.getAge());
        jc2.eat();
        jc2.sleep();
        jc2.jump();
    }
}

/*
    记住:在实现某一个接口的时候,只是其中的某一部分要实现这个功能,
    所以,我们需要单独去写一个实现这个功能的类(继承自原类+实现接口)
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值