03-多态、内部类、匿名内部类、枚举、Object、Objects
1、多态
1.1、概念
- 一类事物的多种形态
- H2O
- 常温:水
- 低温:冰
- 高温:水蒸气
1.2、格式
- 父类引用指向子类对象
- 父类 变量名 = new 子类();
- Animal a = new Dog();
- Animal a = new Cat();
- 接口 变量名 = new 实现类();
1.3、多态的前提
-
- 有继承或者实现关系
- 要有方法重写
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
}
}

浙公网安备 33010602011771号