本帖最后由 minaduki2333 于 2019-5-7 14:53 编辑
day01-继承&修饰符今日内容1.面向对象三大特征之一: 继承 继承的概念 类与类进行继承的代码格式 继承关系下成员的特点: 成员变量的特点 成员方法的特点, 方法的重写 构造方法的特点 this 和 super 关键字2.抽象类 抽象类的概念 抽象类和抽象方法的代码格式 抽象类和抽象方法的使用注意事项
继承继承的概述知识点: 继承主要解决什么问题什么是"父类"什么是"子类"总结: 继承主要解决的问题: 共性抽取 (避免类中重复代码)父类: 被继承的类, 也叫作基类, 超类(super class). 父类, 爷爷类, 曾爷爷类, 都统称为父类子类: 也叫作派生类, 导出类子类可以拥有父类的内容子类也可以有自己特有的内容动物的继承: 补充: 子类继承父类是 is-a (是一个 / 是一种 / 属于)关系: 兔子 属于 食草动物 狮子 是一个 食肉动物 食肉动物 是一个 动物 助教 是一个 员工 讲师 是一个 员工继承的格式知识点: Java代码中如何让 "类与类" 产生"继承"关系, 格式是什么总结: extends: 继承关键字. 用在类的声明上继承的格式: public class 子类类名 extends 父类类名 { }5分钟练习: 练习继承需求: 定义员工类(Employee): 类中定义方法吃eat(), 内部输出"吃饭"定义老师类(Teacher), 继承员工类.定义助教类(Assistant), 继承员工类.定义测试类(Test), 在 main() 方法中: 创建Teacher类对象, 调用 eat() 吃方法 创建Assistant类对象, 调用 eat() 吃方法代码: public class Employee { // 吃 public void eat() { System.out.println("吃饭"); }}// 老师类, 继承员工public class Teacher extends Employee {}// 助教类, 继承员工类public class Assistant extends Employee {}public class Test { public static void main(String[] args) { // 创建老师对象调用吃 Teacher teacher = new Teacher(); teacher.eat(); // 创建助教对象调用吃 new Assistant().eat(); }}继承中成员变量的访问特点知识点: 在继承关系下, 子类和父类中有"重名的成员变量", 如何访问?"子类对象.成员变量" 直接访问, 使用的是子类还是父类的成员变量"子类对象.成员方法()" 方法内部间接访问成员变量, 使用的是子类的还是父类的总结: 继承关系中, 父子类成员变量"不重名", 正常调用继承关系中, 父子类成员变量"重名", 则: 直接通过子类对象访问成员变量: "等号左边是谁, 就优先用谁, 没有则向上找" (创建对象时, 等号左边是哪个类, 就优先用哪个类的成员变量, 没有则向父类找) 间接通过成员方法访问成员变量: "该方法属于谁, 就优先用谁, 没有则向上找" (方法定义在哪个类, 就优先用哪个类中的成员变量, 没有则向父类中找)5分钟练习: 访问成员变量需求:定义Fu类, 类中定义如下: 成员变量: int num = 100; (不要加private) 成员方法: public void methodFu(), 方法中打印num定义Zi类, 继承Fu类, Zi类中定义如下: 成员变量: int num = 200; (不要加private) 成员方法: public void methodZi(), 方法中打印num定义测试类 创建Fu类对象, 通过Fu类对象调用num和methodFu(), 查看结果 创建Zi类对象, 通过Zi类对象调用num和methodZi(), 查看结果代码: [Java] 纯文本查看 复制代码 public class Fu {
int num = 100;
public void methodFu() {
System.out.println(num);
}
}
public class Zi extends Fu { // 注意!! 要继承!!
int num = 200;
public void methodZi() {
System.out.println(num);
}
}
public class Test {
public static void main(String[] args) {
// 创建Fu类对象, 通过Fu类对象调用num和methodFu(), 查看结果
Fu fu = new Fu();
// 直接访问: 等号左边是谁, 就优先用谁, 没有则向上找
// 等号左边是 Fu 类, 优先用 Fu 中的 num
System.out.println(fu.num); // 100
// 调用方法间接访问: 方法属于谁, 就优先用谁, 没有则向上找
// methodFu 方法属于 Fu 类, 所以优先使用 Fu 类中的num
fu.methodFu(); // 100
// 创建Zi类对象, 通过Zi类对象调用num和methodZi(), 查看结果
Zi zi = new Zi();
// 等号左边是 Zi 类, 优先用 Zi 类中的 num
System.out.println(zi.num); // 200
// methodFu 方法属于 Fu 类, 优先使用 Fu 类中的 num
zi.methodFu(); // 100
// methodZi 方法属于 Zi 类, 优先使用 Zi 类中的 num
zi.methodZi(); // 200
}
} 区分子类方法中重名的三种变量知识点: 如果有"重名"的 "局部变量", "子类成员变量", "父类成员变量", 如何进行访问总结: 变量使用的"就近原则": 如果方法中有局部变量, 则使用局部变量 如果方法中没有局部变量, 有本类的成员变量, 则使用本类的成员变量 如果方法中没有局部变量, 也没有本类的成员变量, 有父类的成员变量, 则使用父类的成员变量 如果局部变量, 本类成员变量, 父类成员变量都没有, 则报错指定访问: 变量名: 局部变量(就近原则) this.成员变量名: 可以访问本类的成员变量 (当本类没有, 也可以访问父类成员变量) super.成员变量名: 可以访问父类的成员变量 this: 当前类对象的引用 super: 当前类对象的父类引用补充: // 说出结果public class Fu { int num = 10; // 父类成员变量}public class Zi extends Fu { //int num = 20; // 子类成员变量 public void method() { //int num = 30; // 局部变量 System.out.println(num); // ? 10 System.out.println(this.num); // ? 10 System.out.println(super.num); // ? 10 }}继承中成员方法的访问特点知识点: 继承关系下, 子类和父类中有"重名的方法", 子类对象调用方法调用的是哪个总结: 父子类中有"重名方法"的访问规则: "创建的对象是谁, 就优先用谁, 没有则向上找" new的对象是哪个类, 就优先使用哪个类中定义的方法, 如果没有定义则向上找 (其实就是方法的重写) (创建的是子类对象, 就优先使用子类中定义的方法)继承中方法的覆盖重写: 概念与特点知识点: 什么是方法的重写, 有哪些要求总结: 方法的重写: Override, 也叫覆盖, 覆写. 在"继承"关系下, 子父类方法"方法名称"和"参数列表"都相同, 这种情况称为方法重写 重写: Override. 继承关系中, 方法名相同, 参数列表也相同重载: Overload. 方法名相同, 参数列表不同补充: 继承中方法的覆盖重写: 注意事项知识点: 子类覆盖重写父类方法时, "返回值类型"有什么要求, "权限修饰符"有什么要求@Override 有什么作用, 写在哪里提前了解: java.lang包中的 Object类 是所有类的父类, 比如 String 就是 Object 的子类 我们可以认为: String比Object小总结: 方法覆盖重写的注意事项: 1. 父子类之间 方法名 和 参数列表 必须都相同 2. 子类方法的 "返回值类型" 必须 "小于等于" 父类方法的返回值类型 3. 子类方法的 "权限修饰符" 必须 "大于等于" 父类方法的权限修饰符 权限修饰符按权限从大到小: public > protected > 默认(default) > private @Override: 写在方法声明的上面, 用来检测是不是正确的覆盖重写 这个注解只是帮助检查. 就算不写, 只要满足重写的要求, 也是正确的方法覆盖重写补充: public class Fu { // 父类 默认权限, 返回值类型 Object Object method() { System.out.println("父类方法执行!"); return new Object(); }}public class Zi extends Fu { // 子类 public比父类权限大, 返回值类型String比Object小 @Override public String method() { System.out.println("子类重写方法执行!"); return "a"; }}继承中方法的覆盖重写: 应用场景知识点: 什么时候使用方法的覆盖重写总结: 方法重写的应用场景: 父类的方法无法满足子类的需求, 子类可以重写 (子类增强父类的方法)继承中构造方法的访问特点知识点: 继承关系中, 子类的构造方法中隐含了什么super(); 用在哪里, 有什么作用总结: 继承关系中, 构造方法的访问特点: 1. 子类构造方法中第一行默认隐含调用 super(); 子类一定会先调用的父类构造, 然后再执行的子类构造 2. 子类构造中, 可以通过 super(参数); 来调用父类任何构造 3. super(); 必须是子类构造方法的第一行语句. 不能多次调用super构造 4. 子类必须调用父类的构造方法, 不写则赠送无参的 super();补充: public class Fu { public Fu() { System.out.println("父类无参构造"); } public Fu(int num) { System.out.println("父类有参构造!"); }}public class Zi extends Fu { public Zi() { super(); // 在调用父类无参构造方法 //super(20); // 在调用父类重载的构造方法 System.out.println("子类构造方法!"); } public void method() {// super(); // 错误写法!只有子类构造方法,才能调用父类构造方法。 }}this和supersuper关键字的三种用法知识点: super 有哪三种用法总结: super关键字的3种用法: 1. 在子类的成员方法中, 访问父类的成员变量: super.age; 2. 在子类的成员方法中, 访问父类的成员方法: super.eat(); 3. 在子类的构造方法中, 访问父类的构造方法: super();补充: // 补全代码public class Fu { int num = 10; public void method() { System.out.println("父类方法"); }}public class Zi extends Fu { int num = 20; public Zi() { // 访问父类无参构造方法 super(); } public void methodZi() { // 打印父类成员变量num System.out.println(super.num); } public void method() { // 访问父类成员方法method super.method(); }}this关键字的三种用法知识点: this 关键字有哪三种用法总结: this关键字的3种用法: 1. 在本类的成员方法中, 访问本类的成员变量: this.age; 2. 在本类的成员方法中, 访问本类的其他成员方法: this.eat(); 3. 在本类的构造方法中, 访问本类的其他构造方法: this(...); 在第三种用法当中要注意: this(...); 调用也必须是构造方法的第一行语句, 也只能有唯一一个 super() 和 this() 两种构造调用, 不能同时使用补充: this.成员变量 / this.成员方法() 如果本类没有该成员变量/成员方法, 也可以调用父类继承过来的成员变量或方法 public Student(String name, int age) { this.name = name; this.age = age; } public StudentLeader(String name, int age) { super(name, age); sout(); ... } public StudentLeader() { this("张三", 30); }// 补全代码public class Zi extends Fu { int num = 20; public Zi() { // 调用本类的构造方法 Zi(int num) ? this(10); } public Zi(int num) { this.num = num; } public void showNum() { // 打印本类中的成员变量 //? System.out.println(this.num); System.out.println(num); } public void methodB() { // 调用本类其他成员方法 showNum() //? this.showNum(); showNum(); }}super与this关键字内存图解知识点: 理解 this 和 super 的调用方式总结: Java继承的三个特点知识点: Java语言中, 继承有什么特点总结: Java中继承的3个特点: 1. Java只支持单继承, 不支持多继承 2. Java支持多层继承 (继承体系) 3. 一个父类可以有多个子类, 一个子类只能有一个直接父类 // 1. Java只支持单继承, 不支持多继承 class C extends A{} //正确 class C extends A,B {} //错误 // 2. Java支持多层继承(继承体系) class Yeye {} class Fu extends Yeye {} class Zi extends Fu {}补充: 抽象类抽象的概念知识点: 什么样的方法属于抽象方法总结: 抽象: 无法具体描述方法体无法确定如何实现, 就应该是一个抽象方法补充: 抽象方法和抽象类的格式知识点: 抽象方法的定义格式什么是抽象类, 抽象类的定义格式总结: 抽象方法: 没有方法体的方法 格式: 修饰符 abstract 返回值类型 方法名(参数列表);抽象类: 包含抽象方法的类就是抽象类 格式: 修饰符 abstract class 类名 { } // 抽象类 public abstract class Animal { // 抽象方法 public abstract void eat(); } public class Cat extends Animal { public void eat() { System.out.println("吃老鼠"); } } new Cat().eat();补充: 抽象方法和抽象类的使用知识点: 抽象类能否创建对象?子类如何重写父类的抽象方法?总结: 如何使用抽象类和抽象方法: 1. 抽象类不能创建对象 2. 必须用一个子类来继承抽象父类 3. 子类必须覆盖重写抽象父类当中所有的抽象方法 覆盖重写要求:去掉 abstract, 补上方法体大括号{} 4. 创建子类对象调用方法day02-多态&抽象类&接口今日内容接口接口: 概述与生活举例知识点: 生活中有哪些接口接口起到什么作用接口:规范接口的实现类: 规范的具体实现总结: 接口的作用: 提供一种公共的规范标准补充: 接口: 定义基本格式知识点: 定义接口的格式是什么JDK 7 中, 接口中可以定义什么JDK 8 中, 接口中新增了什么JDK 9 中, 接口中新增了什么总结: Java中的接口: 多个类的公共规范接口的定义格式: 权限修饰符 interface 接口名 { } // 示例 public interface USB { }接口中包含的成员: JDK7: 1. 常量 (自定义常量) 2. 抽象方法 abstract (); JDK8 新增: 3. 默认方法 default 4. 静态方法 static JDK9 新增: 5. 私有方法 private补充: // JDK9 中定义一个接口public interface USB { // 自定义常量 // 抽象方法 // 默认方法 // 静态方法 // 私有方法}接口: 抽象方法定义知识点: 抽象方法的"修饰符"有什么特殊要求总结: 注意事项: 1. 接口中的抽象方法, 修饰符必须是: public abstract 2. public abstract 可以省略 (省略后也默认是 public abstract) 3. 方法的三要素, 可以随意定义补充: public > protected > 默认 > privatepublic abstract 返回值类型 方法名(参数);接口: 抽象方法使用知识点: 接口能否创建对象一个类"实现"一个接口的格式是什么, 实现用什么关键字一个类实现一个接口后, 该类有哪2种选择总结: 接口的使用: 1. 接口不能创建对象, 要定义实现类来"实现"该接口 (implements) 2. 接口的实现类必须"覆盖重写(实现)"接口中"所有的"抽象方法 3. 创建实现类的对象, 调用重写的方法进行使用一个类实现一个接口后, 该类有哪2种选择: 1. 覆盖重写所有的抽象方法 2. 如果没有覆盖重写所有抽象方法, 则必须将自己定义为抽象类实现类实现接口的格式: public class 实现类名称 implements 接口名称 { // 需要重写父接口的所有抽象方法 }补充: 5分钟练习: 使用接口需求:定义接口USB, 其中包含2个抽象方法: 打开功能: open() 关闭功能: close()定义接口实现类:键盘 Keyboard, 实现USB接口, 实现USB接口规范的功能 打开功能实现方式: 打印"开启键盘" 关闭功能实现方式: 打印"关闭键盘"定义测试类: 创建Keyboard对象, 调用开启和关闭方法代码: public interface USB { // 接口就相当于纸质的规范, 规定USB需要有哪些功能 public abstract void open(); public abstract void close();}public class Keyboard implements USB { // 键盘这个事物按照USB规范实现了USB接口的功能, 就具有了USB接口的行为 @Override public void open() { System.out.println("开启键盘"); } @Override public void close() { System.out.println("关闭键盘"); }}public class Test { public static void main(String[] args) { // USB规范只是纸质文件不能用, 我们真正使用的是键盘这个事物 // 所以需要创建实现类的对象来调用方法 Keyboard keyboard = new Keyboard(); keyboard.open(); keyboard.close(); }} 接口: 默认方法定义知识点: 接口中定义默认方法的格式是什么默认方法用于解决什么问题总结: 默认方法: JDK 8 开始, 接口中允许定义默认方法 默认方法只能定义在接口中默认方法的定义格式: 使用 default 关键字修饰, 有方法体 // 默认方法格式 public default 返回值类型 方法名称(参数列表) { // 方法体 } 默认方法的作用: 解决接口升级的问题补充: 接口: 默认方法使用知识点: 默认方法的"修饰符"有什么特殊要求默认方法的2种使用方式分别是什么总结: 默认方法的 public 可以省略不写 (省略后也默认是public)默认方法的2种使用方式: 1. 通过实现类对象直接调用执行 2. 在实现类中覆盖重写后, 再调用重写的方法补充: 5分钟练习: 练习默认方法需求:定义接口USB, 其中包含1个默认方法: 传输数据功能: transfer(), 方法内部打印"通过USB插口传输数据"定义实现类: U盘 UDisk, 实现USB接口 不用重写默认方法定义实现类: 手机 Phone, 实现USB接口 重写默认的传输方法: 方法内部打印"使用USB线传输数据"定义测试类: 创建U盘对象, 调用传输数据方法 创建手机对象, 调用传输数据方法代码: public interface USB { // USB规范中规定的传输数据的功能, 并提供了具体实现方式 public default void transfer() { System.out.println("通过USB插口传输数据"); }}public class UDisk implements USB { // U盘对于USB规范中规定的传输数据方式认可, 直接继承使用, 不用重写}public class Phone implements USB { // 由于手机不满足于USB规定的默认传输方式, 需要重写默认方法 @Override public void transfer() { System.out.println("使用USB线传输数据"); }}public class Test { public static void main(String[] args) { // 创建U盘对象, 调用传输数据方法 UDisk uDisk = new UDisk(); uDisk.transfer(); // 通过USB插口传输数据 // 创建手机对象, 调用传输数据方法 new Phone().transfer(); // 使用USB线传输数据 }}接口: 静态方法定义知识点: 接口的静态方法, "修饰符"有什么特殊要求总结: 静态方法: JDK 8 开始, 接口当中允许定义静态方法 接口中的静态方法, public 可以省略(省略后也默认是public)补充: 接口: 静态方法使用知识点: 接口中的静态方法, 能否使用 "接口名.静态方法()" 调用能否使用接口实现类对象, 调用接口中的静态方法总结: 接口中静态方法的使用方式: 接口名.静态方法名();实现类对象"不能"调用接口的静态方法 原因: 一个实现类可以同时实现多个接口, 多个接口中可能有相同的静态方法声明, 但方法体却不同, 无法知道调用的是哪个具体的方法补充: 5分钟练习: 测试静态方法需求:定义接口USB, 其中包含1个静态方法: 显示USB规范功能: static void show(), 方法内部打印如下USB设计规范的内容: "USB用于规范电脑与外部设备的连接和通讯, 是应用在PC领域的接口技术"定义测试类: 在测试类中, 直接使用USB接口名调用静态show()方法代码: public interface USB { public static void show() { System.out.println("USB用于规范电脑与外部设备的连接和通讯, 是应用在PC领域的接口技术"); }}public class Test { public static void main(String[] args) { // 接口规范自身具有的行为, 用接口调用静态方法, 和实现类没有任何关系 USB.show(); // USB用于规范电脑与外部设备的连接和通讯, 是应用在PC领域的接口技术 }} 接口: 私有方法定义知识点: 接口中的私有方法可以解决什么问题总结: 私有方法: JDK 9开始, 接口当中允许定义私有方法 可以定义 "静态"私有方法 和 "非静态"私有方法 // 非静态私有方法 private 返回值类型 方法名(参数列表) { // 方法体 } // 静态私有方法 private static 返回值类型 方法名(参数列表) { // 方法体 }私有方法的作用: 解决多个默认方法中代码重复的问题补充: 接口: 私有方法使用总结: 接口中的私有方法只能在接口内部使用 静态私有方法, 解决多个静态方法代码重复的问题 非静态私有方法, 解决多个默认方法代码重复问题接口: 常量定义和使用知识点: 接口中定义的常量, 格式是什么如何使用接口中的常量常量的"修饰符"有什么特殊要求总结: 接口中的常量定义格式: public static final 数据类型 常量名称 = 数据值; // 示例 public interface USB2 { // 常量一旦赋值, 不可以修改 public static final String VERSION = "2.0"; }使用格式: 接口名.常量名 // 示例 System.out.println(USB2.VERSION); // 2.0注意事项: 1. 常量可以省略 public static final (省略后也默认是 public static final) 2. 常量必须进行赋值, 一旦赋值后不能改变 3. 常量的命名规范: 所有字母全都大写, 单词之间用下划线_进行分隔补充: 接口: 内容小结知识点: 总结接口中都有哪些内容, 哪些要求总结: 在Java 9+版本中, 接口的内容可以有: 1. 成员变量 (其实是常量) 格式: [public] [static] [final] 数据类型 常量名 = 数据值; 注意: 常量必须进行赋值, 而且一旦赋值不能改变 常量名称完全大写, 用下划线进行分隔 2. 抽象方法 格式: [public] [abstract] 返回值类型 方法名称(参数列表); 注意: 实现类必须覆盖重写接口所有的抽象方法, 除非实现类是抽象类 3. Java 8 开始, 接口里允许定义默认方法 格式: [public] default 返回值类型 方法名称(参数列表) { 方法体 } 注意:默认方法也可以被覆盖重写 4. Java 8 开始, 接口里允许定义静态方法 格式: [public] static 返回值类型 方法名称(参数列表) { 方法体 } 注意: 应该通过接口名称进行调用, 不能通过实现类对象调用接口静态方法 5. Java 9 开始, 接口里允许定义私有方法 格式: 普通私有方法: private 返回值类型 方法名称(参数列表) { 方法体 } 静态私有方法: private static 返回值类型 方法名称(参数列表) { 方法体 } 注意:private的方法只有接口自己才能调用, 不能被实现类或别人使用补充: 接口: 注意事项和特点知识点: 接口中能否有 "静态代码块" 或 "构造方法"?一个类, 能否同时实现多个接口 (多实现)? 一个类, 能否继承一个父类, 同时实现多个接口?一个类, 同时实现多个接口, 多个接口中有重复的抽象方法, 实现类如何重写?一个类, 同时实现多个接口, 多个接口中有重复的默认方法, 实现类如何重写?一个类, 父类方法和父接口默认方法冲突, 优先用哪个?总结: 注意事项: 1. 接口没有 静态代码块, 构造方法 2. 一个类只能继承一个父类, 但可以同时实现多个接口 public class 实现类类名 extends 父类类名 implements 接口A, 接口B, ... {} 3. 多个接口存在重复的抽象方法, 实现类只需覆盖重写一次 4. 实现类没有覆盖重写所有抽象方法, 那实现类就必须是一个抽象类 5. 多个接口当中存在重复的默认方法, 那么实现类一定要对冲突的默认方法进行覆盖重写 6. 一个类, 父类方法和接口默认方法冲突, 优先用父类当中继承的方法补充: 类和接口之间关系总结知识点: 接口和接口之间能否继承? 单继承还是多继承?多个父接口中, 抽象方法重复了, 子接口如何处理多个父接口中, 默认方法重复了, 子接口如何处理总结: 类, 接口之间的各种关系: 1. 类与类: 单继承, 多级继承 2. 类与接口: 多实现 3. 接口与接口: 多继承 public interface A {} public interface B {} public interface C extends A, B {}注意事项: 1. 多个父接口中, 抽象方法重复, 没关系 2. 多个父接口中, 默认方法重复, 则子接口必须覆盖重写默认方法, 而且要带着 default 关键字补充: // Demo演示// 某些情况下, 多个接口中存在方法名和参数列表一样, 但返回值类型不一致的情况, 子接口无法同时继承, 实现类无法同时实现/*接口多实现的冲突情况 */public class Demo {}interface A { public abstract void method(); // 返回值类型void}interface B { public abstract int method(); // 返回值类型int}// 子接口多继承A和B如何编写?/*interface C extends A, B { // 无法解决: 不要去继承这样的接口}*/// 实现类多实现A和B如何编写?//class D implements A, B { // 无法解决: 不要去实现这样的接口////}什么时候用抽象类? 什么时候用接口 如果一个事物, 可以"概括描述子类", 则适合定义为普通父类或抽象父类 超极本和笔记本, 超极本属于笔记本, 笔记本可以定义为抽象类 如果一个事物, 只是"为子类扩展出某种功能", 则适合定义为接口 超极本和USB, USB只是扩展某种功能, 适合定义为接口, 里面的连接断开方法由超极本自己实现多态多态的概述知识点: 什么是多态多态需要什么前提总结: 多态的前提: 1. 继承或实现 2. 子类重写父类方法 3. 父类引用 指向 子类对象 Person s = new Student();补充: 多态的格式与使用知识点: 如何在代码中实现多态总结: 多态的要点: 父类引用指向子类对象格式: 父类类名 对象名 = new 子类类名(); 父接口名 对象名 = new 实现类类名();补充: public class Fu {}public class Zi extends Fu {}public class Test { public static void main(String[] args) { // 多态: 左侧父类的引用, 指向了右侧子类的对象 Fu obj = new Zi(); }}多态中成员变量的使用特点知识点: 多态中, 子类对象直接访问成员变量, 用的是子类还是父类的多态中, 子类对象间接通过成员方法, 访问成员变量, 用的是子类还是父类的总结: 多态中成员变量的特点: 直接通过对象名称访问成员变量: "看等号左边是谁, 优先用谁, 没有则向上找" 间接通过成员方法访问成员变量: "看该方法属于谁, 优先用谁, 没有则向上找"补充: 多态中成员方法的使用特点知识点: 多态中, 子父类有相同方法, 调用的是谁?总结: 多态中成员方法的特点: "创建的对象是谁, 就优先用谁, 没有则向上找"多态口诀: 成员变量: 编译看左边, 运行看左边 *静态成员方法: 编译看左边, 运行看左边 非静态成员方法: 编译看左边, 运行看右边说明: Fu obj = new Zi(); obj.method(); 编译看是否报错, 运行看执行结果 左边指父类中是否有该成员的定义, 右边指子类中是否有该成员的定义总结一句话: 除了非静态成员方法运行看右边, 其他无论编译或运行都看左边补充: // Demo演示多态调用各种成员的口诀class Fu { int num = 10; public static void staticMethod() { System.out.println("父类静态方法staticMethod"); } public void method() { System.out.println("父类成员方法method"); }}class Zi extends Fu { int num = 20; public static void staticMethod() { System.out.println("子类静态方法staticMethod"); } // 重写父类方法 @Override public void method() { System.out.println("子类重写成员方法method"); } // 子类特有方法 public void methodZi() { System.out.println("子类特有方法methodZi"); }}/*多态调用成员方法 非静态成员方法: 编译看左边, 运行看右边 编译看左边父类中是否定义了该方法 运行按照右边子类中重写的方法执行 */public class Demo { public static void main(String[] args) { // 多态创建对象 Fu obj = new Zi(); // 调用成员变量 // 成员变量: 编译看左边, 运行看左边// System.out.println(obj.num); // 10 // 调用静态方法 // 静态方法: 编译看左边, 运行看左边// obj.staticMethod(); // 父类静态方法staticMethod // 调用成员方法 // 成员方法: 编译看左边, 运行看右边 obj.method(); // 子类重写成员方法method// obj.methodZi(); }}使用多态的好处知识点: 多态有什么用总结: 多态可以简化代码书写补充: // 多态能简化方法的定义// 员工类public abstract class Employee { public abstract void work(); }// 讲师类public class Teacher extends Employee {}// 助教类public class Assistant extends Employee {}// 需求: 定义方法, 让讲师和助教工作// 以前的方式: 定义2个重载方法, 如果员工种类很多, 那需要定义很多重载方法public static void method(Teacher t) { // Teacher t = new Teacher(); t.work();}public static void method(Assistant a) { // Assistant a = new Assistant(); a.work();}method(new Teacher());method(new Assistant());// 多态的方式, 只需要定义一个方法public static void method(Employee e) { // Employee e = new Assistant(); e.work(); }method(new Teacher());method(new Assistant());引用类型转换对象的向上转型知识点: Zi zi = new Zi();Fu zi = new Zi();引用数据类型能否转换转换的规则是什么什么是向上转型, 有什么要求总结: 向上转型: 子类对象 提升为 父类类型 (实现类对象提升为父接口类型) 向上转型一定是安全的 向上转型后, 无法使用子类特有方法 (编译看左边, 父类中没有子类特有方法) // 多态就是向上转型: 猫是一个动物 Animal a = new Cat(); // a.catchMouse(); Cat a = new Cat(); a.catchMouse();补充: 对象的向下转型知识点: 什么是向下转型向下转型的格式是什么向下转型一定能成功吗向下转型的应用场景总结: 向下转型: 父类对象"还原"为子类类型 (父接口对象还原为实现类类型)向下转型格式: (就是强制类型转换的格式) 子类类名 对象名 = (子类类名)父类对象; 实现类类名 对象名 = (实现类类名)父接口对象;注意: 对象本来是什么, 才能向下转型为什么. 如果乱转会抛出类型转换异常 ClassCastException向下转型的应用场景: 调用子类特有方法补充: // 多态向上转型Animal a = new Cat();// 向下还原为CatCat c = (Cat)a;c.猫的特有方法();用instanceof关键字进行类型判断知识点: 能否在向下转型前, 先判断对象是否属于某个子类类型?instanceof 的格式是什么, 结果是什么类型总结: instanceof: 用于判断一个对象属于哪个类, 然后再向下转型, 避免发生类型转换异常使用格式: 对象 instanceof 类名 结果是布尔类型 Animal a = new Cat(); if (a instanceof Dog) { // 强转为Dog Dog d = (Dog)a; d.特有方法(); } 补充: public class Demo02Instanceof { public static void main(String[] args) { Animal animal = new Dog(); // 本来是一只狗 animal.eat(); // 狗吃SHIT // 如果希望调用子类特有方法,需要向下转型 // 判断一下父类引用animal本来是不是Dog if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.watchHouse(); } // 判断一下animal本来是不是Cat if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.catchMouse(); } giveMeAPet(new Dog()); } // 通过多态接收参数 public static void giveMeAPet(Animal animal) { if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.watchHouse(); } if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.catchMouse(); } }}5分钟练习: 多态的转型需求:定义抽象类: 动物 Animal 具有抽象方法: 吃 eat()定义类: 猫 Cat, 继承Animal类 重写抽象方法: eat(), 方法内部打印"猫吃鱼" 在猫类中定义特有方法: 抓老鼠 catchMouse(), 方法内部打印"猫抓老鼠"定义测试类: 使用多态形式, 创建Cat类对象用Animal类型变量接收, 调用吃的方法 向下转型, 调用猫特有方法抓老鼠代码: public abstract class Animal { public abstract void eat();}public class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } // 子类特有方法 public void catchMouse() { System.out.println("猫抓老鼠"); }}public class Test { public static void main(String[] args) { // 多态创建对象 Animal a = new Cat(); // 向上转型 // 调用实现类和父接口共有的方法 a.eat(); // 成员方法: 编译看左边, 运行看右边 // 调用实现类特有的方法, 需要向下转型, 转型之前要判断 if (a instanceof Animal) { // 先还原回Cat Cat cat = (Cat) a; // 然后用子类对象引用调用子类特有方法 cat.catchMouse(); } }}笔记本接口案例笔记本USB接口案例: 分析需求:定义笔记本类,实现笔记本使用USB鼠标、USB键盘所需类和接口: USB 接口, 包含: 开启功能 open() 关闭功能 close() 笔记本Computer类, 包含: 开机功能 powerOn() 关机功能 powerOff() 使用USB设备功能 useDevice(USB usb) 鼠标Mouse类, 实现USB接口: 定义特有方法: 点击 click() 键盘Keyboard类, 实现USB接口: 定义特有方法: 敲击 type() 测试类: 创建笔记本对象, 调用开机方法 使用笔记本对象调用使用USB设备功能的方法, 传入一个鼠标对象, 实现使用鼠标的功能 使用笔记本对象调用使用USB设备功能的方法, 传入一个键盘对象, 实现使用键盘的功能 使用笔记本对象调用关机方法运行效果: 笔记本电脑开机 笔记本对象.powerOn(); 打开鼠标 \ 鼠标点击 -> 笔记本对象.useDevice(鼠标对象); 关闭鼠标 / 打开键盘 \ 键盘输入 -> 笔记本对象.useDevice(键盘对象); 关闭键盘 / 笔记本电脑关机 笔记本对象.powerOff();笔记本USB接口案例: 实现总结: 方法参数为接口类型时, 实际传入的是接口实现类的对象, 利用到多态的原理5分钟练习: 编写笔记本USB接口代码代码: public interface USB { // 开启设备 public abstract void open(); // 关闭设备 public abstract void close();}// 鼠标public class Mouse implements USB { @Override public void open() { System.out.println("开启鼠标"); } @Override public void close() { System.out.println("关闭鼠标"); } // 特有方法 public void click() { System.out.println("鼠标点击"); }}// 键盘public class Keyboard implements USB { @Override public void open() { System.out.println("开启键盘"); } @Override public void close() { System.out.println("关闭键盘"); } // 特有方法 public void type() { System.out.println("键盘输入"); }}// 笔记本public class Computer { public void powerOn() { System.out.println("笔记本电脑开机"); } public void powerOff() { System.out.println("笔记本电脑关机"); } // 笔记本电脑使用USB设备 public void useDevice(USB usb) { // 接口和实现类共有的方法不需要向下转型 // 成员方法: 编译看左边, 运行看右边 usb.open(); // 调用实现类特有方法, 需要向下转型 if (usb instanceof Mouse) { Mouse mouse = (Mouse) usb; mouse.click(); } else if (usb instanceof Keyboard) { Keyboard keyboard = (Keyboard) usb; keyboard.type(); } usb.close(); }}public class Test { public static void main(String[] args) { // 创建笔记本对象 Computer computer = new Computer(); computer.powerOn(); // 笔记本使用鼠标 computer.useDevice(new Mouse()); // 笔记本使用键盘 computer.useDevice(new Keyboard()); computer.powerOff(); }}day11 final, 权限, 内部类今日内容finalfinal关键字概念与四种用法知识点: final 关键字能修饰什么总结: final: 关键字, 最终的, 不可变的意思4种使用方式: 1. 修饰一个类 2. 修饰一个方法 3. 修饰一个局部变量 4. 修饰一个成员变量补充: final关键字用于修饰类知识点: final 修饰类有什么作用总结: final 修饰类的作用: 该类不能被继承 // final类 public final class 类名称 { // ... }补充: final关键字用于修饰成员方法知识点: final 修饰成员方法有什么作用final 和 abstract 能否共用总结: final修饰成员方法的作用: 该方法不能被覆盖重写 // final方法 public final void method() { } final 不能与 abstract 同时使用 final修饰的类不能被继承, 而abstract修饰的类需要被继承 final修饰的方法不能被重写, 而abstract修饰的方法需要被重写补充: final关键字用于修饰局部变量知识点: final 修饰局部变量有什么作用总结: final 修饰局部变量的作用: 自定义常量, 一旦赋值不能修改注意: 对于基本数据类型, 不可变指变量中的"值"不可改变 对于引用数据类型, 不可变指变量中的"地址值"不可改变补充: final int num = 10; // 赋值后不能修改// 分开赋值也可以final int num2;num2 = 20; // 赋值后不能修改final Student stu = new Student("高圆圆");//stu = new Student("赵又廷"); // 错误! 用新地址赋值是不行的stu.setName("高圆圆圆圆"); // 正确! 地址没变, 只是修改对象中的成员变量的值final关键字用于修饰成员变量知识点: final 修饰成员变量有什么作用有什么注意事项总结: final 修饰成员变量的作用: 是自定义常量, 一旦赋值不能修改注意: 1. 成员变量final之后必须手动赋值, 不会再给默认值 2. final的成员变量, 要么直接赋值, 要么通过构造方法赋值. 二者选其一 3. 必须保证类当中所有重载的构造方法, 都最终会对final的成员变量进行赋值补充: public class Person { private final String name /*= "鹿晗"*/; // 声明时直接赋值 public Person() { name = "关晓彤"; // 在构造内部赋值 } public Person(String name) { this.name = name; // 通过参数赋值 }}四种权限修饰符知识点: 权限修饰符有哪4种, 分别限制了在什么范围内能访问总结: 四种权限修饰符 (从大到小): public > protected > (default) > private 注意事项:(default)并不是关键字“default”,而是根本不写。[td]访问范围(以下范围从小到大) | public | protected | 默认 | private | 同一个类 (我自己) | YES | YES | YES | YES | 同一个包 (我邻居) | YES | YES | YES | NO | 不同包子类 (我儿子) | YES | YES | NO | NO | 不同包非子类 (陌生人) | YES | NO | NO | NO |
补充: com.itheima....org.apache.javalib A int a B int b C int c继承 class LoginAction extends Action {}内部类内部类的概念与分类知识点: 什么是内部类内部类定义在哪里内部类有哪几种总结: 内部类: 定义在一个类的内部的类一个事物在另一个事物内部: 汽车 内部有 发动机 人 内部有 心脏内部类的分类: 1. 成员内部类 2. 局部内部类 3. 匿名内部类 (属于局部内部类的一种)补充: 成员内部类的定义知识点: 成员内部类定义在哪里, 格式是什么"内部类"和"外部类"的成员"相互访问的规则"是什么总结: 成员内部类的定义格式: 定义在成员位置 修饰符 class 外部类名称 { 修饰符 class 成员内部类名称 { // ... String name; } // 其他成员如 成员变量, 成员方法, 构造方法... private String name; public Heart getHeart() { return new Heart(); } } Body.Heart heart = new Body().getHeart(); 注意事项: 内部类和外部类的相互访问规则: 内部类中使用外部类成员: "随意访问", 包括外部类私有的 外部类中使用内部类成员: 需要"通过内部类对象" 内部类在编译后, 也会生成独立的字节码文件. 文件名规则: 外部类名$内部类名.class
|
|