[Java笔记11] 面向对象5(多态、内部类、Lambda表达式)

目录

多态

多态的常见形式

多态下引用数据类型的类型转换

内部类

静态内部类

成员内部类

局部内部类

匿名内部类

Lambda表达式

Lambda表达式的简化格式

Lambda表达式的省略写法


视频教程传送门 -> https://www.bilibili.com/video/BV1Cv411372m?p=109

多态

同类型的对象,执行同一个行为,会表现出不同的行为特征。

多态的常见形式

父类类型 对象名称 = new 子类构造器;
接口 对象名称 = new 实现类构造器;

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

多态中成员访问特点:
方法调用 -> 编译看左边,运行看右边。(多态侧重行为多态)
变量调用 -> 编译、运行都看左边。

优势:
在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象。

问题:
多态下不能使用子类的独有功能  => 通过强制类型转换解决

多态下引用数据类型的类型转换

自动类型转换(从子到父):子类对象赋值给父类类型
强制类型转换(从父到子)
此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量

强制类型转换

- 可以转换成真正的子类类型,从而调用子类独有功能
- 有继承关系/实现的2个类型就可以进行强制转换,编译无问题
- 运行时,如果发现强制转换后的类型不是对象真实类型则报错
  类型转换异常:ClassCastException

=> 建议强转转换前使用instanceof判断当前对象的真实类型,再进行强制转换

变量名 instanceof 真实类型
判断关键字左边的变量指向的对象的真实类型,是右边的类型或者是其子类类型返回true

【例】电脑USB接入功能,USB可以是多种设备          

需求:
设计一个电脑对象,可以安装2个USB设备
鼠标 -> 被安装时可以完成接入、调用点击功能、拔出功能
键盘 -> 被安装时可以完成接入、调用打字功能、拔出功能
分析:
定义一个USB的接口(申明USB设备的规范必须是:可以接入和拔出)-> USB.java
提供2个USB实现类代表鼠标(KeyBoard.java)和键盘(Mouse.java),让其实现USB接口,并分别定义独有功能
创建电脑对象(Computer.java),创建2个USB实现类对象,分别安装到电脑中并触发功能的执行

接口 USB.java

package com.itheima.d4_polymorphic_test;

public interface USB {
    void connect();
    void unconnect();
}

实现类 KeyBoard.java

package com.itheima.d4_polymorphic_test;

/**
   实现类(子类)
 */
public class KeyBoard implements USB{
    private String name;

    public KeyBoard(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功接入设备");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功弹出设备");
    }

    /**
      独有功能
     */
    public void keyDown(){
        System.out.println(name + "今天你的鲨鱼干嘛了>OO<");
    }

    public String getName() {
        return name;
    }

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

实现类 Mouse.java

package com.itheima.d4_polymorphic_test;

/**
   实现类(子类)
 */
public class Mouse implements USB{
    private String name;

    public Mouse(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功接入设备");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功弹出设备");
    }

    /**
      独有功能
     */
    public void click(){
        System.out.println(name + "一键三连~~~");
    }

    public String getName() {
        return name;
    }

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

Comupter.java 提供安装USB的入口(定义了一个方法installUSB)

package com.itheima.d4_polymorphic_test;

public class Computer {
    /**
       提供一个安装的入口:行为。
     */
    public void installUSB(USB u){
        u.connect();

        // 独有功能
        if(u instanceof Mouse){
            Mouse m = (Mouse) u;
            m.click();
        }else if(u instanceof KeyBoard) {
            KeyBoard k = (KeyBoard) u;
            k.keyDown();
        }

        u.unconnect();
    }
}

测试类 Test.java

package com.itheima.d4_polymorphic_test;

/**
    USB设备模拟
    1、定义USB接口:接入 拔出
    2、定义2个USB的实现类:鼠标、键盘。
    3、创建一个电脑对象,创建USB设备对象,安装启动。
 */
public class Test {
    public static void main(String[] args) {
        // a、创建电脑对象
        Computer c = new Computer();

        // b、创建USB设备对象
        USB u = new Mouse("罗技鼠标");
        c.installUSB(u);
        System.out.println("----------------");
        USB k = new KeyBoard("CHERRY键盘");
        c.installUSB(k);
    }

}

输出:

内部类

内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。

静态内部类

格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;

特点、使用与普通类是一样的,类有的成分它都有,只是位置在别的类里面。
可以直接访问外部类的静态成员,不能直接访问外部类的实例成员。


成员内部类

格式:外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
例如:Outer.Inner in =  new Outer().new  Inner();

无static修饰,属于外部类的对象。
可以直接访问外部类的静态成员,实例方法中可以直接访问外部类的实例成员。

在成员内部类中访问所在外部类对象 ,格式:外部类名.this

局部内部类

放在方法、代码块、构造器等执行体中。
 

匿名内部类

不用定义实现类,匿名内部类直接构建一个对象代表子类对象

格式:
new 类|抽象类名|或者接口名() {
    重写方法;
};

特点:
匿名内部类是一个没有名字的内部类。
匿名内部类写出来就会产生一个匿名内部类的对象。
匿名内部类的对象类型相当于是当前new的那个的类型的子类类型。

Animal a = new Animal() {
    public void run() {
      System.out.println("鲨鲨游啊游");
    }
};
a. run();

作用:方便创建子类对象,最终目的为了简化代码编写。

推荐阅读:

java中的内部类总结 https://www.cnblogs.com/nerxious/archive/2013/01/24/2875649.html
JAVA匿名内部类 https://www.cnblogs.com/yixianyixian/p/3810118.html
JAVA匿名内部类(Anonymous Classes) https://www.cnblogs.com/wuhenzhidu/p/anonymous.html

Lambda表达式

作用 => 简化匿名内部类的代码写法

Lambda表达式的简化格式

(匿名内部类被重写方法的形参列表) -> {
   被重写方法的方法体代码 
   }

说明:"->" 是语法形式,无实际含义

注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式

函数式接口 => 首先必须是接口、其次接口中有且仅有一个抽象方法

【例】简化匿名内部类

package com.test.d9_lambda;

public class LambdaDemo2 {
    public static void main(String[] args) {
        // 使用Lambda的标准格式简化匿名内部类的代码形式
        // 注意:Lambda只能简化接口中只有一个抽象方法的匿名内部类形式(函数式接口)
//eg1,实现类重写接口方法00
//        Swimming s1 = new Swimming() {
//            @Override
//            public void swim() {
//                System.out.println("老师游泳贼溜~~~~~");
//            }
//        };

//eg1,简化匿名内部类01
//        Swimming s1 = () -> {
//            System.out.println("老师游泳贼溜~~~~~");
//        };

//eg1,大括号内只有一行代码,进一步简化匿名内部类02
        Swimming s1 = () -> System.out.println("老师游泳贼溜~~~~~");
        go(s1);

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

//eg2,go()中直接传入匿名内部类
//        go(new Swimming() {
//            @Override
//            public void swim() {
//                System.out.println("学生游泳很开心~~~");
//            }
//        });

//eg2,简化匿名内部类01
//        go(() ->{
//                System.out.println("学生游泳很开心~~~");
//        });

//eg2,进一步简化匿名内部类02,注意分号
        go(() -> System.out.println("学生游泳很开心~~~"));


    }

    public static void go(Swimming s){
        System.out.println("开始。。。");
        s.swim();
        System.out.println("结束。。。");
    }
}

@FunctionalInterface // 一旦加上这个注解必须是函数式接口,里面只能有一个抽象方法
interface Swimming{
    void swim();
}

输出:

开始。。。
老师游泳贼溜~~~~~
结束。。。
---------------------
开始。。。
学生游泳很开心~~~
结束。。。

Lambda表达式的省略写法

1)参数类型可以省略不写
2)如果只有一个参数,"()"也可以省略
3)如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号
  此时,如果这行代码是return语句,必须省略return不写

package com.test.d9_lambda;

import javax.swing.*;
import java.util.Arrays;

public class LambdaDemo3 {
    public static void main(String[] args) {
        Integer[] ages1 = {34, 12, 42, 23};
//1.匿名内部类,重写比较方法
//        Arrays.sort(ages1, new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return o2 - o1; //  降序
//            }
//        });

//2.Lambda表达式简化
//        Arrays.sort(ages1, (Integer o1, Integer o2) -> {
//                return o2 - o1; //  降序
//        });

//3.进一步简化,参数类型不写
//        Arrays.sort(ages1, ( o1,  o2) -> {
//            return o2 - o1; //  降序
//        });

        //4.再进一步简化,一行代码大括号不写,省略return不写
        Arrays.sort(ages1, ( o1,  o2 ) ->  o2 - o1 );

        System.out.println(Arrays.toString(ages1));

    }
}

输出:[42, 34, 23, 12]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值