【JavaSE 第九天】
一、 复习回顾
1. 封装
(1) 封装
含义:
- 将对象功能的实现细节隐藏,对外暴露公共的使用方式
好处: - 安全性提高
- 提高程序的扩展性
- 代码复用性
(2) 程序中的封装体现
private 私有的,只是封装形式的一种体现
- private 修饰符,只能本类访问
- 只能修饰成员,成员方法,成员变量(属性)
- 程序中,成员变量都要使用 private 修饰 (语法规范)
- 提供方法 get(取值) / set (赋值)间接使用成员变量
2. 方法参数
(1) 方法的参数是基本数据类型
- 方法的参数是基本数据类型,byte 、short 、int 、long 、float 、double 、char 、boolean
- 方法参数是基本类型时,传递的是基本类型的具体数值
(2) 方法的参数是引用数据类型
- 方法的参数是引用数据类型,数组
- 引用数据类型中,方法参数传递的是内存中的地址值
二、 继承
1. 程序中的继承
在程序中也能出现继承的关系,让一个类继承另一个类
例如:A 类继承 B 类
- 出现继承的关系
- A 类是 B 类的子类,或者称为派生类
- B 类是 A 类的父类,或者称为 超类 、基类
- 子类可以直接拥有父类的成员(不是全部)
2. 继承的语法格式
继承使用关键字 extends ,用来表示继承的意思
(extend 本身含义是,扩展,延伸)
- 定义格式
class B{}
class A extends B{} // A类继承 B类
父类:
public class Manager {
String name;
int age;
}
子类:
public class Teacher extends Manager{
}
调用:
public static void main(String[] args) {
/**
* 创建对象:Manager的子类对象
*/
Teacher teacher=new Teacher();
// teacher对象,调用成员变量
// teacher子类对象调用继承的成员变量
teacher.name="张三";
teacher.age=52;
System.out.println("teacher.name = " + teacher.name);
System.out.println("teacher.age = " + teacher.age);
}
3. 继承的好处
使用程序中的继承,使用继承的好处:
- 减少代码量
- 复用性提高
- 继承的存在导致了面向对象的最后一个特征:多态
继承的弊端:类和类之间的紧密性(依赖性)更强(扩展性更差)
三、 继承后各成员特点
1. 继承后成员变量的特点
子类和父类的成员变量同名的情况:
- 调用的使用:子类自己有,使用自己的,子类没有,使用父类
父类:
public class Fu {
String s="父类";
}
子类:
public class Zi extends Fu{
String s="子类";
}
调用:
public static void main(String[] args) {
// 创建子类对象
Zi zi=new Zi();
// 子类对象,调用变量
System.out.println("zi.s = " + zi.s);
}
2. super 关键字
super 关键字是超级的意思,在子类中调用父类的成员,使用此关键字
super.变量
调用父类的成员变量super.方法
调用父类的成员方法- this 表示当前调用者对象(不是本类对象)
- super 表示父类在内存中的存储空间(不是父类对象)
- 方法中的局部变量与类中的成员变量同名的情况:
- 在方法内部 用
this.
区分成员变量和局部变量 - 在方法内部 用
super.
调用父类的成员变量
public class Zi extends Fu{
String s="子类";
public void print(){
String s="方法";
System.out.println("s = " + s);
// 在方法内部 用 this. 区分成员变量和局部变量
System.out.println("this.s = " + this.s);
// 在方法内部 用 super. 调用父类的成员变量
System.out.println("super.s = " + super.s);
}
}
3. 内存分析
- 内存空间:
- JDK 1.8 以后叫做 元数据区(Meta Data)
- JDK 1.7 叫做 方法区
4. 继承后成员方法的特点
- 方法重写(override):子类父类中出现了一模一样(方法的声明)的方法,称为子类重写了父类的方法,又称为覆盖或者叫做复写。(与重载不同)
- 重写与重载的区别:
- 重写:
重写(Override)是父类与子类之间多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Override)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。 - 重载:
重载(Overload)是一个类中多态性的一种表现。如果在一个类中定义了多个同名的方法,它们参数列表不同,则称为方法的重载。
区别:重载实现于一个类中、重写实现于子类中。
调用子类重写的方法,假如子类没有重写,调用父类的方法
- 重写:
// 父类
public class Fu {
public void print(){
System.out.println("父类方法print");
}
}
//子类
public class Zi extends Fu {
/**
* 重写父类的方法
*/
public void print(){
System.out.println("子类方法print:重写");
}
}
//调用
public static void main(String[] args) {
//创建子类对象
Zi zi = new Zi();
zi.print();
}
5. 方法重写的意义
继承的本质是扩展、延伸的意思,依靠方法的重写来实现
示例:
早期的(父类):
public class Phone {
/**
* 定义手机的来电显示功能
* 数字移动电话
*/
public void showingCall(){
System.out.println("来电显示号码:");
}
}
之后的(子类):
public class Iphone extends Phone{
/**
* 新手机
* 功能变强,但是原有的功能不变,继续复用
*/
// 重写父类的方法
public void showingCall(){
// 复用显示号码的功能,父类的方法中已经完成
// 方法名不变,用户不需要重新认知
// 调用父类的方法
super.showingCall();
// 新增的功能
System.out.println("显示大头像");
System.out.println("显示归属地");
}
}
调用:
public static void main(String[] args) {
// 创建手机对象
Phone phone=new Phone();
System.out.println("第一个调用");
phone.showingCall();
// 创建新手机对象
Iphone iphone=new Iphone();
System.out.println("第二个调用");
iphone.showingCall();
}
6. 方法重写的问题
- 方法重写需要考虑权限问题:
保证子类的权限要大于或者等于父类的方法权限
Alt + (Fn)+ Insert
快捷键 可以进行重写方法
- 父类的方法权限是 public
父类:
class Fu{
public void print(){}
}
子类:
class Zi extends Fu{
public void print(){} // 正确
protected void print(){} // 错误,权限降低
// 用 javac 编译会出现:“无法重写方法,正在尝试分配更低的访问权限”
void print(){} // 错误,权限降低
private void print(){} // 错误,权限降低
}
- 父类的方法权限是 protected
父类:
class Fu{
protected void print(){}
}
子类:
class Zi extends Fu{
public void print(){} // 正确
protected void print(){} // 正确
void print(){} // 错误,权限降低
private void print(){} // 错误,权限降低
}
- 父类的方法权限是默认(缺省)
父类:
class Fu{
void print(){}
}
子类:
class Zi extends Fu{
public void print(){} //正确
protected void print(){} //正确
void print(){} //正确
private void print(){} //错误,权限降低
}
- 如果父类的方法权限是 private,子类不知道该方法的存在,没有继承的说法。(不存在重写)
这时四个写法都会正确,但并不是方法重写。
7. 继承后构造方法(构造器)特点
- ①构造方法特点 : 子类的构造方法(构造器)中,第一行存在隐式代码(写不写都存在),代码是 super();,作用是调用父类的无参数构造方法(构造器)。
- 并且
super();
与后续的代码不能换位置,必须在构造方法(构造器)的第一行。(实际上 Java 以“分号”区分作为“一行”)
父类:
public class Fu {
public Fu(){
System.out.println("父类构造方法");
}
}
子类:
public class Zi extends Fu{
public Zi(){
super(); // 调用父类的无参数构造方法(绝对性存在)隐式代码
System.out.println("子类构造方法");
}
}
调用:
public static void main(String[] args) {
// 创建子类对象
new Zi();
}
内存分析:
- 补充:实际上 父类也是继承自 Object 类(Java中自己的类)
public class Fu extends Object{
public Fu(){
super();
System.out.println("父类构造方法");
}
}
- ②注意事项:
- 子类的构造方法,无论重载多少个,第一行肯定也是
super();
public class Zi extends Fu {
public Zi(){
super(); // 调用父类的无参数构造方法.
System.out.println("子类构造方法");
}
public Zi(int a){
super(); // 调用父类的无参数构造方法.
System.out.println("子类构造方法:重载");
}
}
- 父类中没有无参数构造方法(自己显式定义了新的构造方法,默认的隐式构造方法(无参的构造方法)消失),子类的构造方法中要用
super(传递参数);
因为父类中没有无参构造方法,所以要传递相应的参数,否则就会报错
父类:
public class Fu {
public Fu(int a){
// 父类的构造方法 加上参数,成为有参数的构造器
System.out.println("父类构造方法" + a);
}
}
子类:
public class Zi extends Fu{
// 子类的无参构造方法
public Zi(){
// 父类中没有无参构造方法,调用有参的构造方法,传递相应的参数
super(1);
System.out.println("子类构造方法");
}
}
- 父类中存在多个构造方法,子类的构造方法只要调用到其中的一个即可(必须调用,至少一个)
父类:
public class Fu {
/**
* 父类的构造方法
* 加上参数,成为有参数的构造方法
*/
public Fu(int a){
System.out.println("父类构造方法" + a);
}
public Fu(String s){
System.out.println("父类构造方法" + s);
}
}
子类:
public class Zi extends Fu {
// 子类的无参构造方法
public Zi(){
//父类中没有无参数构造
//调用其中 int类型参数的传递相应的参数
super(7);
}
// 子类的有参构造方法
public Zi(String s){
//调用父类构造方法,保证至少调用其中一个
super("字符串");
}
}
调用:
public static void main(String[] args) {
// 创建子类对象
// new Zi(); 这是调用的是无参构造方法
new Zi("1"); // 需要调用有参数的那个,保障传递运行
// 保障能够调用运行即可
}
- 解释:
- 调用中的 “1” 传到了子类的有参构造方法中
- 子类把 “字符串” 这一参数传到了父类中的相应的构造方法中
- 输出结果。
四、 继承的特点
1. 单继承
- 一个类只能继承一个类,不允许同时继承多个类
class A extends B,C{} // 不允许的行为,完全错误
- 单继承存在局限性,为了解决局限性问题,引入了接口的概念
2. 多层继承
class A extends B{}
class B extends C{}
// 多层继承,允许实现
// class C extends Object{} 隐含项
- A 类可以同时拥有 B 和 C 的成员, B 只能拥有 C 的成员。
- A 类中 super 调用的是 B 类成员,如果 B 类没有成员,调用 C 成员。
- Object 类是 Java 中自己自带的类,所有的类都是 Object 的子类。
注:这里的“成员"包含成员变量和成员方法。
3. 继承体系
- 学习时:从继承体系的顶部学习(最具共性)
- 使用时:使用时从最底层的部分使用(最具全面性)