三大特性
- 封装
- 继承
- 多态
三大特性:封装
封装是什么
将成员变量私有化,并且提供对应的公共访问方法
封装的优点
- 提高代码的复用性
- 提高代码的可阅读性
- 隐藏核心实现的逻辑代码,简化外部逻辑,并且阻止来自外部的随意访问
- 实现代码与功能的一对一匹配
封装的实现
核心:
- 成员变量私有化:private
- 提供公共访问方法:getter/setter
注意:只有私有化后的成员变量才能叫做属性
示例:
package day20191103;
public class Demo01 {
private int a;
private int b;
public void Demo01() {
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
实体类的规范
实体类是什么:具有实际意义的类叫做实体类,又叫JavaBean
实体类有什么:
- 属性
- 无参构造器
- getter/setter
JavaBean的规范
- 命名规范:单个单词首字母大写,多个单词的组合遵循驼峰命名法
- 成员变量私有化,提供getter/setter方法
- 提供无参构造器
- 重写equals()和hashCode()
- 重写toString()
注意:业务代码不能写在实体类中
三大特性:继承
继承是什么
子类继承父类,子类拥有父类所有(公开的)成员属性和成员方法(构造器除外),同时子类也可以拥有自己特有的成员属性和成员方法
注意:
- 若子类自己的成员属性与父类同名,则父类的成员属性被覆盖
- 若子类自己的成员方法与父类同名,则发生方法重写
继承的作用
- 提高代码的复用性
- 提取公共特征
- 可以在父类的基础上进行扩展
继承的使用
关键词:extends
示例:
class Animal{
String name;
int age;
public void sleep(){
}
public void eat(){
}
}
class People extends Animal{
String bitthday;
public void study(){
}
}
public static void main(String[] args){
People p = new People();
p.study();
//子类可以拥有父类的成员变量和成员方法
p.sleep();
}
继承的特点
-
继承具有传递性,即子类继承父类的同时,也会继承父类的父类(爷爷-爸爸-儿子)
-
一个父类可以有多个子类(一个爸爸可以有多个儿子)
-
一个子类只能有一个父类(一个儿子只能有一个爸爸)
-
如果一个类没有继承任何类,那么这个类默认继承Object类,所以每个类都有父类(每个儿子必定有一个爸爸)
-
结合第一点和第四点,我们可以得知:所有类都继承了Object类。这个继承可以分为两种:
- 直接继承:子类直接继承Object类
class Son extends Object{ //直接继承 }
- 间接继承:子类的父类(或最高代)继承Object类
class Father{ } class Son extends Father{ //子类继承父类,父类继承Object类 }
子类内存在堆中的表现形式
子类内存在堆中分为两个部分
- 父类对象
- 子类对象
这两个对象在new操作时被创建,对象中有各自成员属性与成员方法。在调用成员属性和成员方法时,遵循就近原则:子类对象中存在同名的属性或方法时,则调用子类中的属性和方法;否则,就调用父类对象中的属性或方法(方法重写的原理)。
内存示意图如下:
子类调用父类成员
关键字:super
super是什么
- 表示父类对象,与this用法类似、意义不同
super的作用
- 调用父类(公开的)构造器:super(参数列表)
- 调用父类(公开的)成员属性:super.属性名()
- 调用父类(公开的)成员方法:super.方法名()
super调用自身构造器的注意点
- 只能放在构造器中
- 必须是第一行代码
注意:
- 每一个类的构造器中都有一个隐含的super(),可以被自定义的**super(参数)**覆盖
- 在子类实例化对象时,一定会在构造自身之前先构造一个父类对象
- 当父类只有有参构造器时,子类构造器将出现错误。因此,为了方便继承,每一个父类都必须添加无参构造器
三大特性:多态
多态
多态的表现形式
- 重载
- 重写
多态的前提条件
- 具有继承关系的父、子类(实现抽象类也算)
方法重载
方法重载的条件
- 同一个类中
- 方法名相同、参数列表不同的方法构成重载
- 参数个数不同
- 参数个数相同,参数类型不同
- 参数个数相同,参数类型相同,相同类型的参数顺序不同
注意1:
- 参数列表的异同判断与参数名称无关
- 方法重载与返回值类型无关
- 方法重载与访问控制符无关
- 调用方法时,根据传入的参数确定调用哪一个重载方法
方法重载的作用
- 提高代码的复用性
- 提高代码的阅读性
- 使代码更加规范
方法重写
方法重写的条件:
- 在子类中(继承/抽象)
- 返回值类型相同或是父类返回值类型的子类,方法名、参数列表必须相同
- 访问控制权限不能比父类窄
方法重写的作用:
- 提高代码的复用性
- 体现不同对象之间的差异性
示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Son son = new Son();
son.method();
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父类方法");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子类方法");
}
}
注意:子类调用方法时,遵循就近原则
向上造型
向上造型是什么:父类类型的引用变量接收子类类型的对象,是多态的体现
- 示例:Father father = new Son();
向上造型中的相关概念
- 编译时类型:编译时,编译器眼中的变量类型(Father father部分)
- 运行时类型:运行时,虚拟机眼中的变量类型(**new Son()**部分 )
编译器认为father的类型是Father,但是在运行时,虚拟机认为father的类型是Son
向上造型中的多态体现
- 编译时类型决定对象能调用哪些方法:通俗地说,father能"."出Father中的所有方法
- 运行时类型决定对象调用的方法内容:如果father调用的方法在Son中被重写,则调用Son中的方法;否则,调用Father中的方法
- 示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Father father = new Son();
father.method();//method()在子类中被重写,所以此时调用的是子类中的方法
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父类方法");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子类方法");
}
}
注意:只有调用被重写的方法才能体现多态,如果调用未被重写的方法,则无法体现多态
向上造型的类型转换
转换的条件
- 必须有直接继承关系
- 运行时类型相同或子类转换成父类
父类不能转换成子类,而子类能转换成父类的原因:子类中除了继承自父类的成员属性和成员方法,还有属于自己的属性和方法。父类转换成子类时,引用变量的编译时类型变成了子类类型,而运行时类型依然是父类类型,由于编译时类型的特性,转换后的引用变量能使用子类特有的属性和方法,但是实际运行时父类中并没有这些属性和方法,于是发生了报错;而子类转换成父类就没有这个问题,因为子类有父类所有(公开的)成员属性和成员方法。
示例:
package day20191029;
public class Demo01 {
public static void main(String[] args) {
Father father1 = new Son();
Son son1 = (Son)father1;
son1.method();
Son son2 = new Son();
Father father2 = (Father)son2;
//编译通过,但是运行后抛出ClassCastException
Father father = new Father();
Son son3 = (Son)father;
son3.method2();
}
}
class Father{
public Father( ) {
}
public void method() {
System.out.println("我是父类方法1");
}
public void method2() {
System.out.println("我是父类方法2");
}
}
class Son extends Father{
public Son() {
}
public void method() {
System.out.println("我是子类方法1");
}
}
注意:强制类型转换属于编译时语法,该语法只在编译时有效,运行时取决于运行时类型。因此才会发生编译通过,但是运行报错。
亲子鉴定
关键字:instanceof
- 作用:判断一个引用变量是否属于某个类型(取决于运行时类型),返回值是布尔类型
- 使用示例:father instanceof Father