封装、继承、多态(抽象)
封装
1. 访问控制修饰符 private 和 public
- public:允许成员(属性或方法)被从对象的外部直接访问
- 示例:public String name;
- public String getName() { … }
- private:不允许成员(属性或方法)被从对象的外部直接访问
- 示例:private String name;
- private String getName() { … }
2. 封装
- 将对象的属性或方法使用private修饰,以禁止外部对其直接访问
- 例如:private String name;
- 提供与属性对应的public的get/set方法,使外部通过调用方法来间接访问属性
- 理解:对象就像一台笔记本,从外部来看,除了它用来与外界交互的消息通道之外(键盘,插口,显示器),对象内部就是一个黑匣子,什么也看不到,这称为封装
- 封装的优点:
- 保护数据的完整性
- 提升应用程序的可维护性
package cn.tedu.fengzhuang;
public class FZDemo {
public static void main(String[]args){
//创建对象--具体英雄
Hero h=new Hero();
//给对象属性进行赋值
/*h.name="亚索";
h.level=1;*/
//调用方法来间接给私有化属性进行赋值
h.setBlood(10);
//展示对象属性
//调用方法来间接给私有化属性进行取值
//System.out.println(h.name+","+h.getBlood()+","+h.level);
}
}
//代表英雄的类
class Hero {
//属性
private String name;
private int level;//等级
//private(关键字---私有化)
//私有化信息是不能在外部直接使用的
private int blood;//血量
//快捷键---Alt+InsertGenerator---GetterandSetter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getBlood() {
return blood;
}
public void setBlood(int blood) {
this.blood = blood;
}
//提供间接给私有属性进行赋值
// public void setBlood(int blood){
// if(blood<0){
// System.out.println("亲,您血量给值有问题!!!");
// }else{
// this.blood=blood;
// }
// }
// //提供间接获取私有属性值
//
// public int getBlood(){
// return blood;
// }
/*//有参构造来判断血量是否小于0
public Hero(int blood){
if(blood<0){
System.out.println("亲,您血量给值有问题!!!");
}else{
this.blood=blood;
}
}*/
}
继承
1. 代码重复问题
读懂上图:UML类图
-
UML全称为统一建模语言,是一种用图形符号来表示面向对象元素的图形化语言。
-
每个类用一个方框表示。方框的三个部分:
- 类名框
- 属性框
- 操作(方法)框
-
属性和方法均可用符号表示其访问控制修饰符:
- +:public
- #:protected
- ~或空:default
- -:private
2. 继承
-
继承:从现有类创建子类
- 现有类称为父类、超类或基类
-
子类继承父类的所有成员(构造器除外)
-
Java语言规定,一个类只能继承一个父类,这种限制被称为单继承。
-
练习:
- 编写Computer类,包含CPU、内存(ram)、硬盘(hardDisk)等属性,getDetails方法用于返回Computer的详细信息
- 编写PC子类,继承Computer类,添加特有属性和方法
- 编写NotePad子类,继承Computer类,添加特有属性和方法
- 编写Test类,在main方法中创建PC和NotePad对象,分别访问对象中特有的属性、方法,以及从Computer类继承的属性和方法并打印输出
3. 继承的优点
- 可以创建更为特殊的类型
- 消除重复代码
- 利于可维护性
4. 继承中的私有成员
- 父类中的成员,无论是公有还是私有,均被子类继承
- 子类不能对继承的私有成员直接进行访问,可通过继承的公有方法来访问
- 练习:
- 改写Computer类,将所有属性声明为private,getDetails方法用于返回Computer的详细信息
- 在PC子类中直接访问继承的私有属性,结果如何?
- 在Computer类中对私有属性添加公有的get/set方法,在PC子类中通过这些公有的get/set方法访问私有属性,结果如何?
5. 方法覆盖(重写、英文为override)
- 方法覆盖:子类重写继承来的父类的方法
- 要求方法签名(方法名+参数列表)必须一致
- 子类方法的访问控制修饰符范围必须大于等于父类被覆盖方法
- 被覆盖的父类方法不应是private方法
- 子类重写方法的返回值类型,必须和父类一致,或者是父类方法返回值类型的子类
- 练习:
- 在PC类中,覆盖getDetails方法,方法返回PC机的详细信息。
- 在Test类中调用getDetails方法,确认输出结果。
6. super
- super作为关键字用来调用(本类中)被覆盖的(父类)方法
- super作为方法名—在子类构造方法里调用父类构造,使用时要在首行
- 一般用于在子类带参构造器中调用父类带参构造器,初始化从父类继承来的属性
- 每个子类构造方法里默认含有super无参语句来调用父类无参构造,当父类没有提供无参构造,子类所有的构造方法需要去手动添加super语句去调用父类对应形式的有参构造
- 保证父类对象优先于子类对象先存在(父子类执行顺序—先执行父类构造代码块、父类构造方法、子类构造代码块、子类构造方法)
- 构造器中的super(…)和this(…)
- 任何构造器的第一行,只能是下列语句之一:
- 如果开发者在构造方法中手动添加了
this(...)
语句,那么该构造方法中不再添加super()
语句 - 但是不论怎么写,一个类的构造器,一定会调用父类的构造器
- super(…):可以是隐含super()、显式无参数super()或显式带参数的super(…)。其作用是调用父类相应的构造器。
- this(…):用来调用本类其他重载构造器。
- 如果开发者在构造方法中手动添加了
- 任何构造器的第一行,只能是下列语句之一:
7. Object类
- 所有类的父类:在Java中,如果一个类没有显式声明继承别的类,那么它默认继承Object类
- Object类除构造方法外的成员被所有Java类继承
- Object类中设计了所有Java类都应该具备的属性和方法
访问控制修饰符
- 除了public和private之外,Java还支持以下访问控制修饰符:
- protected:被protected修饰的成员,允许在子类中直接访问
- default:缺省修饰符,即无修饰。无修饰的成员,允许被同包中的其他类或对象所访问
- 通常情况下,不建议使用它们修饰类的成员
- 四种访问控制修饰符比较
- private = 仅能被同类中的成员访问
- default = private + 能被同包的其他类访问
- protected = default + 能被不同包的子类访问
- public = 被任意访问
总结
- 封装
- 使用private修饰类的属性或方法,限制不能从类的外部直接访问这些成员
- 提供public 的 get/set方法,允许从类的外部间接访问这些成员
- 封装的好处
- 保证数据的完整性
- 继承
-
继承:从现有类创建子类
- 现有类称为父类、超类或基类
- 子类继承父类的所有成员(构造器除外)
- Java语言规定,一个类只能继承一个父类,这种限制被称为单继承。
-
继承的好处:
- 减少重复代码
- 提高程序的可维护性
-
- 方法重写(覆盖override)
- 资类重写从父类继承来的方法
- 有什么要求?
- 方法签名(方法名+参数列表)必须一致
- 子类方法的访问控制修饰符要大于等于父类方法的访问控制修饰符
- public > protected > default > private
- 子类方法返回值类型必须和父类一致,或者时父类返回值类型的子类
- @Override注解的作用?验证当前方法是否构成方法重写
- super
- super关键字(super.):调用父类的方法
- super(…):调用父类的构造方法
- 如果一个构造器中,没有this()也没有super(),那么编译器会默认添加一个
super()
- 保证父类先于子类初始化
- 如果父类没有无参构造器,子类构造器中必须显式使用super(…)调用父类的带参构造器
- 如果一个构造器中,没有this()也没有super(),那么编译器会默认添加一个
- Object:所有类的父类
- 访问控制修饰符:
- private:本类内部
- default:同包
- protected:同包或者不同包子类内部
- public:所有