Java之路 - 抽象类、接口、多态、向上向下转型

1.抽象类

如果父类当中的方法不确定如何进行{}方法实现,那么这就是一个抽象方法

抽象方法所在的类必须是抽象类

使用方法:

(1)不能直接创建new抽象类对象

(2)必须用一个子类来继承抽象父类

(3)子类必须覆盖重写抽象父类当中所有的抽象方法

  覆盖重写(实现):去掉抽象方法的abstract关键字,然后补上方法体大括号;

(4)创建子类对象进行使用

public abstract class animal {   //抽象类
    public abstract void eat(); //这是一个抽象方法

    public void nomalMethod(){

    }
}

注意事项:

1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

爷爷、父亲、儿子三类抽象继承关系:

爷爷辈;
public abstract class animal {   //抽象类
    public animal(){
        System.out.println("动物类父类构造方法");
    }
    public abstract void eat(); //这是一个抽象方法

    public abstract void sleep();

    public void nomalMethod(){
        System.out.println("正常方法");
    }
}

父亲辈:
public abstract class Cat extends animal {
    public Cat(){
        System.out.println("猫类构造方法");
    }
    @Override
    public void eat(){
        System.out.println("猫吃鱼");
    }
}

儿子:
public class CatFei extends Cat {
    @Override
    public void sleep() {
        System.out.println("嘿嘿嘿的睡觉");
    }
}

三代抽象类继承

发红包案例:

群主发普通红包。某群有多名成员,群主给成员发普通红包。普通红包的规则:
1. 群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取。
2. 成员领取红包后,保存到成员余额中。
请根据描述,完成案例中所有类的定义以及指定类之间的继承关系,并完成发红包的操作。

public class PocketUser {
    private String name;
    private int money; //当前用户的余额
    public PocketUser() {
        System.out.println("用户的无参构造方法");
    }

    //显示一下当前用户有多少钱
    public void show(){
        System.out.println("用户" + name + "剩余" + money + "元");
    }
    public PocketUser(String name, int money) {
        System.out.println("用户的有参构造方法");
        this.name = name;
        this.money = money;
        System.out.println(this.name);
    }

    public String getName() {
        return name;
    }

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

    public int getMoney() {
        return money;
    }

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

}

父类 用户类

public class PocketManager extends PocketUser {
    public PocketManager(){
        //super();
        System.out.println("管理员的无参构造方法");
    }

    public PocketManager(String name, int money) {
        super(name, money);
        System.out.println("管理员的有参构造方法");
    }
    public ArrayList<Integer> send(int totalMoney, int count){
        //首先需要一个集合,用来存储若干个红包的金额
        ArrayList<Integer> redlist = new ArrayList<>();

        //首先看下自己还剩多少钱
        int leftmoney = super.getMoney();
        if(totalMoney > leftmoney) {
            System.out.println("余额不足");
            return redlist; //返回一个空集合
        }

        //扣钱 重新设置余额
        super.setMoney(leftmoney - totalMoney);

        //发红包需要平均拆分成count份
        int avg = totalMoney / count ; //每份红包的钱数
        int mod = totalMoney % count ; //平均分完红包后甩下的零头
        //除不开的零头,包在最后一个红包里
        //下面把红包一个一个放到红包里
        for (int i = 0; i < count - 1; i++) { //减一是要除去最后一个红包
            redlist.add(avg);
        }

        //最后一个红包的特殊处理
        int last = avg + mod;
        redlist.add(last); //把最后一个红包也放进去

        return redlist;
        }
    }

子类 管理员类

public class PocketMember extends PocketUser{
    public PocketMember(){};
    public PocketMember(String name, int money){
        super(name,money);
    }
    public void receive(ArrayList<Integer>  list){
        //从多个红包当中随机抽取一个红包,给我自己
        //随机获取一个集合当中的索引编号
        int index = new Random().nextInt(list.size());
        //根据索引 从集合当中删除,并且得到被删除的红包给我自己
        int delta =  list.remove(index); // 删除的红包就是自己的

        //自己本来有多少钱呢
        int money = super.getMoney();
        //把收来来的钱加上去
        super.setMoney(money+delta);
    }
}

子类 群成员

public class MainMethod {
    public static void main(String[] args) {
        PocketManager m1 = new PocketManager("chris",150);
        PocketMember one = new PocketMember("joe",5);
        PocketMember two = new PocketMember("lin",10);
        PocketMember three = new PocketMember("sea",15);
        m1.show();
        one.show();
        two.show();
        three.show();
        //群主发红包
        ArrayList<Integer> redpocket = m1.send(20,3);
        //三个成员收红包
        one.receive(redpocket);
        two.receive(redpocket);
        three.receive(redpocket);
        //再来看看大家还有多少钱
        m1.show();
        one.show();
        two.show();
        three.show();

    }
}

主方法

2.接口(Interface) 接口就是多个类的公共规范

(1)接口没有构造方法和静态代码块,不能new,只能通过实现类实现

(2)一个类的直接父类是唯一的,但是一个类是可以同时实现多个接口

(3)如果实现类没有覆盖重写其接口的所有抽象方法。那么他一定要是个抽象类

(4)如果实现类实现的多个接口中多个接口的默认方法重复了,那么要对其进行覆盖重写

(5)一个类如果直接父类当中的方法,和接口当中的方法产生了冲突,优先用父类当中的方法

  如 public class A extends implements MyInterface 时,如果父类当中的方法和接口当中的默认方法重名了,优先使用父类的而不是接口

接口是一种引用数据类型,最重要的内容就是其中的抽象方法

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

接口的格式:

  public interface 接口名称{  接口内容  }

虽然换成了关键字interface 但编译生成的字节码文件依旧是.class

在java8中,接口内容可以包括:

(1)常量

(2)抽象方法

(3)默认方法

(4)静态方法

如果是java9,还可以额外包含有 5. 私有方法

注意事项:

(1)接口当中的抽象方法,修饰符必须是固定的两个关键字:public abstract

(2)这两个关键字修饰符,可以选择性的省略

(3)方法的三要素可以随意定义

3.接口的使用

(1)接口不能直接使用,必须有一个‘’实现类‘’来实现该接口

格式:

  实现类:public class 实现类名称 implements 接口名称}{

  //.....

}

(2)接口的实现类必须覆盖重写(实现)接口中的所有抽象方法

  去掉abstract关键字,加上方法体大括号

(3)创建实现类的对象,进行使用

接口:
public interface MyInterface {
    // 这是抽象方法1
    public abstract void methodAbs1();

    //这也是抽象方法
    void methodAbs2();
}

实现类:
public class MyImpl implements MyInterface {
    @Override
    public void methodAbs1(){
        System.out.println("这是第一个方法体");
    }

    @Override
    public void methodAbs2(){
        System.out.println("这是第二个方法体");

    }
}

如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己必须是抽象类。

4.接口的默认方法定义

格式: public default 返回值类型 方法名称 (参数列表){ 方法体 }

接口当中的默认方法,可以解决接口升级的问题

应用场景:当一个接口已经被投入很久了,而且有抽象方法,现在又添加了一个抽象方法,那么此时已经实现该接口的类不是全都要改了?

  答:将其设置会默认方法,此时默认方法会被其实现类继承

注意事项:

  1.接口的默认方法可以被实现类直接调用

  2.接口的默认方法也可以被其实现类覆盖重写

5.接口的静态方法  当对象与对象直接有共有的特点时,或者一样的方法,那么就与类有关

格式:public static 返回值类型 (参数列表){  方法体 }

注意!!!!  不能通过接口实现类的对象来调用接口当中的静态方法!!! 只能通过接口名称来调用其静态方法

6.接口的私有方法

当两个方法体直接有太多重复代码,此时需要把重复的抽取出来,抽取一个公共方法来解决两个默认方法之间重复代码的问题

但是这个共有方法不应该让实现类使用,应该是内部私有化的。从java9开始,接口当中允许定义私有方法

(1)普通私有方法,解决多个默认方法之间重复代码问题

  格式:private 返回值类型  方法名称 (参数列表){ 方法体 }

(2)静态私有方法,解决多个静态方法之间重复代码问题

  格式:private static  返回值类型 方法名称(参数列表){方法体}

public interface MyInterface {
    public default void defaultMethod1(){
        System.out.println("这是新添加的默认方法1");
//        System.out.println("AAA");
//        System.out.println("BBB");
        methodCommon();
    }
    public default void defaultMethod2(){
        System.out.println("这是新添加的默认方法2");
//        System.out.println("AAA"); //重复代码
//        System.out.println("BBB"); //重复代码
        methodCommon();
    }
    private void methodCommon(){
        System.out.println("AAA");
        System.out.println("BBB");
    }
}

7.接口的常量

接口当中也可以定义“成员变量”,但是必须使用public static final 三个关键字进行修饰

从效果上看这其实就是接口的常量了

1.格式:public static final 数据类型 常量名称 = 数据值;  一旦赋值不可修改  一旦使用final关键字进行修饰,所以不可变

   接口当中的常量,可以省略public static final, 但其实它还是不可变的,默认存在

2.接口当中的常量,必须进行赋值,不能不赋值,必须手动进行赋值

3.接口常量中的名称,使用完全大写的字母,用下划线进行分隔

public static final int NUM_OF_MY_CLASS = 6;

8.接口内容小结

9.类与接口的关系

(1)类与类之间是单继承的

(2)类与接口之间是多实现的

(3)接口与接口之间是多继承的

  如果多个父接口当中的默认方法重复,那么子接口必须进行默认方法的覆盖重写,而且要带着default!不能删除

10.多态(Polymorphism)

extends继承和implements实现,是多态性的前提

格式:父类名称 对象名 = new 子类名称(); 或者 接口名称 对象名 = new 实现类名称();  左父右子

访问成员变量的两种方式:口诀:编译看左边,运行看左边

(1)直接通过对象名称访问,看等号左边是谁,优先用谁,没有则向上找,不会找右侧的子类!!!

(2)直接通过成员方法访问,看该方法属于谁,优先用谁,没有则向上找,子类没有覆盖重写就是父类中找,如果子类覆盖重写了,就从子类中找

访问成员方法的规则:口诀:编译看左边,运行看右边

  new的是谁,就优先用谁,没有则向上找

多态的使用:

父类:
public class Fu {
    int num = 10;
    public Fu(){
        System.out.println("父类无参构造");
    }
    public Fu(int num){
        System.out.println("父类you参构造");
    }
    public void fumethod(){
        System.out.println("父类方法执行");
    }
    public void method(){
        System.out.println("父类重名方法执行");
        int fu = 222;
        fumethod();
    }
}

子类:
public class Zi extends Fu{
    int num = 20;
    public Zi(){
        this(12);
        System.out.println("子类无参构造");
    }
    public Zi(int num){
        System.out.println("子类有参构造");
    }
    public void ziMethod(){
        int num = 30;
        System.out.println("子类方法执行");
        System.out.println(num); //输出的是局部变量num = 30
        System.out.println(this.num); //输出的是成员变量 num = 20
        System.out.println(super.num); //输出的是父类的成员变量 num = 10
//        super.method();
    }

    @Override
    public void method() {
        super.method();
    }
}
main方法:
public class InterfaceMain {
    public static void main(String[] args) {
        //多态的使用
        Fu obj = new Zi();
        obj.method();
        obj.fumethod();
        Zi zi = (Zi) obj;
        zi.fumethod();
        System.out.println(obj instanceof Zi);
    }
}

使用多态的好处:!!!!

11.对象的向上转型,就是多态写法

含义:右侧创建一个子类对象,把它当做父类来看待使用  就是左父右子

注意事项:向上转型一定是安全的,从小范围转换为大范围,有一个弊端,子类的特有方法无法使用

解决方案:用对象的向下转型【还原】  一定要进行类型判断 instanceof

格式:子类 新的对象名 = (子类名称) 原本的对象名;  含义:将父类对象还原为原来的子类对象

注意事项:原本的对象必须是new的子类对象  如 原本是 animal animal = new Cat();应该这样转 Cat(原本右侧new的类)  cat(新的对象名) = (Cat) animal;

  如果不遵守,而是转成狗类,则会报 java.lang.ClassCastException

12.instanceof   子类也是一个父类!!

如何才能查看原本父类指向的子类是谁呢? - - instanceof 来判断

格式: 对象 instanceof 类名称  会返回一个boolean值  

  animal instance of  Cat

public class InterfaceMain {
    public static void main(String[] args) {
        Zi zi = new Zi();
        give(zi);
    }
    public static void give(Fu fu){
        System.out.println("来啦");
    }
}

 13.接口多态的综合案例
- - - - 笔记本电脑
笔记本电脑(laptop)通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口,
但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。
定义USB接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守
USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。
案例分析:

进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
(1)USB接口,包含开启功能、关闭功能
(2)笔记本类,包含运行功能、关机功能、使用USB设备功能
(3)鼠标类,要实现USB接口,并具备点击的方法
(4)键盘类,要实现USB接口,具备敲击的方法

public interface USB {
    public abstract void open();
    public abstract void close();
}

USB接口

public class Mouse implements USB {

    @Override
    public void open() {
        System.out.println("鼠标已连接,可以正常使用");
    }

    @Override
    public void close() {
        System.out.println("鼠标已关闭");

    }
    public void kick(){
        System.out.println("鼠标点击使用");
    }
}

鼠标实现USB

public class Keyboard implements USB{
    @Override
    public void open() {
        System.out.println("键盘已连接,可以正常使用");
    }

    @Override
    public void close() {
        System.out.println("键盘已断开");

    }
    public void press(){
        System.out.println("键盘输入单词");
    }
}

键盘实现USB

public class MyLaptop {
    private String user;

    public MyLaptop() {}
    public MyLaptop(String user) {
        this.user = user;
        System.out.println("用户" + user +"正在使用电脑");
    }

    public void powerOff(USB usb1,USB usb2){
        System.out.println("笔记本正在关机");
        usb1.close();
        usb2.close();

    }
    public void powerOn(){
        System.out.println("笔记本正在开机");
    }
    public void useDevice(USB usb){
        if (usb instanceof Mouse){
            System.out.println("这是鼠标设备,使用鼠标设备");
            Mouse mouse = (Mouse) usb; //因为不确定传进来的usb设备是鼠标还是键盘,确定后要向下转型
            mouse.kick();
        } else if(usb instanceof Keyboard){
            System.out.println("这是键盘,使用键盘");
            Keyboard keyboard = (Keyboard) usb;
            keyboard.press();
        }
    }
}

笔记本电脑设备

public class UseLaptop {
    public static void main(String[] args) {
        USB mouse = new Mouse();
        USB keyboard = new Keyboard();
        MyLaptop computer = new MyLaptop("蔡晓武");
        computer.powerOn();
        computer.useDevice(mouse);
        computer.useDevice(keyboard);
        computer.powerOff(mouse,keyboard);

    }
}

用户最终使用

原文地址:https://www.cnblogs.com/caixiaowu/p/12681477.html

时间: 2024-08-02 21:11:38

Java之路 - 抽象类、接口、多态、向上向下转型的相关文章

2.25 Java基础总结 ①多态②向上向下转型③instanceof

①多态②向上向下转型③instanceof 一.多态即相同行为,不同实现有两种方法:重载和重写分类:①静态多态:编译时已经确定效果,所用重载实现(不是指static)②动态多态:编译未知,运行已知(使用动态绑定和重写实现) 动态绑定:父类的引用指向子类的对象,执行相应的子类方法,而不是父类的,从而实现多态性 二.向上转型,向下转型向上转型:一个父类的引用可以指向不同的子类对象,或者说一个子类的对象可以被当做一个父类类型低精度向高精度转pet = cat;自动转,子类向父类 向下转型:强制转,有很

Java面向对象作业-用接口方式测试向下转型

Java面向对象作业-用接口方式测试向下转型 根据视频的里实例 我们直接修改Test2测试方法: 1 package com.java1234.chap03.sec13; 2 3 public class Test2 { 4 5 public static void main(String[] args) { 6 People p1=new Student(); 7 p1.say(); 8 9 Student student=(Student) p1; 10 student.say(); 11

JAVA笔记6__抽象类/接口/多态/instanceof关键字、父类设计法则

/** * 抽象类:很多具有相同特征和行为的类可以抽象为一个抽象类 * 1.抽象类可以没有抽象方法,有抽象方法的类必须是抽象类 * 2.非抽象类继承抽象类必须实现抽象方法[可以是空实现] * 3.抽象类可以有方法和属性 * 4.抽象类不能被实例化 * 5.抽象类不能声明为final * 6.抽象类可以有构造方法[不代表实例化对象] */ public class Main { public static void main(String[] args) { Goddess m1 = new Go

Java面向对象之多态(向上向下转型) 入门实例

一.基础概念 多态: 重点是对象的多态性.某一事物的多种体现形态. 多态的作用: 1.提高了代码的扩展性,后期出现的功能,可以被之前的程序所执行. 2.不能使用子类特有的功能.只能使用覆盖父类的功能. 多态的前提: 1.必须要有继承关系或者实现关系. 2.通常对方法进行重写.覆盖. 3.父类或者接口要引用指向子类对象. 多态向上转型: 1.提高程序的扩展性,隐藏了具体子类型 2.只能使用父类中的功能,不能使用子类特有的功能.功能被限定了. 多态向下转型: 1.可以使用子类型的特有功能. 2.必须

从向上向下转型到----抽象类接口(一)

对象的多态性-向上向下转型 向上转型:子类对象变为父类对象,格式:父类 父类对象 = 子类实例,自动转换; 向下转型:父类对象变为子类对象,格式:子类 子类对象 = (子类) 父类实例,强制转换; 注意:对象的多态性和方法复写是联系在一起的 向上转型: class A{ public void print(){ System.out.println("a") } } class B extends A{ public void print(){ System.out.println(&

Java多态之向下转型

目录 Java多态之向下转型 强制类型转换 instanceof Java多态之向下转型 往期回顾:我们学习了向上转型和动态绑定的概念,可以知道在继承关系中,将一个子类对象赋值给父类的引用变量,调用父类的方法,在实际运行时,就可以根据子类中重写的方法执行不同的操作.其中有一个弊端,就是在向上转型的过程中,其实丢失了一部分子类特有的功能,毕竟它只允许调用父类中的方法.那么,如何在这时调用子类中的方法呢,这时就需要与向上转型相对应的方法,就是所谓的:向下转型. 向上转型是自动就能完成的,向下转型则需

抽象类 接口 多态

一 抽象类(abstract) 抽象类的概念只抽取了很多类的方法的声明,方法声明用abstract修饰.一个类如果有抽象方法,那么这个类必须是抽象类.抽象类里边可以没有抽象方法,如果这么做只有一个目的:不让你创建这个类的对象.抽象类不能被实例化,不能创建对象.如果一个类继承抽象类,那么,它要么重写抽象类中的所有抽象方法,要么本身也是抽象类. 抽象类的成员成员变量:可以是常量,也可以是变量.子类可以直接继承抽象类中的成员变量.成员方法:可以是抽象的,也可以是非抽象的.抽象方法在子类中必须要被实现.

java(向上向下转型)

在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型. 5.13.1 向上转型 我们在现实中常常这样说:这个人会唱歌.在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念"人".再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类).我们现实中也经常这样说:麻雀是鸟.这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类.这也符合Java提倡的面向抽象编程思想.来看下面的代码: package a.

对象的向上向下转型规则

对象的转型:向上转型:子类-->父类向下转型:父类-->子类 例如: Class B extends AA a;B b;向上转型是自动的:b = new B();a = b; 向下转型要强制转换:a = new B();b = (B)a; 正确 a = new A();b = (B)a; 错误   *并且在向下转型之前要进行向上转型:即通过a=new B();得到的: *否则会报java.lang.ClassCastException: note.A cannot be cast to not