1、继承 <老子有的儿子也有>
关键字:<extends, implement, this, supper>
一、关键字 <extends,implement>
extends(继承)格 式:权限修饰符 class 子类 extends 父类 {}
- 子类可以使用父类所有的非私有成员
implements(实现)格 式:权限修饰符 class 子类 implements父类1, 父类2, …父类n {}
- 子类在使用前必须实现所实现父类的所有方法。
二、 继承
- Java中只有单继承和多层继承
- Java中的接口可以多继承
- 子类可以直接使用父类的所有非私有成员
- 子类重写了父类方法后,父类方法不再生效
举个栗子
/* 单继承
* 其中【ZiClass】继承了【FuClass】
* 【ZiClass】在使用的过程中,可以使用【FuClass】中的所有非私成员
*/
public class FuClass{void show(){System.out.print("FuClass method.");}}
public class ZiClass extends FuClass{}
public class Test {new ZiClass.show()/*输出: FuClass method. */}
/* 多层继承
* 其中【ZiClass】继承了【FuClass】,【SunClass】继承【ZiClass】
* 【SunClass】在使用的过程中可以使用【FuClass】和【ZiClass】中的所有非私成员
*/
public class FuClass{void show(){System.out.print("ZuFuClass method.");}}
public class ZiClass extends FuClass{}
public class SunClass extends ZiClass{}
public class Test {new SunClass.show()/*输出: ZuFuClass method. */}
/* 多继承 ---- 只能用在接口
* 其中【ZiClass】实现了接口【ZuFuInterface】和接口【FuInterface】
* 【ZiClass】在使用的过程中必须实现接口【ZuFuInterface】和接口【FuInterface】中的所有方法
*/
public interface ZuFuInterface{void fun1();}
public interface FuInterface {void fun2();}
public class ZiClass implements ZuFuInterface, FuInterface {void fun1(){} void fun2(){}}
优点
- 提高代码的复用性和可维护性
- 父类做修改,所有子类都跟着父类修改
- 让类与类直接产生联系,是多态的基础
缺点
1.提高了代码的耦合性
- 在软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则是高内聚低耦合。
- 高耦合:类与类的联系太紧密,一个类的更改会影响到其他多个类。
三、关键字 <this, supper>
this(指向本类)格 式:this.成员
- 当本类中有成员时,this指向本类成员
- 当本类中没有成员时,this指向父类成员
举个栗子
import org.junit.jupiter.api.Test;
class a {
char ch = 'a';
}
class b extends a {
char ch = 'b';
//本类中有成员ch,this指向本类的 ch --> 'b'
public char getCh() {
return this.ch;
}
}
class c extends b {
//本类中没有成员ch,this指向父类的 ch --> 'b'
public char getCh() {
return this.ch;
}
}
class test {
@Test
public void Demo() {
System.out.println(new b().getCh());//输出:b
System.out.println(new c().getCh());//输出:b
}
}
supper(指向父类)格 式:supper.成员
- 在子类中使用父类的成员
举个栗子
import org.junit.jupiter.api.Test;
class a {
char ch = 'a';
}
class b extends a {
char ch = 'b';
//super指向父类,super.ch 指向父类成员变量 ch --> 'a'
public char getCh() {
return super.ch;
}
}
class test {
@Test
public void Demo() {
System.out.println(new b().getCh());//输出:a
}
}
构造方法的的执行流程
- 创建子类时,一定会优先初始化父类,
- 初始化父类时,一定会优先初始化父类的成员变量,然后在执行父类的构造方法。
- 父类初始化完毕之后,才会回头初始化子类。
- 初始化子类,也是优先初始化子类的成员变量,最后再执行子类的构造方法。
举个栗子
import org.junit.jupiter.api.Test;
class Fu {
Other other = new Other();//父类成员变量
public Fu() {
System.out.println("class Fu constructor running.");
}
}
class Zi extends Fu {
Other other = new Other();//子类成员变量
public Zi() {
System.out.println("class Zi constructor running..");
}
}
class Other {
public Other() {
System.out.println("class Other constructor running...");
}
}
class test {
@Test
public void Demo() {
new Zi();
/*
输出:
class Other constructor running... //创建【Zi】时,先初始化其父类;初始化父类时,先初始化父类成员变量,此Other为【FU】的Other对象;
class Fu constructor running. //初始化父类成员变量后,执行【Fu】的构造方法
class Other constructor running... //初始化父类后,初始化【Zi】的成员变量,此Other为【Zi】的Other对象
class Zi constructor running.. //初始化子类成员变量后,执行【Zi】的构造方法
*/
}
}
四、那么什么时候才需要用到继承呢?
- 当我们所编写的代码重复时,就可以进行共性抽取,把重复的代码抽取为一个父类。
输出:
上面的类中,厨师和顾客都有【name属性】和【gender属性】,我们可以将其抽取在一个父类中,使代码得意复用。
举个栗子
输出:
- 从上图我们可以看出,将【Cook类】和【Customer类】中的【name属性】、【gender属性】和他们的 getter/setter 方法抽取到了【Person】类中;
- 然后让【Cook类】和【Customer类】继承【Person类】,其创建对象都拥有父类的所有非私有成员( getter/setter 方法),使重复的代码只书写一遍,提高了代码的复用性。
五、方法重写
@Override(方法重写)格 式:将其写在重写的方法上一行。
@Override
class 方法名(){}
- 子类和父类中,两个完全相同的方法
- 权限修饰符可不同,但子类方法的权限修饰符必须【大于等于】父类方法
- public > protected > default(默认) > private
- 子类方法的返回值类型必须【小于等于】父类方法
- 父类方法没有抛出异常,则子类也不允许抛出异常
- 子类抛出的异常必须【小于等于】父类方法
- 因为父类方法【无法满足】子类的需求,所以子类将父类的方法重写,来满足需求
- 如果父类方法【能满足】子类需求,子类直接调用即可
举个栗子
- 【Customer】类更新了,新的类叫【NewCustomer】,该类继承了【Customer】类。
- 需求:在【eat】方法的基础上,新增一个输出,将顾客的性别输出出来。
public class NewCustomer extends Customer {
public NewCustomer() {
}
@Override
public void eat(){
// System.out.println(getName() + "正在用兰花指干饭。"); //该语句与父类中【eat()】方法重复,可直接调用父类【eat()】方法
super.eat();
System.out.println("该顾客是一位【"+getGender()+"】性。"); //对父类进行升级,满足子类的新需求
}
}
class Test{
@Test
public void Demo01(){
NewCustomer newCustomer = new NewCustomer();
newCustomer.setName("张彪");
newCustomer.setGender("女");
newCustomer.eat();
}
输出:
六、权限修饰符
- 用此表修饰符修饰【方法】效果与修饰【变量】效果相同
★★★★★ | public | protected | default(默认不写) | private |
---|---|---|---|---|
在同一个类下 | √ | √ | √ | √ |
在同一个包中 | √ | √ | √ | × |
不同包子类中 | √ | √ | × | × |
不同包不同类 | √ | × | × | × |
举个栗子
-
同一个类下,所有修饰符修饰的变量皆可访问
-
同一个包中,可以访问被【public】、【default】和【protected】修饰符所修饰的变量。
-
不同包的子类中,可以访问被【public】和【protected】修饰符所修饰的变量。
-
不同包不同类中,可以访问被【public】修饰符所修饰的变量。
- final(最终):可以修饰<修饰符, 方法, 变量>
- 使用【final】修饰 <类> 时,被修饰的类将无法拥有子类,但可以被调用
- 当定义的类不想被别人改动,则可以使用【final】修饰该类
- 使用【final】修饰 <方法> 时,被修饰的方法将无法被重写,但可以被调用
- 当定义的方法不想被别人改动,则可以使用【final】修饰该方法
- 使用【final】修饰 <变量> 时,被修饰的变量将变成常量
- 当修饰的变量为【基本类型】时,其值无法修改
- 当修饰的变量为【引用类型】时,其地址值不可修改
- static(静态)
静态只能访问静态成员
- 被【static】修饰的成员,不再属于对象,而是属于类
- 使用【static】修饰 <变量> 时,该变量对该类的所有对象共享
- 被【static】修饰的成员可以直接通过类名调用 (eg: 类名.静态成员)
- 当某个类的变量需要被【共享】时,则可以使用【static】修饰该变量
- 当某个**<方法>**中,只使用了静态成员,则可以使用【static】修饰该方法
举个栗子
//太多了!举个锤子!
七、代码块
- 局部代码块
- 使用位置: 方法内部一对大括号 “{}”
- 作用: 限制局部变量的生命周期
- 构造代码块
- 使用位置: 类中方法外的一对大括号 “{}”
- 作用: 抽取多个构造方法中的共性内容
- 执行流程: 每次创建对象,自动调用一次
- 静态代码块
//有时间再举