• 11.Java面向对象进阶(3)


    1.多态

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

    多态的常见形式

    父类类型 对象名称 = new 子类构造器;
    接口 对象名称 = new 实现类构造器;
    
    • 1
    • 2
    public abstract class Animal {
    	public String name = "父类";
        public abstract void run();
    }
    public class Cat extends Animal{
    	public String name = "子类猫";
        @Override
        public void run() {
            System.out.println("猫跑路了");
        }
    }
    public class Rabbit extends Animal{
    	public String name = "子类兔子";
        @Override
        public void run() {
            System.out.println("兔子跑路了");
        }
    }
    public class Test {
        public static void main(String[] args) {
            // 1.多态的形式
            Animal a = new Cat();
            a.run();
    		System.out.println(a.name); // 编译看左,运行也看左
            Animal b = new Rabbit();
            b.run();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

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

    优势
    在动态形式下,右边对象可以实现解耦合,便于扩展和维护

    Animal a = new Dog();
    a.run(); // 后续业务行为随对象而变,后续代码无需修改
    
    • 1
    • 2

    定义方法的时候,使用父类类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利

    public class Test {
        public static void main(String[] args) {
            // 1.多态的形式
            Animal a = new Cat();
            Animal b = new Rabbit();
            go(a);
            go(b);
        }
    
        /*
        * 需求,所有动物都可以比赛
        * */
        public static void go(Animal a) {
            System.out.println("-------");
            a.run();
            System.out.println("--------");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    多态下会产生一个问题
    多态下不能使用子类独有功能

    public class Cat extends Animal{
        public String name = "子类猫";
        @Override
        public void run() {
            System.out.println("猫跑路了");
        }
        public void sleep() {
            System.out.println("猫睡觉");
        }
    }
    public class Test {
        public static void main(String[] args) {
            // 1.多态的形式
            Animal a = new Cat();           
           //    a.sleep(); // 多态下不能访问子类独有功能 
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    自动类型转换(从子到父):子类对象赋值给父类类型的变量指向
    强制类型转换(从父到子)
    此时必须进行强制类型转换: 子类 对象变量=(子类)父类类型的变量
    作用:可以解决多态下的劣势,可以实现调用子类独有的功能
    注意:如果转型后的类型和对象真是类型不是同一种类型,那么转换的时候就会出现ClassCastException
    Java建议强制转换前使用instanceof判断当前对象的真是类型,再进行强制转换

    变量名 instanceof 真实类型
    判断关键字左边的变量指向的对象的真是类型,是否是右边的类型或者是其子类类型,是则返回true
    
    • 1
    • 2
    public class Test {
        public static void main(String[] args) {
            // 自动类型转换
            Animal a = new Cat();
            a.run();
    
            // 强制类型转换
            Animal a2 = new Cat();
            a2.run();
    //        Cat r = (Cat) a2; // 从父类类型到子类类型,必须强制类型转换 有继承或者实现关系编译阶段可以强制,运行时可能出错
    //        r.sleep();
            if(a2 instanceof Cat) {
                Cat c = (Cat) a2;
                c.sleep();
            } else if(a2 instanceof Rabbit) {
                Rabbit ra = new Rabbit();
                ra.run();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.多态案例

    需求:使用面向对象编程模拟:设计一个电脑对象,可以安装2个USB设备
    鼠标:被安装时可以完全接入、调用点击功能、拔出功能
    键盘:被安装时可以完成接入、调用打字功能、拔出功能

    public interface USB {
        void connect();
        void unConnect();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class KeyBoard implements USB{
        private String name;
    
        public KeyBoard(String name) {
            this.name = name;
        }
    
        public KeyBoard() {
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void keyUp() {
            System.out.println("键盘被敲击");
        }
        @Override
        public void connect() {
            System.out.println(name+"接入");
        }
    
        @Override
        public void unConnect() {
            System.out.println(name+"拔出");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    public class Mouse implements USB{
        private String name;
    
        public Mouse(String name) {
            this.name = name;
        }
    
        public Mouse() {
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        public void bdClick() {
            System.out.println(name+"双击");
        }
        @Override
        public void connect() {
            System.out.println(name+"接入");
        }
    
        @Override
        public void unConnect() {
            System.out.println(name+"拔出");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    public class Component {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        public void start() {
            System.out.println(name+"开机");
        }
        public void installUSB(USB usb) {
            // 多态  usb可能是鼠标也可能是键盘
            usb.connect();
            if(usb instanceof KeyBoard) {
                KeyBoard k = (KeyBoard) usb;
                k.keyUp();
            }else if(usb instanceof Mouse) {
                Mouse m = (Mouse) usb;
                m.bdClick();
            }
            usb.unConnect();
    
        }
    
        public Component() {
        }
    
        public Component(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    public class Test {
        public static void main(String[] args) {
            Component c = new Component("戴尔");
            c.start();
    
            USB k = new KeyBoard("阿米洛花旦娘");
            c.installUSB(k);
    
            USB m = new Mouse("雷蛇");
            c.installUSB(m);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.内部类

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

    public class People{
    	// 内部类
    	public class Heart {
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    内部类的使用场景、作用
    当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完成结构又只为外部事物提供服务,那么整个内部的完成结构可以选择使用内部类来设计
    内部类通常可以方便访问外部类的成员,包括私有的成员
    内部类提供了更好的封装性,内部类本身就可以用private protected等修饰,封装性可以做更多控制

    内部类的分类
    静态内部类
    成员内部类(非静态内部类)
    局部内部类
    匿名内部类

    静态内部类
    由static修饰,属于外部类本身
    它的特点和使用与普通类是完全一样的,类有的成分他都有

    public class Outer{
    	// 静态成员内部类
    	public static class Inner{
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    静态内部类创建对象的格式
    格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;

    Outer.Inner in = new Outer.Inner();
    
    • 1

    静态内部类中是否可以直接访问外部类的静态成员

    可以,外部类的静态成员只有一份可以被共享访问

    静态内部类中是否可以直接访问外部类的实例成员

    不可以,外部类的实例成员必须用外部类对象访问

    成员内部类
    无static修饰,属于外部类的对象
    JDK16之前,成员内部类中不能定义静态成员,JDK16开始也可以定义静态成员了

    public class Outer {
    	public class Inner{}
    }
    
    • 1
    • 2
    • 3

    成员内部类创建对象的格式
    格式:外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();

    Outer.Inner in = new Outer().new Inner();
    
    • 1

    成员内部类中是否可以直接访问外部类的静态成员

    可以,外部类的惊天成员只有一份可以被共享访问

    成员内部类的实例方法中是否可以直接访问外部类的实例成员

    可以,必须现有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员

    成员内部类案例:
    观察如下代码,写出合适的代码对应其注释要求输出的结果

    class People {
        private int heartbeat = 150;
        public  class Heart {
            private int heartbear = 120;
            public void show() {
                int heartbeat = 70;
                System.out.println(heartbeat); // 70
                System.out.println(this.heartbear); // 120
                System.out.println(People.this.heartbeat); // 150
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    局部内部类(了解)
    局部内部类放在方法、代码块、构造器等执行体中
    局部内部类的类文件名为:外部类$N内部类.class

    public class Test {
        public static void main(String[] args) {
            class Dog {
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    匿名内部类
    本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等
    作用:方便创建子类对象,最终目的是为了简化代码编写
    格式

    new|抽象类|或者接口名() {
    	重写方法
    }
    Employee a = new Employee() {
    	public void work() {}
    }
    a.work();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    public class Test {
        public static void main(String[] args) {
            Animal a = new Animal() {
                @Override
                public void run() {
                    System.out.println("run");
                }
            };
            a.run();
        }
    }
    
    abstract class Animal{
        public abstract void run();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    匿名内部类可以作为方法的实际参数进行传参

    public class Test2 {
        public static void main(String[] args) {
            go(new Swiming() {
                @Override
                public void swim() {
                    System.out.println("学生蛙泳");
                }
            });
        }
        /*
         * 学生、老师、运动员一起参加游泳比赛
         * */
        public static void go(Swiming s) {
            System.out.println("开始");
            s.swim();
            System.out.println("结束");
        }
    }
    interface Swiming {
        void swim();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    阿里、腾讯、京东、拼多多智慧农业斗法
    【虚拟化】KVM
    音视频封装格式
    ABC 327
    堆排序(思路分析) [数据结构][Java]
    Python爬虫爬图片测试1
    CompletableFuture使用详解
    docker更新正在运行中的容器内存
    anaconda打开闪退解决
    GOLANG 原生SQL 为什么 查询不到字段值
  • 原文地址:https://blog.csdn.net/weixin_44978043/article/details/125388000