面向对象-多态

一、多态

1.1 介绍

多态:多种形态

代码:方法的多态性 --> 同一个方法,出现不同的功能 -> aniaml.play()

(属性没有多态性)

多态的好处:

  • 扩展性强,让代码更灵活
  • 减少耦合度 —> 开发思想:高内聚(即尽可能自己完成),低耦合(即使用别人的东西)

多态出现的前提:

  • 继承/实现
  • 重写
  • 向上转型(父类引用指向子类对象)

1.2 示例

父类:

public class Animal {
    String name;

    public void  eat(){
        System.out.println("动物吃东西 ");
    }
}

子类:

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        //这也算是类型转换;小向大默认进行
        //向上转型 -- 父类引用(父类对象)指向子类对象
        Animal animal = new Dog();
        Animal animal1 = new Cat();

        /**
         * 编译看父类,运行看子类
         */
        animal.eat();//狗吃骨头
        animal1.eat();//猫吃鱼

        //new Dog -  子类
        feedAnimal(new Dog());
        feedAnimal(new Cat());
    }

    /**
     * 多态的应用场景1:把方法的参数设计成父类
     * 调用方法时传入子类,让方法出现多态性
     * 目的:扩展性强
     * @param animal
     */dd
    public static void feedAnimal(Animal animal){
        animal.eat();
    }
}

1.3 instanceof【了解】

向上转型 :子类对象赋值给父类引用

向下转型:父类引用(对象)赋值给子类引用

  • 注意:向下转型是必须先有向上转型,才能成功向下转型
public static void main(String[] args) {
    //向上转型
    Animal animal = new Dog();
    //调用父类与子类都有的方法  --  父类编译,子类运行
    animal.eat();
    //向上转型后,无法调用子类特有的方法
    //animal.watch();

    System.out.println("------------");
    //向下转型
    Dog dog = (Dog) animal;
    //调用子类特有的方法
    dog.watch();//狗会看门

    System.out.println("-------------------");
    feedAnimal(new Dog());
    feedAnimal(new Cat());

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

    //instanceof 可以调用子类特有方法
    show(new Dog());
    show(new Cat());
    //System.out.println(cover(65));
}

//多态设计方法 --  输出狗类与猫类重写父类的共有方法
public static void feedAnimal(Animal animal) {
    animal.eat();
}

// 多态设计方法(instanceof)  --  输出狗类与猫类的特有方法
public static void show(Animal animal) {
    /**
     * instanceof 判断对象是否属于某个类的实例
     */
    if (animal instanceof Dog) {
        Dog dog = (Dog) animal;
        dog.watch();
    } else if (animal instanceof Cat) {
        Cat cat = (Cat) animal;
        cat.sleep();
    }
}

ASCII码值

在这里插入图片描述

设计一个方法,将数字转成ASCII中的对应的字母
//数字65 ==> A 97 ==> a
//65~90 A~Z; 97~122 a~z;
//0-65535之间的整数可以赋值给char,char是对应的ascii值
//char c2 = 65;//A
public static String cover(int a) {
String result = “”;//作用域
if (a>=65 && a<=90 || a>=97 && a<=122){
char c = (char) a;//将int型强转为char型
result = c +“”;//任何数据拼接字符串,都会变成字符串
}else {
System.out.println(“err”);
}
return result;
}

测试方法

System.out.println(cover(65));//A

二、多态总结

2.1 总结

代码写法:类中有另外一个类的属性,部门类中员工属性,老师类中学生类数组属性

静态:

  • 当想要共享时就用static
  • 当想要方便调用时方法/属性时,加static

多态

  • 前提:继承、重写、向上转型
  • 运行效果:编译看父类,运行看子类
  • 好处:扩展、灵活
  • 多态使用场景(大装小,父类装子类)
    • 场景1:方法的参数列表是父类类型,传参数传子类对象
    • 场景2:父类数组,装子类对象
    • 场景3:父类类型当方法的返回值类型,return 返回子类对象

2.2 场景2:

父类:

//形状 - -父类
public class Shape {
    //面积方法
    public double area(){
        return 0.0;
    }
    //周长方法
    public double girth(){
        return 0.0;
    }
}

子类:

//圆类
public class Circle extends Shape {
    private double r;

    public Circle(double r) {
        this.r = r;
    }

    @Override
    public double area() {
        return 3.14 * r * r;
    }

    @Override
    public double girth() {
        return 2 * 3.14 * r;
    }
}
//矩形类
public class Rect extends Shape {
    private double l;//长
    private double w;//宽

    public Rect(double l, double w) {
        this.l = l;
        this.w = w;
    }

    @Override
    public double area() {
        return l * w;
    }

    @Override
    public double girth() {
        return 2 *(l+w);
    }
}
//正方形类
public class Square extends Shape {
    private double l;//边长

    public Square(double l) {
        this.l = l;
    }

    @Override
    public double area() {
        return l * l;
    }

    @Override
    public double girth() {
        return 4 * l;
    }
}

测试类:

public static void main(String[] args) {
    //创建一个长度为3的数组,且可以存储不同类型的对象
    Shape[] shapeArr = new Shape[3];
    //向上转型(圆形对象赋值给父类形状对象)
    shapeArr[0] = new Circle(10);
    shapeArr[1] = new Rect(10,10);
    shapeArr[2] = new Square(10);
    for (int i = 0; i < shapeArr.length; i++) {
        System.out.println("形状的面积"+shapeArr[i].area());//能把方法放在输出语句中的,是因为方法有返回值
        System.out.println("形状的周长"+shapeArr[i].girth());
    }
}

结果:
在这里插入图片描述

三、抽象类(abstract)

抽象:抽象就是不具体

抽象类: 方法变的不具体

3.1 语法

/**
 * Created by slc on 2023/10/12.
 * 1.方法抽象是指方法没有方法体,还需要abstract修饰
 * 2.抽象方法需要放在抽象类,使用abstract修饰类
 *   -- 解释1.父类定义了方法,子类也重写了父类方法,此时就不用父类方法了,干脆就直接定义为抽象方法
 * 3.抽象类可以有正常方法
 * 4.abstract 不能修饰属性
 * 5.抽象类中可以有构造方法,但是不能直接new出来
 *      --即抽象方法所在的类不能被创建对象
 * 6.抽象方法存在作用:是用来被子类继承的(重写)
 */
public abstract class Animal {
    String name = "huahua";

    public abstract void eat();
    public abstract void play();

    public  Animal(){
        System.out.println("Animal()");
    }
}
/**
 * Created by slc on 2023/10/12.
 * 1.子类继承抽象类,二选一操作
 *      1)要么本身定义为抽象类
 *      2)要么实现所有的抽象方法(重写)
 */
public class Dog extends Animal{
    public Dog(){
        System.out.println("Dog()");
    }
    @Override
    public void eat() {
    }

    @Override
    public void play() {
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        //抽象类不能实例化  -- 抽象类不能创建对象
        //new Animal();

        //创建子类对象 (继承了抽象类) --
        Dog dog = new Dog();
        System.out.println(dog.name);
        
		System.out.println("-----------");
        //抽象类虽然不创建对象,但是可以当作父类引用指向子类对象
        //向上转型
        Animal animal = new Dog();
        animal.eat();
    }
}

结果:
在这里插入图片描述

3.2 使用总结

抽象类应用就是一种约束的效果,是一种限制,子类一旦继承父类,就必须要重写方法

当设计程序时,有些类需要被子类继承且必须重写方法时,就把父类设计成抽象类

抽象类是用来抽象性差异。具体共同点

也就是将差异性方法抽象化,提供给子类用于重写。共同的方法具体化,所有子类继承使用

把子类不一样的方法抽象成抽象方法,每个子类都重写

把子类都一样的方法提取到父类,每个子类直接用,不用重写。

四、 接口 (interface)

比抽象还抽象的Java文件就是 - 接口

4.1 特性

类就是一个模板,来描述一些统一的特性

接口不是类,只是一种定义,只是一种规范

引用数据类型:数组、类、接口

接口不是类,比抽象类还抽象的一种Java文件

  • 接口不是类,使用interface所修饰

  • 接口中没有属性,所有属性都是常量默认被public static final所修饰

  • 接口中不能定义普通方法,所有的方法都是抽象的,默认都是被public abstract所修饰

  • 接口中没有构造方法,既不能创建对象

  • 接口主要是用来被子类实现implements

  • 子类实现接口,必须重写接口中的所有抽象方法,否则就要将自己定义为抽象类

  • 子类允许多实现接口,中间用逗号隔开

  • 子类在允许继承的同时,还可以实现接口

  • public class UDisk extends Electron implements USB,IA,Disk{}
    
  • 接口之间允许继承,且允许多继承(类不允许多继承)

4.2 应用

与抽象类用处基本一致,多用在多态的场景

USB usb = new UDisk();

4.3 代码演示

U盘类:

/**
 * Created by slc on 2023/10/13.
 * - 子类实现接口,必须重写接口中的所有抽象方法,(否则就要将自己定义为抽象类)
 * - 子类允许多实现接口,中间用逗号隔开
 * - 子类在允许继承的同时,还可以实现接口
 */
//U盘类
public class UDisk extends Electron implements USB,Disk{
    //重写Electron中的抽象方法
    @Override
    public void show() {
        System.out.println("UDisk show()");
    }
    //重写USB接口中的抽象方法
    @Override
    public void trans() {
        System.out.println("UDisk trans()");
    }

    //重写Disk接口中的抽象方法
    @Override
    public void save() {
        System.out.println("UDisk save()");
    }
}

抽象类(电子设备)

//电子设备
public abstract class Electron {
    public abstract void show();
}

USB接口:

/**
 * Created by slc on 2023/10/13.
 * 接口不是类,是使用interface修饰
 * <p>
 * 接口可以继承接口,且是多继承
 */
public interface USB extends Disk {
    /**
     * 接口中属性默认被pubulic修饰 ,而且只能被public修饰
     * 即接口中的属性都是 静态常量
     * -- -static 是静态,可以直接通过类名.属性直接调用
     */
    public static final int length = 5;

    /**
     * 接口中的方法全部
     * 默认被public abstract所修饰
     * 即所有方法都是抽象类
     */
    public abstract void trans();
    /**
     * 接口中没有构造方法
     *   --- 即不允许创建构造方法
     */
    // public USB(){};
}

接口:

//接口
public interface Disk {
    void save();
}

测试类:

public class Test {
    public static void main(String[] args) {
        //创建对象
        //USB usb = new USB();//因为USB是abstract,无法实例化,既无法创建对象

        //向上引用  -- 即父类引用指向子类对象
        USB usb = new UDisk();
        usb.trans();
    }
}

输出结果:
在这里插入图片描述

4.4 继承与实现的经验

对于以后写代码,该怎么设计?

  • 很多类有公共的属性,方法抽取成父类来继承
  • 有些类中的方法被抽取到父类中,但是子类又不合适还需要重写,那就把类和方法定义成抽象
  • 将一些功能性的行为定义成接口,让想拥有这些功能的类去实现即可

五、内部类

5.1 概述

内部类的概念:

在一个类中定义的类,称之为内部类,外面的类称为外部类

内部类的分类:

  • 1.成员内部类
  • 2.静态内部类
  • 3.局部内部类
  • 4.匿名内部类

内部类的特点:

  • 1.内部类可以访问到外部类的私有成员,且不破坏封装性
  • 2.内部类也会生成.class文件.名为:外部类名$内部类名.class

外部类的特点:

  • 1.一个Java文件中可以编写多个类,但是只能有一个类能使用public修饰,称之为主类。主类名必须与文件名一致
  • 建议:以后开发中,一个Java文件就编写一个类

5.2 示例:

public class Outer {
    private int outer = 1;

    void testOuter() {
        //外部类访问不到内部的属性与方法
        //System.out.println(inner);//访问不到
    }

    //成员内部类
    public class Inner {
        int inner = 2;

        void testInner() {
            //内部类可以用外部变量与方法
            System.out.println(outer);
            testOuter();
        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        //创建Outer类
        Outer outer = new Outer();
        outer.testOuter();
        //创建内部内对象
        Outer.Inner inner = new Outer().new Inner(); 
    }
}

5.3 匿名内部类

语法:

new 父类/接口(){

​ 重写接口类的方法

}

实例:

USB接口:

//USB接口
public interface USB {
    void trans();
}

测试类:

public class TestUSB {
    public static void main(String[] args) {
        /**
         * 按以前,需要新建一个类实现USB接口,创建子类实现对象
         * 但是如果该接口的方法只需要实现一次,那么这么做就浪费时间
         *
         * 可以使用匿名内部类来简写
         * 匿名内部类语法:
         *      new 接口名(){
         *          重写接口类中方法()
         *      }
         *      相对于: 实现了接口并重写了方法且创建了子类对象
         */
        //匿名内部类
        new USB() {
            @Override
            public void trans() {
                System.out.println("传输");
            }
        }.trans();//传输

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

        USB usb = new USB() {//引入局部变量
            @Override
            public void trans() {
                System.out.println("传输");
            }
        };
        usb.trans();//传输
    }
}

特点:

  • 1.匿名内部类本身就是一个对象
  • 2.一般匿名内部类中都不会定义属性和方法,因为没有意义
  • 3.匿名内部类的父类一般都是抽象类或者是接口

匿名内部类的应用场景

  • 1.如果一个方法的参数是接口,且这个接口只需要实现一次,那么就可以使用匿名内部类

示例:

public static void main(String[] args) {
        /**
         * 按以前,需要新建一个类实现USB接口,创建子类实现对象
         * 但是如果该接口的方法只需要实现一次,那么这么做就浪费时间
         *
         * 可以使用匿名内部类来简写
         * 匿名内部类语法:
         *      new 接口名(){
         *          重写接口类中方法()
         *      }
         *      相对于: 实现了接口并重写了方法且创建了子类对象
         */
        //匿名内部类
        new USB() {
            @Override
            public void trans() {
                System.out.println("传输");
            }
        }.trans();//传输

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

        USB usb = new USB() {//引入局部变量
            @Override
            public void trans() {
                System.out.println("传输");
            }
        };
        usb.trans();//传输

        System.out.println("--------");
    	//调用接口参数方法
        addUSB(new USB() {//lambda表达式
            @Override
            public void trans() {
                System.out.println("chuanshu");
            }
        });
    }

    //方法传入接口参数
    public static void addUSB(USB usb) {
        usb.trans();
    }

}

六、抽象类 && 接口对比

抽象接口
修饰符abstractinterface
是类不是类
属性正常属性全是静态常量
方法可以定义普通方法,抽象方法全部都是抽象方法
构造方法有构造方法没有构造方法
子类继承抽象类,单继承实现接口,多实现
应用多个类有共同特点,行为时。向上抽取形成父类,如果子类都会重写的方法,可以定义为抽象接口一般用来定义功能,行为

-------- | ------------------------------------------------------------ | -------------------------- |
| 修饰符 | abstract | interface |
| 类 | 是类 | 不是类 |
| 属性 | 正常属性 | 全是静态常量 |
| 方法 | 可以定义普通方法,抽象方法 | 全部都是抽象方法 |
| 构造方法 | 有构造方法 | 没有构造方法 |
| 子类 | 继承抽象类,单继承 | 实现接口,多实现 |
| 应用 | 多个类有共同特点,行为时。向上抽取形成父类,如果子类都会重写的方法,可以定义为抽象 | 接口一般用来定义功能,行为 |

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Su sir~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值