目录
1、封装
好处
- 隐藏实现细节:方法(连接数据库)<--调用(传入参数..)
- 可以对数据进行验证,保证安全合理
2、继承
好处
- 代码的复用性提高了
- 代码的扩展性和维护性提高了
注意事项
- 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
- 子类必须调用父类的构造器, 完成父类的初始化
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器(不管有无参,默认调用的都是父类的无参构造器) ,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译错误
- 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
- super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
- super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器(当有this时,默认的super也没有,默认的super会出现在this方法所代表的构造器内)
- java 所有类都是 Object 类的子类, Object 是所有类的基类.
- 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类),即可能创建一个对象会调用多个构造器
- 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。
- 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
本质分析
Son son = new Son();//内存的布局
//?-> 要按照查找关系来返回信息
//(1) 首先看子类是否有该属性
//(2) 如果子类有这个属性,并且可以访问,则返回信息,
//不可以访问则报错(比如private,即使再往上查找有公有的这个属性)
//(3) 如果子类没有这个属性,就看父类有没有这个属性
//(如果父类有该属性,并且可以访问,就返回信息..)
//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
System.out.println(son.name);//返回就是大头儿子
//System.out.println(son.age);//返回的就是 39
//System.out.println(son.getAge());//返回的就是 39
System.out.println(son.hobby);//返回的就是旅游
若要调用Father和Grandpa类中的name,创建 Father和Grandpa对象
3、super关键字
super 代表父类的引用,用于访问父类的属性、方法、构造器
基本语法
- 访问父类的属性,但不能访问父类的private属性[案例]super.属性名;
- 访问父类的方法,不能访问父类的private方法super.方法名(参数列表);
- 访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句!
好处
- 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
- 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果
- super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则。总的来说就是访问最近的上一级成员
4、方法重写/覆盖(override)
方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
重写和重载的比较
5、多态
引入
基本介绍
- 多态的前提是:两个对象(类)存在继承关系
- 方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
具体体现1(方法的多态,重写和重载就体现多态)
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
编译类型和运行类型
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以变化的
- 编译类型看定义时=号的左边,运行类型看=号的右边
//animal编译类型是Animal,运行类型Dog
Animal animal = new Dog0;
//animal的运行类型变成了Cat,编译类型仍然是 Animal
animal = new Cat();
具体体现2(对象的多态,上下转型)
多态向上转型
- 本质:父类的引用指向了子类的对象(把子类赋给了父类),这里父类包括父类的父类及更高
- 语法:父类类型 引用名=new 子类类型()
- 特点:编译类型看左边,运行类型看右边。
- 可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员
- 最终运行效果看子类的具体实现!
//向上转型: 父类的引用指向了子类的对象
//语法:父类类型引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
//(1)可以调用父类中的所有成员(需遵守访问权限)
//(2)但是不能调用子类的特有的成员
//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse();Cat的特有方法,会报错
//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
//,然后调用,规则和方法调用规则一致。
animal.eat();//猫吃鱼,Cat类重写的方法
animal.run();//跑,父类的方法
animal.show();//hello,父类的方法
animal.sleep();//睡,父类的方法
多态向下转型
- 语法:子类类型 引用名=(子类类型)父类引用
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须指向的是当前目标类型的对象
- 当向下转型后,可以调用子类类型中所有的成员
//多态的向下转型
//(1)语法:子类类型 引用名 =(子类类型)父类引用;
//编译类型 Cat,运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
//即原来的anminal指向Cat类型
Dog dog = (Dog) animal; //不可以
属性的值看编译类型
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);// ? 看编译类型 10
Sub sub = new Sub();
System.out.println(sub.count);//? 20
}
}
class Base { //父类
int count = 10;//属性
}
class Sub extends Base {//子类
int count = 20;//属性
}
instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
class BB extends AA {}//子