目录:
一、 封装
二、 继承
三、 多态
四、 抽象类
一、封装
1. 概述
- 定义:将类的某些信息隐藏在类的内部,不允许外部程序直接访问。只能通过该类提供的 特定的方法 来实现对隐藏信息的操作和访问,也就是:
- 要隐藏对象的信息
- 同时也要留出访问的接口
2. 封装的特点
- 隐藏类的实现细节,实现了信息的隐藏及安全性,方便修改和实现
- 提高了程序的模块化,提高系统独立性和软件的可重用性,且易于维护
- 具体实现是编写该类的人控制的,让使用者只能通过事先定制好的 方法 来访问数据,实现者可以方便地加入控制逻辑,限制对属性的不合理操作
3. 封装的实现
-
变量:使用
private
修饰,这就是变量的封装 - 方法:也是一种封装,封装了多条代码
- 类: 也是一种封装,封装了多个方法
-
封装的实现步骤:
public class Cat {
//成员属性:
//修改属性可见性---private 限定只能在当前类内访问,只能修饰成员变量
private String name;
public Cat() {
}
//创建get/set方法
//在get/set方法当中添加属性的限定
public void setName(String name) { //set方法一般没有返回值
this.name = name;
}
public String getName() {
return "我是一只名叫"+this.name+"的猫咪";
}
public int getMonth() {
return month;
}
public void setMonth(int month) { //对年龄进行限定
if(month<=0)
System.out.println("输入信息错误,宠物猫的年龄必须大于0");
else
this.month = month;
}
}
二、 继承
1. 概述
- 一种类于类之间的关系,使用已存在的类作为基础建立新类。
- 使用已存在的类的定义作为基础创建新类
- 新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但 不能选择性地继承父类,必须继承父类 所有开放的特征
- 使用
extends
关键字实现
2. 继承的逻辑关系
- 不能为了继承某个功能而随意进行继承操作,必须要符合 “A is a B” 关系
3. 继承的特点:
- 子类会自动拥有父类所有 非
private
修饰的属性和方法 - 通过 子类对象 既可以调用自身的 非
private
修饰的成员,也可以调用父类的 非private
修饰的成员 - 父类 不可以 访问子类 特有成员,即使是共有的
- 继承的出现提高了代码的复用性,提高软件开发效率。
- 继承的出现让类与类之间产生了关系,提供了多态的前提
4. 继承的注意事项:
- 在Java中,类只支持单继承,不允许多继承,一个类只能有一个直接父类
- 多个类可以继承一个父类:
class B extends A{}
class C extends A{} // 类B和类C都可以继承类A
- 在Java中,多层继承 是可以的,即一个类的父类可以再去继承另外的父类
class A{}
class B extends A{} // 类B继承类A,类B是类A的子类
class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的子类
- 在Java中,子类和父类是一种相对概念,一个类是某个类父类的同时,也可以是另一个类的子类。
5. 继承后子类父类成员变量的特点
- 子类的对象调用成员变量的时候,子类自己有,使用子类,子类自己没有则调用父类
- 子父类中出现了 同名 的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用
super
关键字
6. 继承后子类父类成员方法的特性
- 子类的对象调用方法的时候,子类自己有,使用子类,子类自己没有调用的父类
- 子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为
override
重写、复写或者覆盖
7. 继承的初始化顺序
- 父类中有:静态代码块,构造代码块,无参构造方法,静态属性。
- 子类中有:静态属性,静态代码块,构造代码块,无参构造方法
- 执行顺序:
- 父类的静态代码块
- 子类的静态代码块
- 父类的构造代码块
- 父类的无参构造方法
- 子类的构造代码块
- 子类的无参构造方法
8. 方法重载和方法覆盖
- 方法重载:
- 同一个类中
- 方法名:重载的两个方法的方法名必须相同
- 参数列表: 不同,三者至少满足一个(参数顺序、个数、类型),三者至少满足一个
- 重载与返回值类型、权限修饰符 无关
- 与方法的参数名 无关
- 方法覆盖
- 有继承关系的 子类 中, **子类覆盖父类的方法 **
- 方法名:子类方法和父类方法 必须相同,
- 参数列表:子类方法和父类方法的形参列表 必须相同
- 访问修饰符:
子类方法的权限 >= 父类的方法的权限
- 返回值类型:
- 基本类数据类型: 必须相同
- 引用数据类型:相同 或者 子类方法的返回值类型是父类方法的返回值类型的 子类
-
注意:
- 当子类重写父类方法后,子类对象调用的是 覆盖后 的方法。
- 属性名也是一样的道理,没有重名之前,调用的是父类的,重名之后用的是子类的
- 被
final
修饰的方法不允许在子类中覆盖 - 父类被覆盖的方法的参数列表中被声明为
final
的参数,在子类的覆盖方法的中可以不必指定为final
- 子类覆盖方法声明的 异常列表中的异常类 必须与父类被覆盖方法声明的异常列表中的异常类 兼容
- 只有在 子类类体中可以访问 的父类或祖先类的方法才能被覆盖
- 静态方法 不能被覆盖,只能被隐藏
- 如果通过子类对象访问父类方法,在 父类类体 中,访问到的任然是子类中的覆盖方法
三、 多态
1. 概述
- 定义:多种形态,是面向对象语言最核心特征,封装和继承都是为多态准备的,非常重要
- Java中多态的 代码体现 在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。
- 最终多态体现为 父类引用变量可以指向子类对象
如 Student 类可以为 Person 类的子类。那么一个S tudent 对象既可以赋值给一个 Student 类型的引用,也可以赋值给一个 Person 类型的引用。
-
多态的分类:
- Java中的多态一般是运行时多态
- 编译时多态:设计时多态,方法重载来实现
- 运行时多态:程序运行时动态决定调用哪个方法
多态的前提:必须有 子父类关系 或者类 实现接口关系,否则无法完成多态。
-
多态的优点:
- 提高代码的可维护行
- 提高代码的扩展性
多态的弊端:不能使用子类的特有功能
如何解决?
法1:创建子类对象调用子类方法
法2:把父类的引用强转为子类引用
2. 多态调用的三种格式
- 父类的引用变量指向子类对象:
父类类型 变量名 = new 子类类型();
- 普通类多态定义的格式:
父类 变量名 = new 子类();
- 抽象类多态定义格式:
抽象类 变量名 = new 抽象类子类();
- 接口多态定义的格式:
接口 变量名 = new 接口实现类();
3. 注意事项:
- 同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个 子类覆盖后的方法
Person p1 = new Student();
Person p2 = new Teacher();
p1.work(); //p1会调用Student类中重写的work方法
p2.work(); //p2会调用Teacher类中重写的work方法
- 当变量名指向不同的子类对象时,由于每个子类覆盖父类方法的内容不同,所以会调用不同的方法。
4. 多态中成员访问的特点
-
成员变量
- 编译看左边(引用变量的声明类型),运行看左边(实际访问到的成员变量的值,也是由引用变量的声明类型来决定)
-
方法
- 编译看左边(引用变量的声明类型),运行看右边(实际访问到的方法,是由引用变量所指向的对象的实际类型来决定)
5. 编译时多态(方法重载 overload)
- 因为对于方法重载而言,虽然多个方法的方法名相同,但是我们的编译器,可以根据方法调用代码推断出,所要调用的那个方法的方法签名,从而根据方法签名(jvm唯一的),确定要调用的方法
** 注:方法签名: 方法名+方法参数列表**
6. 运行时多态
- 因为在编译器编译的时候,无法知道,具体调用的是哪个方法的代码,只有当 jvm 具体真正执行到调用代码的地方,jvm才能知道调用的究竟是哪个方法
- 实现运行时多态:继承、方法覆盖/重写(override)、父类引用指向子类对象
7. 多态的转型
-
向上转型
:当有 子类对象赋值给一个父类引用 时,便是向上转型,多态本身就是向上转型的过程。(也叫:隐式转型、自动转型)- 格式:
父类类型 变量名 = new 子类类型();
- 格式:
-
向下转型
:一个 已经向上转型 的子类对象可以使用 强制类型转换 的格式,将父类引用转为子类引用,这个过程是向下转型。如果是直接创建父类对象,是无法向下转型的!- 格式:
子类类型 变量名 = (子类类型) 父类类型的变量;
- 格式:
什么时候使用向上转型?
当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,这时就可以使用向上转型。
- 什么时候使用向下转型?
当要使用子类特有功能时,就需要使用向下转型。
向下转型的好处:可以使用子类特有功能。
但是弊端是需要面对具体的子类对象;在向下转型时容易发生ClassCastException
类型转换异常。在转换之前必须做 类型判断
如:if( !a instanceof Dog){…}
8. instanceof 关键字
作用: 可以通过
instanceof
关键字来判断是否能够对象转化。也就是,一个引用型的变量,是不是这个类型的对象,提高向下转型的安全性格式:
boolean b = 对象 instanceof 数据类型;
,返回true / false
注意:
null instanceof <类名>
结果永远是false
Person p1 = new Student(); // 前提条件,学生类已经继承了人类
boolean flag = p1 instanceof Student; //flag结果为true
boolean flag2 = p2 instanceof Teacher; //flag结果为false
四、 抽象类
1. 概述
- 在Java中,一个没有方法体的方法应该定义为抽象方法,而如果一个类中含有抽象方法,则该类必须定义为一个抽象类
- 抽象类通常作为一个 框架(虽然在父类抽象类中,有些行为并不能具体确定,但是从类设计的角度将,我们能确定该类存在这样的行为),把子类将实现的抽象方法组织起来,简化或限制子类的设计
2. 抽象类的定义格式
抽象方法定义的格式:
public abstract 返回值类型 方法名(参数);
抽象类定义的格式:
abstract class 类名 {}
3. 抽象类特点
- 抽象类和抽象方法都需要被
abstract
修饰。抽象方法一定要定义在抽象类中。 -
static、final、private
不能与abstract
同时出现。 - 抽象方法 不能有 方法体
- 抽象类 不一定 有抽象方法,但是含有抽象方法的类 必须是 抽象类
- 构造方法,类方法(用
static
修饰的方法),不能声明为抽象方法。 - 抽象类本身不能实例化(但是多态机制可以用子类实例化),不可以直接创建对象
原因:调用抽象方法没有意义
- 只有覆盖了抽象类中 所有的 抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类。
- 抽象类只定义了类的部分行为(包含具体行为), 这些行为是 子类共有的,其它行为由子类实现的抽象方法提供
4. 抽象类成员特点
- 抽象类的 成员变量:既可以变量,又可以是常量
- 抽象类的 构造方法:用于父类数据的初始化
子类继承抽象类时,构造方法不会被覆盖。 而且,在实例化子类对象时首先调用的是抽象类中的构造方法再调用子类中的。
因此,在抽象类中可以使用构造方法封装,所继承子类公共的东西。
- 抽象类的 方法:可以是抽象的,也可以是非抽象的,
-
作用:
- 抽象的:强制子类实现 (语法上的强制约束力)
- 非抽象的:子类可以复用
-
作用:
5.抽象类的子类(二选一)
- 如果不想重写抽象类里面的抽象方法,则子类也必须是抽象类
- 如果不是抽象类,则必须实现抽象父类的所有抽象方法
6. 抽象类的细节
- 抽象类一定是个父类?
严格来说是的,不是父类的话就没有意义了,抽象类的抽象方法必须由子类来实现 本身只起到定义的作用
- 抽象类中是否可以没有抽象方法?如果可以,那么,该类还定义成抽象类有意义吗?为什么?
可以没有抽象方法,有意义,是为了不让该类创建对象,方法可以直接让子类去使用
在实际开发中,有的时候,不希望使用者,直接实例化出一个类的对象,可以将这个类定义为abstract