03-多态、内部类、匿名内部类、枚举、Object、Objects

1、多态

1.1、概念

  • 一类事物的多种形态
  • H2O
    • 常温:水
    • 低温:冰
    • 高温:水蒸气

1.2、格式

  • 父类引用指向子类对象
  • 父类 变量名 = new 子类();
    • Animal a = new Dog();
    • Animal a = new Cat();
  • 接口 变量名 = new 实现类();

1.3、多态的前提

    1. 有继承或者实现关系
    2. 要有方法重写

1.4、多态的作用

​ 左边写父类或者接口,右边可以是任意子类,提高代码扩展性

eg:Animal a = new Dog();/Animal a = new Cat();

1.5、多态的特点

​ 编译看左边,运行看右边

1.6、多态的弊端

  • 不能使用子类特有方法
  • eg:Animal a = new Dog();
    • // a.lookhome();

1.7、示例代码

public class Demo01 {
    public static void main(String[] args) {
        // 以前我们创建对象: 类名 变量名 = new 类名();
        Cat c = new Cat();
        Dog d = new Dog();
        d.eat();
        // 多态: 父类/接口 变量名 = new 子类/实现类();
        // 多态的好处:右边可以创建任意子类,方便切换,增加了扩展性
        Animal a = new Dog();
        a.eat(); // 多态时执行右边对象的方法
        // a.lookHome(); // 多态:编译看左边,运行看右边
        // 多态真正的好处是在调用方法时使用多态
        goEat(d);
        goEat(c);
    }
    // 定义一个方法,假设这个方法是你同事写好的,你没有资格改
    // 请动物吃饭
    // 方法参数写父类,可以传入任意子类对象
    // goEat(d); Animal d = new Dog();
    // goEat(c); Animal d = new Cat();
    public static void goEat(Animal d) {
        d.eat();
    }
    // 如果方法参数写一个具体子类,那么只能传入这一种类型.需要写多个重载的方法
/* public static void goEat(Dog d) {
        d.eat();
    }
    public static void goEat(Cat d) {
        d.eat();
    }*/
}

1.8、 引用类型转换

1.8.1、 向上转型

​ 将子类转成父类(多态)

eg: Animal a = new Dog();

​ Animal a = new Cat();

1.8.2、向下转型

​ 将父类转成子类 子类 变量名 = (子类) 父类对象;

​ 向下转型的好处:可以调用子类的特有方法

eg:

​ Animal a = new Dog();

​ Dog d = (Dog)a;

​ d.lookHome(); // 调用子类的特有方法

1.8.3、instanceof关键字

  • 格式:变量名 instanceof 类名
  • 作用:判断变量是否是这种类型

1.8.4 示例代码

public class Demo021 {
    public static void main(String[] args) {
        // 向上转型(多态): 将子类转成父类 父类 变量名 = new 子类();
        Animal a = new Dog();
        // Animal a = new Cat();
        a.eat();
        // a.lookHome(); // 不能调用子类特有方法
        boolean b = a instanceof Dog;
        System.out.println("b = " + b);
        // 提高程序的健壮性,让程序不容易崩溃
        if (b) {
            // 将a对象由Animal类型转成Dog类型
            Dog d = (Dog)a; // ClassCastException: 类型转换异常
            d.lookHome(); // 调用子类的特有方法
        } else {
            System.out.println("不是一只狗");
        }
    }
}

2、内部类(了解)

2.1、概念

​ 把一个类定义到另一个类的里面(类种类)

  • eg:
    class Cc { // 外部类(宿主)
    class Dd {
    // 内部类(寄生)
    }
    }

2.2、内部类的分类

  • 按照定义的位置
    • 成员内部类
    • 局部内部类

2.3、什么使用内部类

  • 一个事物内部还有一个事物,内部的事物脱离外部的事物无法独立运行
  • eg:人里面有一颗心脏

2.4、成员内部类

2.4.1、概念

​ 在类中定义且在类中方法外的类

2.4.2、成员内部类的使用

  • 创建外部类对象
  • 通过外部类对象创建内部类都西昂

2.4.3、成员内部类的好处

​ 可以直接使用外部类的成员(成员变量,成员方法)

2.4.4、内部类编译后的结果

  • 内部类名$内部类名.class
    • Body$Heart.class

2.4.5、示例代码

Body类
public class Body {
    public boolean isLive = true; // 是否活着
    public void walk() {
        System.out.println("人在散步");
    }
    // 成员位置: 类中方法外 这里定义一个类(成员内部类)
    class Heart {
        private String color = "红色";
        public void jump() {
            if (isLive) {
                System.out.println("心脏跳动一下!");
            } else {
                System.out.println("心脏停止跳动,凉凉!");
            }
        }
    }
}
测试类
public class Demo05 {
    public static void main(String[] args) {
        // 1.创建外部类对象
        Body body = new Body();
        // 2.通过外部类对象创建内部类对象
        Body.Heart heart = body.new Heart();
        // 有些地方是这么创建内部的 (不建议,没有保存外部类对象)
        // Body.Heart heart2 = new Body().new Heart();
        // 3.调用内部类方法
        heart.jump();
        body.isLive = false;
        heart.jump();
    }
}

2.5、静态成员内部类

2.5.1、概念

​ 在成员内部类的前面添加static修饰

2.5.2、静态成员内部类特点

​ 静态成员内部类只能使用外部类静态修饰的成员

2.5.3、静态成员内部类的创建格式

  • 直接创建静态内部类
  • 外部类名.内部类名 变量名 = new 外部类名.内部类名();
    • eg:Body.Heart heart = new Body.Heart();

2.5.4、示例代码

Body类
public class Body {
    public static boolean isLive = true; // 是否活着
    public void walk() {
        System.out.println("人在散步");
    }
    // 静态成员内部类
    static class Heart {
        private String color = "红色";
        public void jump() {
            if (isLive) {
                System.out.println("心脏跳动一下!");
            } else {
                System.out.println("心脏停止跳动,凉凉!");
            }
        }
    }
}
测试类
public class Demo07 {
    public static void main(String[] args) {
        Body.Heart heart = new Body.Heart();
        heart.jump();
    }
}

2.6 局部内部类

2.6.1、概念

​ 定义在方法中的类

2.6.2、局部内部类的使用

​ 在定义局部内部类的下方创建对象去使用

2.6.3、局部内部类的好处

​ 局部内部类可以直接使用外部类的成员

2.6.4、局部内部类编译后的特点

  • 外部类名$数字内部类名.class
    • Chinese$1Chopsticks.class

2.6.5、示例代码

Chinese类
// 中国人
public class Chinese {
    public String color = "黄";
    public void eat() {
        // 在方法中定义筷子类
        class Chopsticks {
            public int length = 60;
            // 使用筷子
            public void use() {
                System.out.println(color + "颜色的人,使用长度为 " + length + " 的筷子吃饭");
            }
        }
        // 创建局部内部类对象
        Chopsticks chopsticks = new Chopsticks();
        chopsticks.use();
    }
}
测试类
public class Demo08 {
    public static void main(String[] args) {
        Chinese chinese = new Chinese();
        chinese.eat();
    }
}

3、匿名内部类

3.1、概念

​ 匿名内部类就是没有名字的内部类

3.2、格式

​ 父类/接口 对象名 = new 父类/接口(){ 重写方法 }

3.3、匿名内部类的好处

​ 简化代码

3.4、匿名内部类的本质

​ 省去了创建子类或者实现类再调用子类和实现类的重写方法步骤,而是直接创建子类或者实现类然后直接使用括号进行重写

3.5、示例代码

public class Demo09 {
    public static void main(String[] args) {
        // 3.使用实现类
        Student s = new Student();
        s.swimming();
        // 匿名内部类
        // 接口 变量名 = new 接口的实现类();
        Swimmable sw = new Swimmable() {
            @Override
            public void swimming() {
                System.out.println("我是匿名内部类游泳");
            }
        };
        sw.swimming();
    }
}

3.6、匿名内部类的使用场景

  • 方法参数要接口传入匿名内部类,简化代码

  • public class Demo10 {
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(6);
            list.add(8);
            list.add(1);
            list.add(3);
            // 体验匿名内部类简化代码
            // 传入匿名内部类, 使用简单,方便观看
            Collections.sort(list, new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 - o2;
                }
            });
            System.out.println(list);
        }
    }

4、枚举

4.1、不适用枚举存在的问题

​ 不适用枚举,性别可以随便写,造成非法的数据

  • eg:

    • public class Person {
          private String name;
          private String sex; // 男, 女
      }
      Person p = new Person("凤姐", "呵呵");

4.2、概念

  • 一个一个地列举出来。如列举某个类型的所有值

eg:

  • 性别只有男和女
  • 一个星期只有7天
  • 适合类型只有几个固定值的情况

4.3、格式

  • enum 枚举名 {
        成员变量名1, 成员变量名2, 成员变量名3;
    }
  • 枚举中的成员变量名也称为“枚举项”

  • public enum Gender {

    ​ MAN,WOMEN;

    }

4.4、使用方式

  • 枚举名.成员变量名
  • Person person = new Person("凤姐", Gender.MAN);

4.5、使用枚举的好处

​ 将来不能随便写数据,一定是从枚举中选择某一项

4.6、枚举的应用场景

  • 方向
  • 季节
  • 月份
  • 小时

4.7、枚举深入了解

4.7.1、反编译工具介绍

  • xxx.java -> 编译javac -> xxx.class
  • xxx.class -> 反编译工具 -> xxx.java
  • enum是一个关键字,我们看不到它的源码,可以使用反编译工具

4.7.2、季节枚举示例

public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

4.7.3、反编译上一个示例

final class Season1 extends Enum {
    public static final Season SPRING = new Season("SPRING", 0);
    public static final Season SUMMER = new Season("SUMMER", 1);
    public static final Season AUTUMN = new Season("AUTUMN", 2);
    public static final Season WINTER = new Season("WINTER", 3);
    private Season1(String s, int i) {
        super(s, i);
    }
}

5、Object类

5.1、Object类的特点

  • Object类是所有类的父类(祖宗),所有类都直接或间接地继承了Object类

5.2、toString方法

  • Object类中默认的toString方法返回 包名.类名@地址
    • com.itheima.demo15toString方法_重点.Person@4554617c
  • 当我们觉得打印对象的地址没有什么意义的时候,子类可以重写父类的toString方法,打印对象的成员变量
    • 使用快捷键:alt + insert -> toString()

5.3、示例代码

Person类

public class Person {
    private String name;
    private int age;
    // 子类觉得父类方法不能满足要求,子类可以重写父类方法
    public String toString() {
        return "Person{name = " + name + ", age = " + age + "}";
    }}

测试类

Person p1 = new Person("柳岩", 18);
String str = p1.toString(); // com.itheima.demo15toString方法_重点.Person@4554617c
System.out.println(str);
// 打印对象
System.out.println(p1.toString());
System.out.println(p1); // 打印对象,就是调用对象的toString进行打印

5.4、equals方法

  • 回顾 "=="符号

    • 基本数据类型比较数据的值是否相等

      • System.out.println(3 == 5)//falase
    • 引用数据类型比较对象的地址是否相等

      • String str1 = new String("abc");
        String str2 = new String("abc");
        System.out.println(str1 == str2);
  • Object类中的equals默认比较对象的地址

  • 当我们不像比较对象的地址,而是对象的成员变量时

    • 重写equals方法
    • 快捷键:alt + insert - > equals() and hashCode()

5.5、示例代码

Student类

public class Student {
    private String name;
    private int age;
    @Override
    public boolean equals(Object o) {
        // 如果是同一个对象,返回true
        if (this == o) return true;
        // 如果o为null,或者两者类型不同返回false
        if (o == null || getClass() != o.getClass()) return false;
        // 能到下面来说明类型相同,强转
        Student student = (Student) o;
        // 年龄不同返回false
        if (age != student.age) return false;
        // 如果姓名相同返回true,姓名不同返回false
        return name != null ? name.equals(student.name) : student.name == null;
    }

测试类

public class Demo16 {
    public static void main(String[] args) {
        System.out.println(3 == 5); // false
        Student s1 = new Student("小张", 12);
        Student s2 = new Student("老张", 12);
        System.out.println(s1 == s2); // false
        System.out.println(s1.equals(s2));    }
}

6、Objects类

6.1 Objects介绍

  • 是JDK1.7提供的类,其中有很多静态方法帮助我们操作对象
  • 一般来说类名后面带s的都是工具类,里面会提供一些静态方法,帮助我们操作某些对象

6.2 常用方法

  • public static boolean equals(Object a, Object b) // 判断a和b是否相同,本质a.equals(b)
  • public static boolean isNull(Object obj)
    // 判断是否为null,如果为null返回true

6.3、示例代码

public class Demo17 {
    public static void main(String[] args) {
        // Student s1 = new Student("花花", 20);
        Student s1 = null;
        Student s2= new Student("花花", 20);
        // null调用方法会出现空指针异常
        // System.out.println(s1.equals(s2));
        // JDK1.7时增加Objects类,里面有一个equals,帮我们做更严谨的判断
        System.out.println(Objects.equals(s1, s2));
        /*
        Objects类中的
        public static boolean equals(Object a, Object b) {
            // a = s1;
            // b = s2;
            // a != null && a.equals(b): 先判断a!null才去调用a.equals(b)
            return (a == b) || (a != null && a.equals(b));
        }
         */
        // public static boolean isNull(Object obj) 判断是否为null,如果为null返回true
        System.out.println(Objects.isNull(s1)); // true
        System.out.println(Objects.isNull(s2)); // false
    }
}
posted @   OnlyOnYourself-Lzw  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示