JaveNote—OOP(2)
Contents
- IDEA快捷键
- Package:包
- 访问修饰符
- OOP三大特性之封装
- OOP三大特性之继承
- OOP三大特性之多态
- super关键字
- Overwrite
- Object类
- 断点调试
IDEA快捷键
删除当前行: CTRL + Y
复制当前行并粘贴: CTRL + D
补全代码行: ALT + /
*导入该行需要的类: ALT + ENTER
快速格式化代码: CTRL + ALT + L
运行: SHIFT + F5
*生成构造器等: CTRL + ALT + INSERT
*查看类的层级关系: CTRL + H
*将光标放在一个方法上,输入 CTRL + B可以定位到具体类。
自动分配变量名\for语句等模板:.var .fori
package
基本介绍
作用:
- 区分相同名字的类
- 当类很多时,可以很好管理类。
- 控制访问范围。
本质:创建不同的文件夹保存类文件。
解释:在com.cagur.a com.cagur.b中都存在Person类,如果在另外一个文件中要使用Person类,就要import 如果带上包名就不用import。但是只能有一个是不带包名的。
包的命名规范
小写字母 + 圆点
一般为com.公司名.项目名.业务模块名
使用细节
- import java.util.Scanner 只引入这一个类
- import java.util.* 表示引入这个包下所有类
- 建议:需要使用哪个类就导入哪个类即可,不要使用*
- package放在类最上面用来打包,一个类最多有一个package,import放package下
访问修饰符
访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|
public | 🆗 | 🆗 | 🆗 | 🆗 |
protected | 🆗 | 🆗 | 🆗 | ❌ |
无修饰 | 🆗 | 🆗 | ❌ | ❌ |
private | 🆗 | ❌ | ❌ | ❌ |
同一个类中,无论什么访问权限都能自由访问。
同一个包中,除了private其它都能访问。
细节
- 修饰符支持修饰类的属性、成员方法和类。
- 类只能用无修饰和public来修饰。
Encapsulation 封装
定义:数据被保护在内部,隐藏实现细节,只有通过调用提供的方法才能访问。
好处:可以对传入的数据进行验证。
步骤
- 将属性设为private
- 提供public的set方法,用于判断并赋值。--加入数据验证的业务逻辑。
- 提供public的get方法,用于获取属性值。--加入权限判断的业务逻辑。
set方法写在构造器中,仍然可以进行验证数据。
Extend 继承
好处:提高了代码复用性、代码扩展性和维护性。
继承的细节
- 继承是全继承。子类继承了父类所有成员,但是private的成员不能直接访问。除非通过父类提供的公共方法访问。
- 子类必须调用父类构造器。子类构造器隐藏了: super(); 即调用默认调用父类的无参构造。
- 如果父类不提供无参构造器,则必须在子类构造器中用super指定父类的哪个构造器完成对父类的初始化工作!
- super必须放在子类构造器的第一行!
- super() 和 this() 都只能放构造器第一行,因此不能共存于同一个构造器。
- Object是所有类的基类。
- 父类构造器的调用不限于直接父类,将一直向上追溯到Object
- 单继承机制:子类最多继承一个父类。
- 不能滥用继承,必须满足 is a 的关系
继承的本质
建立一个查找关系!
方法区的加载顺序:从父到子。
访问子类方法时候的查找顺序:
- 首先看子类是否有该属性。如果有且权限允许,就访问。
- 如果子类没有,就看父类是否有这个属性且权限允许,有就访问。
- 按照2的逻辑一直找到object
- 如果都没有就不行。如果找到其中一步但是访问权限为private,不会继续找,报错。
super关键字
基本介绍
- super代表父类引用,用于访问父类的属性、方法和构造器。
- 基本语法:
- 支持访问父类属性,**无法访问父类的私有属性。**父类方法同理。
- 对于构造器,只能放到子类构造器的第一条语句。
super()
super好处
- 子类中有和父类的成员重名时,为了访问父类成员,比如通过super。
- 以寻找某个方法为例,先找本类,如果有就调用,如果没有就找父类。
- 父类没有继续向上找,直到Object。
- 如果查找过程中,找到了这个方法但是访问修饰符不允许访问某,则报错
- 没有找到会提示方法不存在。
- super访问不限于直接父类,但是遵循就近原则。 继承的本质是建立一种查找关系。
Override重写
- 子类的方法和父类:方法名相同、返回类型相同、参数相同,就说子类覆盖了父类的方法。
- 细节;
- 要求子类方法参数、方法名字和父类完全相同。
- 子类的返回类型,和父类返回类型一致,或者父类返回类型的子类。
- 比如父类返回Object,子类可以返回String。
- 子类不能缩小父类访问权限。
- 重写和重载的比较
- 重写:父子类之间的关系。
- 重载:在本类中,方法名相同,但是参数列表中类型、个数、顺序至少一个不同,同时不要求返回类型相同,没有修饰符的要求。
多态Polymorphic
- 引入多态:凡是Animal就需要用一个Eat方法,但是Animal的种类很多,不可能对Cat、Dog、Monkey都写Eat方法,代码复用性太差。
- 基本介绍:
- 方法多态:
- 重写:不同参数去调用sum方法,体现了sum方法的多种状态。
- 重载:每个对象调用自己的eat方法。
- 多态的核心:类的多态。
- 方法多态:
对象多态
- 多态四要素:
- 一个对象的编译类型和运行类型可以不一致。
- 编译类型在定义对象的时候就确定了,无法改变
- 运行类型是可以变化的
- 在Java中,编译类型看左边,运行类型看右边
Animal animal = new Dog();//父类引用指向子类对象
//左边是引用,表示编译类型是Animal。
//右边表示,运行类型是Dog
animal = new Cat();
//编译类型仍然是Animal,运行类型可以改变成为Cat。
Animal a = new Dog();
a.cry();//dog cry
a = new Cat();
a.cry();
//cat cry
//演示多态参数
public void feed(Animal animal , Food food){
sout(animal.getName() + food.getName());
}
多态细节讨论
- 讨论前提:两个类存在继承关系。
向上转型
- 本质:父类引用指向子类的对象。
- 语法:父类引用名 = new 子类型();
- 例:
Object obj = new Cat()
- 例:
- 特点:编译类型看左边,运行类型看右边。
- 可以调用父类中所有成员,但是需要遵循访问权限。
- 依据:编译阶段能调用哪些成员由编译类型决定
- 不能调用子类中的特定成员。
- 最终运行效果看子类的具体体现。
- 例:假设猫和动物均有eat方法,猫有miao方法,动物有run方法,猫继承动物并进行向上转型。那么,调用eat方法会调用猫的eat,无法调用miao,能调用run
- 可以调用父类中所有成员,但是需要遵循访问权限。
向下转型
- 语法:子类引用 = (子类类型)父类。
Cat cat = (Cat)animal;
- 细节:
- 只能强转父类的引用。
- 要求父类引用必须指向的是当前目标类型的对象。(即animal原来就指向了cat)
- 向下转型后,可以调用子类的所有成员。
Animal animal = new Cat();
//error
cat.catchMouse();
Cat cat = (Cat)animal; //编译类型和运行类型不变
//success
cat.catchMouse();
属性没有重写,属性看编译类型!
instanceOf比较操作符:看的是运行类型
- 用法:判断对象是否还有XX类型,或者XX类型的子类型
class Base{}
class Son extends Base{}
Son son = new Son();
son instanceof Son //true
son instanceof Base // true
Base base = new Son();
base instanceof Base //true 运行类型是Base子类
base instanceof Son //true 运行类型是Son
Object obj = new Object();
obj instanceof Base //false 运行类型是Object,不是Base及其子类
"hello" instanceof Object // true
⭐动态绑定机制
- 当调用对象方法的时候,该方法会与对象的内存地址/运行类型进行绑定。
- 当调用对象属性的时候,没有动态绑定机制。
多态应用
多态参数
- 方法定义的形式参数为父类类型,实参运行传入子类类型。
多态数组
package poly.polyarr;
public class PolyArray {
public static void main(String[] args) {
// TODO: 2023/1/4 多态数组
// 创建2个学生对象,2个老师对象,统一放在数组中
Person[] persons = new Person[5];
persons[0] = new Person("jack",50);
persons[1] = new Student("jack",18,100);
persons[2] = new Student("smith",20,80);
persons[3] = new Teacher("scott",30,20000);
persons[4] = new Teacher("king",25,50000);
//遍历多态数组说say
for(int i = 0;i<persons.length;i++){
System.out.println(persons[i].say()); // 动态绑定
//person[i]的编译类型是Person。运行类型根据实际决定。
//如何调用子类的特殊方法呢?--类型判断结合向下转型
if(persons[i] instanceof Student){
((Student)persons[i]).study(); // 向下转型,将person转换成子类引用
}else if(persons[i] instanceof Teacher){
((Teacher)persons[i]).teach();
}else{
System.out.println("类型有误请检查");
}
}
}
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 AjaxZhan
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果