抽象类

1.抽象类

1.1抽象类概述

在Java中,一个没有方法体的方法定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

1.2抽象类的特点

  • 抽象类和抽象方法必须使用abstract关键字修饰

    public abstract class 类名{}

    public abstract void eat();

  • 抽象类中不一定有抽象方法,有抽象方法的一定是抽象类

  • 抽象类不能实例化

    抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态

  • 抽象类的子类:

    要么重写抽象类中的所有抽象方法,要么是抽象类。

package com.szy001;
/*
抽象类
 */
public abstract class Animal {
    //抽象方法
    public abstract void eat();
    public void sleep(){
        System.out.println("睡觉");
    }
}
package com.szy001;

public class Cat extends Animal{//抽象类的子类,它继承了抽象类
    @Override
    public void eat() {//重写了抽象方法
        System.out.println("猫吃鱼");
    }
}
package com.szy001;

public abstract class Dog extends Animal{//抽象类的子类要么重写抽象类中的所有方法,要么它本身也是个抽象类
    //public abstract void eat();
}
package com.szy001;

public class AnimalDemo {
    public static void main(String[] args) {
//    Animal a=new Animal();//抽象类不能直接实例化
        Animal a=new Cat();//抽象类可以通过子类对象实例化
        a.eat();
        a.sleep();
    }
}

1.3抽象类的成员特点

  • 成员变量

    可以是变量,也可以是常量

  • 构造方法

    有构造方法,但是不能直接实例化(可以通过多态)

    那么,构造方法的作用是什么呢?用于子类访问父类数据的初始化

  • 成员方法

    可以有抽象方法:限定子类必须完成某些动作(子类要重写抽象方法)

    也可以有非抽象方法:提高代码复用性

    package com.szy002;
    /*
    抽象类
     */
    public abstract  class Animal2 {
        private int age=20;
        private final String city="北京";
        public Animal2(){
            //无参构造方法
        }
        public Animal2(int age){//带参构造方法
            this.age=age;
        }
        public void show(){
            age=40;
            System.out.println(age);
    //        city="上海";常量不可赋值
            System.out.println(city);
        }
        public abstract void eat();//抽象方法
    
    }
    
    package com.szy002;
    
    public class Cat2 extends Animal2{
        @Override
        public void eat() {//重写父类的抽象方法
            System.out.println("猫吃鱼");
        }
    }
    
    package com.szy002;
    /*
    测试类
     */
    public  class AnimalDemo2 {
        public static void main(String[] args) {
            Animal2 a=new Cat2();
            a.eat();
            a.show();
        }
    }
    

案例:猫和狗(抽象类)

需求:请采用抽象类的思想实现猫和狗的案例,并在测试类中进行测试

package com.szy003;

public abstract class Animal3 {
    private String name;
    private int age;

    public Animal3() {
    }

    public Animal3(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();
}
package com.szy003;

public class Cat3 extends Animal3{
    public Cat3() {//无参构造方法
    }

    public Cat3(String name, int age) {//带参构造方法
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
package com.szy003;

public class Dog3 extends Animal3{
    public Dog3() {//无参构造方法
    }

    public Dog3(String name, int age) {//带参构造方法
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
package com.szy003;
/*
测试类
 */
public class AnimalDemo3 {
    public static void main(String[] args) {
        Animal3 a=new Cat3();//采用无参构造方法
        a.setName("加菲");
        a.setAge(3);
        System.out.println(a.getName()+a.getAge());

        a=new Cat3("小花",4);//采用带参构造方法
        System.out.println(a.getName()+a.getAge());

        a=new Dog3();
        a.setName("小白");
        a.setAge(7);
        System.out.println(a.getName()+a.getAge());

        a=new Dog3("二黄",9);
        System.out.println(a.getName()+a.getAge());
    }
}

2.接口

2.1接口概述

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用

Java中的接口更多的体现在对行为的抽象

2.2接口的特点

  • 接口用关键字interface修饰

    public interface 接口名{}

  • 类实现接口用implements表示

    public class 类名 implements 接口名{}

  • 接口不能实例化

    接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态。

    多态的形式:具体类多态,抽象类多态,接口类多态。

    多态的前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现)类对象

  • 接口的实现类:

    要么重写接口中的所有抽象方法,要么是抽象类。

package com.szy004;
/*
定义了一个接口
 */
public interface Jumpping {
    public abstract void jump();//定义一个抽象方法
}
package com.szy004;

public class Cat4 implements Jumpping{//类实现接口
    @Override
    public void jump() {
        System.out.println("猫可以跳高了");
    }
}
package com.szy004;

public abstract class Dog4 implements Jumpping{
    //抽象类在实现接口时可以不重写接口的抽象方法,但是它具体的子类将来继承它的时候还是要重写接口的抽象方法
}
package com.szy004;
/*
测试类
 */
public class JumppingDemo {
    public static void main(String[] args) {
//        Jumpping j=new Jumpping();不可以实例化
        Jumpping j=new Cat4();
        j.jump();
    }
}

2.3接口的成员特点

  • 成员变量

    只能是常量

    默认修饰符:public static final

  • 构造方法

    接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在

    一个类如果没有父类,默认继承自Object类

  • 成员方法

    只能是抽象方法

    默认修饰符:public abstract

    关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解

package com.szy005;

public interface Inter {
    public int num=10;
    public final int num2=20;
    public static final int num3=30;//接口中默认是public static final这种类型
//    int num3=30;与上面的等价

//    public Inter(){}报错,接口里不能有构造方法的
//    public void show();接口里面不能有非抽象方法的
    public abstract void method();
    void show();//接口里的方法默认带了public abstract
}
package com.szy005;
/*
接口实现类
 */
//public class InterImpl implements Inter{
public class InterImpl extends Object implements  Inter{//等价与上面的
   public InterImpl(){
        super();
    }

    @Override
    public void method() {//重写接口的抽象方法method()
        System.out.println("method");

    }

    @Override
    public void show() {//重写接口的抽象方法show()
        System.out.println("show");
    }
}
package com.szy005;
/*
测试类
 */
public class InterfaceDemo {
    public static void main(String[] args) {
        Inter i= new InterImpl();
//        i.num=20;报错,因为接口中的变量默认被final修饰
        System.out.println(i.num);
//        i.num2=40;报错,因为num2被final修饰了
        System.out.println(i.num2);
        System.out.println(Inter.num);//通过接口名直接访问num,说明num也是被静态修饰的

    }
}

案例:猫和狗(接口)

需求:对猫和狗进行训练,他们就可以跳高了,这里加入了跳高功能,请采用抽象类和接口来实现猫狗案例,并在测试类中进行测试。

package com.szy006;
/*
接口
 */
public interface Jumpping6 {
    public abstract void jump();
}
package com.szy006;

public abstract class Animal6 {
    private String name;
    private int age;

    public Animal6() {
    }

    public Animal6(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();
}
package com.szy006;

public class Cat6 extends Animal6 implements Jumpping6{
    public Cat6() {
    }

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

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

    @Override
    public void jump() {
        System.out.println("猫可以跳高了");
    }
}
package com.szy006;

public class Dog6 extends Animal6 implements Jumpping6{
    public Dog6() {
    }

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

    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    @Override
    public void jump() {
        System.out.println("狗可以跳高了");
    }
}
package com.szy006;
/*
测试类
 */
public class AnimalDemo6 {
    public static void main(String[] args) {
        //创建对象,调用方法
        Jumpping6 j=new Cat6();
        j.jump();
        System.out.println("-----------");

        Animal6 a=new Cat6();
        a.setName("加菲");
        a.setAge(8);
        System.out.println(a.getName()+":"+a.getAge());
        a.eat();
        ((Cat6)a).jump();//a为Animal6类型的,不能直接调用jump方法
        System.out.println("----------");

        a=new Cat6("布偶",3);
        System.out.println(a.getName()+":"+a.getAge());
        a.eat();
        ((Cat6)a).jump();//a为Animal6类型的,不能直接调用jump方法
        System.out.println("----------");

        Cat6 c=new Cat6();
        c.setName("蓝宝石");
        c.setAge(4);
        System.out.println(c.getName()+":"+c.getAge());
        c.eat();
        c.jump();
        System.out.println("************");

        Animal6 b=new Dog6();
        b.setName("金毛");
        b.setAge(8);
        System.out.println(b.getName()+":"+b.getAge());
        b.eat();
        ((Dog6)b).jump();
        System.out.println("-------------");

        b=new Dog6("阿布",6);
        System.out.println(b.getName()+":"+b.getAge());
        b.eat();
        ((Dog6)b).jump();
        System.out.println("-------------");

        Dog6 d=new Dog6();
        d.setName("哈士奇");
        d.setAge(12);
        System.out.println(d.getName()+":"+d.getAge());
        d.eat();
        d.jump();
        System.out.println("-----------");

    }
}

2.4类和接口的关系

  • 类和类的关系:继承关系,只能单继承,但是可以多层继承。
  • 类和接口的关系:实现关系,可以单实现,也可以多实现,还可以继承一个类的同时实现多个接口。
  • 接口和接口的关系:继承关系,可以单继承,也可以多继承。
package com.szy007;
/*
接口1
 */
public interface Inter1 {
}
package com.szy007;
/*
接口2
 */
public interface Inter2 {
}
package com.szy007;
/*
接口3
 */
public interface Inter3 extends Inter1,Inter2{//接口之间可以单继承,也可以多继承
}
package com.szy007;
/*
实现类
 */
public class InterImpl extends Object implements Inter1,Inter2,Inter3{
    //类可以继承类的同时实现多个接口
}

2.5抽象类和接口的区别

  • 成员区别

    抽象类:变量,常量;有构造方法;有抽象方法;也有非抽象方法

    接口:常量;抽象方法

  • 关系区别

    类与类:继承,单继承

    类与接口:实现,可以单实现,也可以多实现

    接口与接口:继承,单继承,多继承

  • 设计理念区别

    抽象类:对类抽象,包括属性、行为

    接口:对行为抽象,主要是行为

案例:运动员和教练

需求:我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。为了出国交流,跟乒乓球相关的人员都需要学习英语。请用所学知识分析,这个案例中有哪些具体类,哪些抽象类,哪些接口,并用代码实现。

分析:从具体到抽象

实现:从抽象到具体

使用:使用的是具体的类的对象

4041

package com.szy008;
/*
说英语接口
 */
public interface SpeakEnglish {
    public abstract void speakEnglish();
}
package com.szy008;
/*
抽象类-人类
 */
public abstract class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(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();//抽象的eat方法
}
package com.szy008;
/*
抽象类-教练类
 */
public abstract class  Coach extends Person {
    public Coach() {
    }

    public Coach(String name, int age) {
        super(name, age);
    }
    public abstract void teach();
}
package com.szy008;
/*
抽象类-运动员类
 */
public abstract class Player extends Person{
    public Player() {
    }

    public Player(String name, int age) {
        super(name, age);
    }
    public abstract void study();
}
package com.szy008;
//具体类-篮球教练类
public  class BasketballCoach extends Coach{
    public BasketballCoach() {
    }

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

    @Override
    public void teach() {
        System.out.println("篮球教练教运动员如何投篮");
    }

    @Override
    public void eat() {
        System.out.println("篮球教练吃羊肉");
    }
}
package com.szy008;

//具体类-乒乓教练类
public class PingPangCoach extends Coach implements SpeakEnglish{
    public PingPangCoach() {
    }

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

    @Override
    public void teach() {
        System.out.println("乒乓教练教运动员正反手");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球教练吃烤红薯");
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球教练说英语");
    }
}
package com.szy008;
/*
具体类-篮球运动员类
 */
public class BasketballPlayer extends Player{
    public BasketballPlayer() {
    }

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

    @Override
    public void study() {
        System.out.println("篮球运动员学投篮");
    }

    @Override
    public void eat() {
        System.out.println("篮球运动员喝牛奶");
    }
}
package com.szy008;
/*
具体类-乒乓球运动员类
 */
public class PingPangPlayer extends Player implements SpeakEnglish{
    public PingPangPlayer() {
    }

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

    @Override
    public void study() {
        System.out.println("乒乓球运动员学习正反手");
    }

    @Override
    public void eat() {
        System.out.println("乒乓球运动员喝椰子汁");
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球运动员说英语");
    }
}
package com.szy008;
/*
测试类
 */
public class PersonDemo {
    public static void main(String[] args) {
        //创建对象
        PingPangPlayer p1=new PingPangPlayer();
        p1.setName("王浩");
        p1.setAge(23);
        System.out.println(p1.getName()+p1.getAge());
        p1.study();
        p1.eat();
        p1.speakEnglish();

        BasketballPlayer b1=new BasketballPlayer();
        b1.setName("章正");
        b1.setAge(33);
        System.out.println(b1.getName()+b1.getAge());
        b1.study();
        b1.eat();

    }
}

3.形参和返回值

3.1类名作为形参和返回值

  • 方法的形参是类名,其实需要的是该类的对象

  • 方法的返回值是类名,其实返回的是该类的对象

    package com.szy009;
    
    public class Cat9 {
        public void eat(){
            System.out.println("猫吃鱼");
        }
    }
    
    package com.szy009;
    
    public class CatOperator {
        public void useCat(Cat9 c){//类名作为形参
            c.eat();
        }
        public Cat9 getCat(){//类名作为返回值
            Cat9 c=new Cat9();
            return c;
        }
    }
    
    package com.szy009;
    /*
    测试类
     */
    public class Cat9Demo {
        public static void main(String[] args) {
            //创建操作类对象,并调用方法
            CatOperator c1=new CatOperator();
            Cat9 c2=new Cat9();
            c1.useCat(c2);
    
            Cat9 c3=c1.getCat();
            c3.eat();
        }
    }
    

3.2抽象类名作为形参和返回值

  • 方法的形参是抽象类名,其实需要的是该抽象类的子类对象
  • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
package com.szy010;

public abstract class Animal10 {
    public abstract void eat();
}
package com.szy010;

public class Cat10 extends Animal10{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
package com.szy010;

public class AnimalOperator10 {
    public void useAnimal(Animal10 a){
        a.eat();
    }
    public Animal10 getAnimal(){
        Animal10 a=new Cat10();
        return a;
    }
}
package com.szy010;
/*
测试类
 */
public class Animal10Demo {
    public static void main(String[] args) {
        //创建操作类对象,并调用方法
        AnimalOperator10 a1=new AnimalOperator10();
        Animal10 a2=new Cat10();
        a1.useAnimal(a2);

        Animal10 a3=a1.getAnimal();
        a3.eat();
    }
}

3.3接口名作为形参和返回值

  • 方法的形参是接口名,其实需要的是该接口的实现类对象

  • 方法的返回值是接口名,其实返回的是该接口的实现类对象

    package com.szy011;
    /*接口*/
    public interface Jumpping {
        void jump();
    }
    
    package com.szy011;
    /*
    操作类
     */
    public class JumppingOpreator {
        public void useJumppig(Jumpping j){
            j.jump();
        }
    
        public Jumpping getJumpping(){
            Jumpping j=new Cat11();
            return j;
        }
    
    }
    
    package com.szy011;
    /*
    接口的实现类
     */
    public class Cat11 implements Jumpping{
        @Override
        public void jump() {
            System.out.println("猫猫跳高");
        }
    }
    
    package com.szy011;
    /*
    测试类
     */
    public class JumppingDemo {
        public static void main(String[] args) {
            //创建操作类对象,并调用方法
            JumppingOpreator jo=new JumppingOpreator();
            Jumpping j=new Cat11();
            jo.useJumppig(j);
    
            Jumpping j2=jo.getJumpping();
            j.jump();
        }
    }
    

package com.szy011;
/*
测试类
*/
public class JumppingDemo {
public static void main(String[] args) {
//创建操作类对象,并调用方法
JumppingOpreator jo=new JumppingOpreator();
Jumpping j=new Cat11();
jo.useJumppig(j);

    Jumpping j2=jo.getJumpping();
    j.jump();
}

}

posted @ 2022-03-30 17:45  行雨  阅读(135)  评论(0编辑  收藏  举报