Day14
1.继承的使用
理解:子类继承父类所有的属性和方法
使用场景:多个类似的类,有相同的属性和方法,就可以把相同属性和方法抽取到父类
优点:减少代码的冗余; 使类与类之间产生了关系(多态的前提)
缺点:继承会增加类与类之间的关系,会增加代码的维护难度
需求:编写中国人和日本人的类,创建各自的对象
分析:
人类:
属性:姓名、性别、年龄
方法:吃饭饭、睡觉觉
中国人的类 继承 人类 :
属性:身份证
方法:打太极
日本人的类 继承 人类:
属性:年号
方法:拍电影
//父类
public class Person {
String name;
char sex;
int age;
public void eat(){
System.out.println(this.name + "吃饭饭");
}
public void sleep(){
System.out.println(this.name + "睡觉觉");
}
}
// 子类 继承 父类
public class Chinese extends Person{
String id;
public void playTaiJi(){
System.out.println("中国人打太极");
}
}
// 子类 继承 父类
public class Japanese extends Person{
String yearNum;
public void playVideo(){
System.out.println("日本人拍电影");
}
}
//测试类
public class Test01 {
public static void main(String[] args) {
//创建对象
Chinese c = new Chinese();
//操作父类属性
c.name = "小彭";
c.sex = '男';
c.age = 21;
//操作子类属性
c.id = "1234567890";
//调用父类方法
c.eat();
c.sleep();
//调用子类方法
c.playTaiJi();
System.out.println("-----------------------------");
//创建对象
Japanese j = new Japanese();
//操作父类属性
j.name = "波多野结衣";
j.sex = '女';
j.age = 18;
//操作子类属性
j.yearNum = "令和";
//调用父类方法
j.eat();
j.sleep();
//调用子类方法
j.playVideo();
}
}
继承内存图:
父类空间优先于子类对象产生
小结
1.继承实际上是子类相同的属性和行为可以定义在父类中,子类特有的属性和行为由自己定义,这样就实现了相同属性和行为的重复利用,从而提高了代码复用。
2.继承是在多个类中之间的,使用关键字extends,在父类的非私有属性和方法可以被子类继承
3.java是单继承的
2.继承的深入
面试题
1.创建子类对象,会调用父类的构造方法吗?
会
2.创建子类对象,为什么会调用父类构造方法?
因为会在子类对象中开辟空间,用于存储父类的成员属性
3.创建子类对象,先调用父类构造方法还是子类构造方法?
先调用子类的构造方法
4.创建子类对象,先完成父类构造方法还是子类构造方法?
先完成父类的构造方法
5.子类对象是否能继承父类所有的属性和方法?
Java官网上,明确表示子类不能继承父类私有化的属性和方法,这是站在使用的角度
实际上,子类能继承父类私有化的属性方法,但是不能直接使用,可以在父类中编写公有方法去调用私有的属性和方法
*值得注意的是子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已,可以通过在父类中设置get/set方法访问父类的private成员变量。*
public class Father {
private String fatherAttr = "父类私有化属性";
public Father() {
System.out.println("调用父类的构造方法");
}
public String getFatherAttr() {
return fatherAttr;
}
public void setFatherAttr(String fatherAttr) {
this.fatherAttr = fatherAttr;
}
private void method01(){
System.out.println("父类私有化方法");
}
public void method02(){
method01();
}
}
public class Son extends Father{
public Son() {
//super();//默认实现:调用父类的构造方法,所以首先完成父类构造方法,再执行下一句
System.out.println("调用子类的构造方法");
}
}
//测试类
public class Test01 {
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.getFatherAttr());
son.method02();
}
}
3.super
理解:super表示父类
super代表的是父类对象的引用,this代表的是当前对象的引用。*
作用:
1.super.属性:在子类中,调用父类的非私有化的成员属性(不常用,因为属性已经私有化了)
2.super.方法:在子类中,调用父类的非私有化的成员方法
3.super():在子类构造方法中的第一句调用父类的非私有化的构造方法
需求:编写中国人和日本人的类,创建各自的对象
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat(){
System.out.println(this.name + "吃饭饭");//name这个属性是本类的,所以使用this,而不是super
}
}
public class Chinese extends Person{
private String id;
public Chinese() {
}
public Chinese(String name,String id) {
super(name);//子类中把父类的成员变量一起有参构造出来,方便使用
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void playTaiJi(){
System.out.println(super.getName() + "打太极");//super.属性:用的是分类的成员变量,子类中没有名字这个属性
}
}
public class Japanese extends Person{
private String yearNum;
public Japanese() {
}
public Japanese(String name,String yearNum) {
super(name);
this.yearNum = yearNum;
}
public String getYearNum() {
return yearNum;
}
public void setYearNum(String yearNum) {
this.yearNum = yearNum;
}
public void playVideo(){
System.out.println(super.getName() + "拍电影");//super.属性:用的是分类的成员变量,子类中没有名字这个属性
}
}
public class Test01 {
public static void main(String[] args) {
//创建对象
Chinese c = new Chinese("小彭", "1234567890");
//调用父类方法
c.eat();
//调用子类方法
c.playTaiJi();
System.out.println("-----------------------------");
//创建对象
Japanese j = new Japanese("波多野结衣", "令和");
//调用父类方法
j.eat();
//调用子类方法
j.playVideo();
}
}
小结 - 编写一个类的步骤:
1.属性
2.私有化属性
3.无参构造
4.有参构造
5.get/set方法
6.其他的方法
3.1 继承后的特点——构造方法
构造方法的名字是与类名一致的。
构造方法的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。(*先有爸爸,才能有儿子*)
*继承后子类构方法器特点:子类所有构造方法的第一行都会默认先调用父类的无参构造方法*****
子类构造方法的第一行都隐含了一个super()调用父类无参数构造方法,super()可以省略不写。
3.2 super和this的用法格式
this.成员变量 – 本类的
this.成员方法名() – 本类的
super.成员变量 – 父类的
super.成员方法名() – 父类的
接下来我们使用调用构造方法格式:
this(…) – 调用本类的其他构造方法,根据参数匹配确认
super(…) – 调用父类的无参构造方法,根据参数匹配确认
注意:
*子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。*
*super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。*
4.重写/复写
理解:在子类中,将父类的方法重新写一遍
子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。*声明不变,重新实现*
应用场景:父类方法不能被改动时,在子类中重新写一遍
条件:
1.在子类中重写父类的方法
2.返回值、方法名、参数列表必须跟父类重写的方法一致
3.访问修饰符不能比父类更严格
面试题:重写(overriding)与重载(overloading)的区别?
重写是发生在子父类继承关系中方法名相同,参数列表相同,返回值相同,子类访问修饰符要大于等于父类的修饰符,子类的异常声明必须小于等于父类的异常声明;
方法重载发生在同一个类中,方法名相同,参数列表不同,返回值无关。
需求:编写中国人和日本人的类,创建各自的对象
public class Test01 {
public static void main(String[] args) {
//创建对象
Chinese c = new Chinese("小彭", "1234567890");
c.eat();//调用子类重写后的方法
System.out.println("-----------------------------");
//创建对象
Japanese j = new Japanese("波多野结衣","令和");
j.eat();//调用子类重写后的方法
}
}
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat(){
System.out.println(this.name + "吃饭饭");
}
}
public class Chinese extends Person{
private String id;
public Chinese() {
}
public Chinese(String name, String id) {
super(name);
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//@Override -- 重写的注解
//注解:给程序员和系统解释代码信息
@Override
public void eat(){
System.out.println(super.getName() + "吃山珍海味");
}
}
public class Japanese extends Person{
private String yearNum;
public Japanese() {
}
public Japanese(String name,String yearNum) {
super(name);
this.yearNum = yearNum;
}
public String getYearNum() {
return yearNum;
}
public void setYearNum(String yearNum) {
this.yearNum = yearNum;
}
@Override
public void eat() {
System.out.println(super.getName() + "吃生鱼片");
}
}
4.1 @Override重写注解
@Override:注解,重写注解校验!
这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。
建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!
4.2 注意事项
1.方法重写是发生在子父类之间的关系。
2.子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
3.子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
4.父类中的方法使用private,static,final任意修饰符,那么,不能被子类重写。
简答题
1.Java 中是否可以重写(override)一个 private 或者是 static 的方法?
1.Java 中 static 方法不能被重写,因为方法重写是基于运行时动态绑定的,而 static 方法是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
2.java 中也不可以重写 private 的方法,因为 private 修饰的变量和方法只能在当前类中使用, 如果是其他的类继承当前类是不能访问到 private变量或方法的,当然也不能重写。
2.构造器不能被继承,因此不能被重写,但可以被重载。
3.重载和重写的区别
1.重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理 。 重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
2.重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要重写父类方法
4.this关键字的用法
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
this的用法在java中大体可以分为3种:
1.普通的直接引用,this相当于是指向当前对象本身。
2.形参与成员名字重名,用this来区分:
public Person(String name,int age){ this.name = name; this.age = age; }
3.引用本类的构造函数
class Person{ private String name; private int age; public Person(){}; public Person(String name){ this.name = name; } public Person(String name,int age){ this(name); this.age = age; } }
5.super关键字的用法
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
super也有三种用法:
1.普通的直接引用:与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。
2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分
3、引用父类构造函数
super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
6.this与super的区别
1.super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
2.super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
super()和this()均需放在构造方法内第一行。尽管可以用this调用一个构造器,但却不能调用两个。
this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
this()和super()都指的是对象,所以,均不可以在static环境中使用。
3.从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
7.继承的好处和坏处
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。 通过使用继承可以提高代码复用性。继承是多态的前提。
好处:
1.子类能自动继承父类的接口
2.创建子类的对象时,无须创建父类的对象
坏处:
1.破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
2.支持扩展,但是往往以增加系统结构的复杂度为代价
3.不支持动态继承。在运行时,子类无法选择不同的父类
4.子类不能改变父类的接口
5.总结
1.继承的使用
2.继承的深入 — 重要
3.super
4.重写