2022-07-26 第八小组 学习笔记

目录

抽象  

抽象类的使用总结和注意事项

思考

抽象类案例

 特点与注意事项

final和abstract的关系?

接口

接口的关键字:用interface来定义

接口不能创建对象。

定义与特点

格式

接口的基本使用

接口实现的注意事项

接口与接口的关系:多继承

接口多继承的作用

栈&队列

栈和队列是两种操作受限的线性表。

栈的特点

队列

栈与队列的相同点

栈与队列的不同点

案例1

案例2

总结


抽象  

某个父类知道其所有子类要完成某功能,但是每个子类完成情况都不一样,父类就只定义该功能的基本要求,具体实现由子类完成,这个类就可以是一个抽象类,抽象类其实就是一种不完全的设计图。


抽象类必须使用abstract修饰:

修饰符 abstract class 类名{   }

Animal

父类,相当于子类的模板

package ab;

public abstract class Animal {
public abstract void run();
//{
//    System.out.println("动物可以跑");
//}
}

Tiger

package ab;

public  class Tiger extends Animal{
    @Override
    public void run() {
        System.out.println("老虎可以跑");
    }
}

Dog

package ab;

public class Dog extends Animal{
    @Override
    public void run() {
        System.out.println("狗跑的很快");
    }
}

测试输出:

package ab;

public class Test {
    public static void main(String[] args) {
        Animal animal=new Tiger();
        animal.run();
        Animal animal1=new Dog();
        animal1.run();
    }
}

抽象类的使用总结和注意事项

1.抽象类用来被继承的,充当模板的,同时也可以提高代码的复用。抽象方法是交给子类重写实现的。

2.一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

3.抽象方法必须在抽象类里

4.抽象类不能被实例化:不能创建对象[ A a=new A();]

5.抽象类构造器存在的意义:为了约定子类的构造器必须和父类要匹配

6.abstract能修饰什么:类、方法。不能修饰:变量、代码块、构造器(构造器没有抽象的概念)

7.抽象方法必须是public或者protected(因为如果是private,不能被子类继承,子类便无法实现该方法),默认情况下是可以的。(默认情况其实就是public)

8.抽象类不能被直接实例化,需要依靠子类采用向上转型的方式处理

9.抽象类必须有子类,使用extends继承,一个类只能继承一个抽象类。

10.子类(如果不是抽象类)则必须重写抽象类中的所有抽象方法 (如果子类没有实现父类的抽象方法,必须将子类也定义为abstract)

11.抽象方法,没有大括号,没有方法体。

12.约定大于配置,配置大于编码

13.抽象类不一定有抽象方法,有抽象方法的类一定是抽象类

思考

Q1:当我们定义一个抽象类,有那些结构?

A1:属性、普通的成员方法、构造器、抽象方法、常量

Q2:抽象类中能不能没有抽象方法?

A2:可以!(如果没有抽象方法,尽量不要写抽象类,非要写也可以)

Q3:抽象方法能否用private修饰?

A3:不能!默认可以,开发中抽象方法基本上是public

Q4:抽象方法能不能用final修饰?

A4:不能、用final修饰的方法时不允许重写

Q5:抽象类能不能用final修饰?

A5:不能、用final修饰的类不允许重写

Q6:抽象方法,存在的意义是什么?

A6:根本意义:约定。自定义的规则。

Q7:抽象方法到底约定了什么,规定了什么,定了哪些规则?

A7:约定了返回值,访问权限,参数列表,需要在重写的时候去定义方法体

抽象类的作用是什么样的?什么时候定义抽象类?

1.可以被子类继承、充当模板的、同时也可以提高代码的复用。

2.如果父类知道子类要完成某个功能,实现要交给子类。

抽象方法是什么样的?

只有方法签名,没有方法体,使用了abstract修饰。


抽象类案例

(本案例参考)https://www.zhihu.com/education/video-course/1483149993460109313?section_id=1483150079171747840

Card(父类)

package ab.anli;

/**
 * 抽象类的父类
 */
public abstract class Card {
    private String name;//主人的名称
    private double money;

    /**
     * 支付功能:子类一定要支付,但是每个子类支付的情况不一样,所以父类把支付定义成抽象方法,交给具体子类实现
     */
    public abstract void pay(double money);

    public String getName() {
        return name;
    }

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

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

金卡(子类)

package ab.anli;

public class GoldCard extends Card {
    /*金卡*/
    @Override
    public void pay(double money) {
        //把优惠后的金额算出来
        double rs = money * 0.8;
        double lastMoney = getMoney() - rs;//剩余的钱=一开始注入的钱10000-打完折后的钱

        System.out.println(getName() + "当前账户总金额:" +
                getMoney() + "  当前消费了:" + rs + "  剩余余额:" + lastMoney);
        setMoney(lastMoney);
    }//先获得银行卡主人的名字,以及当前注入的10000元(getMoney()),然后,当前消费是8折,剩余钱数是一开始注入的钱10000-打完折后的钱
}

银卡(子类)

package ab.anli;

public class SilverCard extends Card {
    @Override
    public void pay(double money) {
        double rs1 = money * 0.85;
        double lastMoney1 = getMoney() - rs1;

        System.out.println(getName() + "当前账户余额为:" + getMoney() + "当前消费了:" + rs1 +
                "余额为:" + lastMoney1);
        setMoney(lastMoney1);
    }
}

测试

package ab.anli;

public class Test {
    public static void main(String[] args) {
        GoldCard goldCard=new GoldCard();
        goldCard.setMoney(10000);//父类
        goldCard.setName("菠萝");
        goldCard.pay(6000);
        System.out.println("---------------");
        SilverCard silverCard=new SilverCard();
        silverCard.setName("吹雪");
        silverCard.setMoney(5000);
        silverCard.pay(300);
    }
}

输出

 特点与注意事项

有得有失:得到了抽象方法,失去了创建对象的能力。

public abstract void run();

 Why?

抽象类不能创建对象不是因为没有构造器,其实是有构造器的,子类需要调用父类构造器,如果没有子类就会报错。那为什么有构造器也不能创建对象呢?

反证法:假如能创建,animal.run();用animal对象调用run方法【参考本文第一个案例】,但是run方法不能跑,因为根本连方法体都没有,它是让子类去重写的,因此假如抽象类能创建对象,万一拿对象去调用从抽象方法,抽象方法跑不了。它不是一个完整的方法,因此抽象类不能创建对象。另外,抽象,本身就是不可以实例化的。

final和abstract的关系?

互斥关系

1.final修饰类,类不能被继承,abstract修饰类,类是抽象类(迫不及待地希望被继承,用它的模板)

abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。

2.抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。

接口

接口就是体现规范的,其中用抽象方法定义的一组行为规范,接口是更加彻底的抽象。

体现了现实世界中“如果你是这类事物...则必须完成某些行为...”的思想。

接口的关键字:用interface来定义

接口不能创建对象。


定义与特点

格式

public interface 接口名{

        //常量

        //抽象方法

}

JDK1.7之前:接口中只能定义抽象方法,不能有属性,不能有方法。(静态的常量)

JDK8之前:接口中只能是抽象方法和常量。

JDK8及以后:接口中只能定义抽象方法,不能有属性,可以有默认方法和静态方法,静态常量。

JDK7---JDK8:默认方法,静态方法。

接口不能实例化。

接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。

接口中的抽象方法默认是public abstract,推荐省略,接口默认会为你加上:void run();

接口中的常量默认是public static final,推荐省略。接口默认会为你加上。

接口的基本使用

接口是用来被类实现(implements)的,实现接口的类称为实现类。实现类可以理解成所谓的子类。(人话:接口就是干爹

修饰符 class 实现类 implements 接口1,接口2, 接口3,....{     }

实现的关键字:implements

接口可以被单实现,也可以被多实现。

创建SportMan、Law接口

package interface_26;
/**
 * 接口*/
public interface SportMan {
    void run();
    void eat();
}
package interface_26;

public interface Law {
    void rule();
}

创建PingPangMen、Test类

package interface_26;
/*实现类*/
public class PingPangMen implements SportMan, Law {//要实现两个接口,implements后面放的就是干爹类
    private String name;

    public PingPangMen(String name) {//通过有参构造器进行初始化
        this.name = name;
    }

    @Override
    public void rule() {
        System.out.println(name+"这个运动员遵守规则");
    }

    @Override
    public void run() {
        System.out.println(name+"必须训练");
    }

    @Override
    public void eat() {
        System.out.println(name+"按时吃饭");
    }

}
package interface_26;

public class Test {
    public static void main(String[] args) {
        PingPangMen pingPangMen=new PingPangMen("张继科");
        pingPangMen.run();
        pingPangMen.eat();
        pingPangMen.rule();
    }
}

输出结果

接口实现的注意事项

一个类实现接口,必须重写完全部接口的全部抽象方法否则这个类需要定义成抽象类。

接口与接口的关系:多继承

类和类的关系:单继承。

类和接口的关系:多实现。

接口和接口的关系:多继承,一个接口可以同时继承多个接口。

创建SportMan、Person接口

package interface_extends;

public interface SportMen {
    void run();
    void drink();
}
package interface_extends;

public interface Person {
    void eat();
}

创建Basketball类,让它实现三个接口多继承

package interface_extends;

import interface_26.Law;

/*实现类*/
public class Basketball implements SportMen,Law,Person {
   
}
//现在是报错的!!要重写方法

重写之后

package interface_extends;

import interface_26.Law;

/*实现类*/
public class Basketball implements SportMen,Law,Person {


    @Override
    public void rule() {
        
    }

    @Override
    public void eat() {

    }

    @Override
    public void run() {

    }

    @Override
    public void drink() {

    }
}

由于后面实现的接口太多啦!能不能把这些接口规范合并呢?

SportMen接口

让SportMen同时继承Law,Person这两个接口,SportMen把这两个接口合并起来了,Basketball就不用再实现三个接口了,直接实现SportMen就可以了。

package interface_extends;

import interface_26.Law;

public interface SportMen extends Law,Person {
    void run();
    void drink();
}
package interface_extends;


/*实现类*/
public class Basketball implements SportMen{


    @Override
    public void rule() {

    }

    @Override
    public void eat() {

    }

    @Override
    public void run() {

    }

    @Override
    public void drink() {

    }
}

接口多继承的作用

规范合并,整合多个接口为同一个接口,便于子类实现。

栈&队列

栈和队列是两种操作受限的线性表。

栈:只能在一端进行插入和删除操作的特殊线性表

允许进行插入和删除操作的一端称为栈顶,另一端称为栈底。

栈的特点

先进后出(FILO)

队列

只允许在表位插入元素,在表头删除元素,FIFO First In First Out

栈与队列的相同点

1.都是线性结构

2.插入操作都是在表尾进行

3.都可以通过顺序结构和链式结构实现。

栈与队列的不同点

队列:先进先出,栈:先进后出

案例1

创建队列Queue类

定义成员变量:private SuperLinked superLinked = new SuperLinked();

入队(新增)

public void add(Integer item){

        superLinked.add(item);
    }

如果调用add方法,只传数据,不传位置的话,默认在单链表的表尾。

出队(删除)

public Integer poll(){
        // 1.判断这个队列是不是空
        if(empty()){
            return null;//如果是空,直接返回空
        }
        // 2.找到队列的头
        Integer integer = superLinked.get(0);
        // 3.把队伍的头删掉
        superLinked.removeFirst();
        // 4.返回删除的值
        return integer;
    }

判断这个队列是不是空:其实就是判断链表是不是空。只需要判断它的size是不是0,如果是0,就是空的,return true;其他情况就是return false;

if(superLink.size()==0){
    return true;
    }
return false;
    }

代码优化:

return superLink.size()==0;

返回队首,不出队

  public Integer peek() {//一般获取队列首部的元素都叫peek
        if(empty()) {//判断是否为空
            return null;
        }
        return superLinked.get(0);
    }

测试:

返回队首

 public static void main(String[] args) {
        Queue queue = new Queue();
        queue.add(1);
        queue.add(120);
        queue.add(50);
        queue.add(999);

        System.out.println(queue.peek());
    }

 出队


 public static void main(String[] args) {
        Queue queue = new Queue();
        queue.add(1);
        queue.add(120);
        queue.add(50);
        queue.add(999);

        queue.poll();

        System.out.println(queue.peek());
    }

 

案例2

创建栈Stack

定义成员变量:private SuperLinked superLinked = new SuperLinked();

入栈/压栈

public void push(Integer item){

        superLinked.add(item);
    }

判断是否为空

private boolean empty() {

        return superLinked.size() == 0;
    }

返回栈顶元素,不出栈

public Integer peek(){
        if(empty()) {
            return null;
        }
        return superLinked.get(superLinked.size() - 1);//栈顶元素是底部最后一个
    }

删除/出栈,从栈尾出去

 public Integer pop(){
        if(empty()) {
            return null;
        }
//找到尾部
        Integer integer = superLinked.get(superLinked.get(superLinked.size() - 1));
        superLinked.remove(superLinked.size() - 1);
        return integer;
    }

测试  添加

public static void main(String[] args) {
        // 测试
        Stack stack = new Stack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);

        System.out.println(stack.peek());
    }

删除

public static void main(String[] args) {
        // 测试
        Stack stack = new Stack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);

        stack.pop();

        System.out.println(stack.peek());
    }

总结

今天学了抽象、接口、栈和队列。其中抽象和接口理解的相对来说比较好,栈和队列只能说能听白老师讲的意思,但是自己写不出来。还是要配合前面讲的链表多加练习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值