目录
10.继承
继承什么,就有什么的特性。是⼀种严格的⽗⼦关系。
如果⼀个类没有明确继承⽗类,那么就表示默认继承 Object 类。
Java是单继承,就是一个类只能继承extends(inherit)一个类,而java这中面向对象的语言就是对现实世界的描述,现实世界中是存在很多多继承,但是java里面是支持实现多个接口。
Object是所有类的父类(这个父类不一定是直接父类)。
●提高代码复用性
将所有子类共有的属性和方法抽取到父类里面,子类继承父类,那么父类里面的属性和方法相当于子类里面也有。
●继承的实现
使⽤ extends 关键字实现,定义语法如下:
class ⼦类 extends ⽗类{ }
// ⼀定要记住,⼦类也被称为派⽣类,⽗类也被成为基类(超类)。
//例子
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
public class Demo {
public static void main(String[] args) {
Student stu=new Student();
stu.setName("张三"); //⽗类定义
stu.setAge(21);//⽗类定义
stu.setSchool("清华⼤学");//子类定义
System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge()+",学校:"+stu.getSchool());
}
}
●继承的优点:
① ⼦类可以直接将⽗类的操作继续使⽤,属于代码重⽤;
② ⼦类可以继续扩充⾃⼰的标准;
● ----Java 不允许多重继承-----但是允许使⽤多层继承----
●多重继承:
Class A{}
Class B{}
Class C extends A,B{}
这种多重的继承在 java ⾥⾯是不被允许使⽤的,只要使⽤就会报错。
●多层继承:
Class A{}
Class B extends A{}
Class C extends B{}
这种多层继承相当于爷孙三代,爷爷 A——爸爸 B——孙⼦ C;虽然这种多层继承在 Java ⾥⾯不限制继承层数,但是为了代码逻辑清晰,在实际开发当中,最好不要超过三层。
● ⼦类在继承⽗类的时候严格来说会继承⽗类中全部操作,但是对于所有的私有操作属于隐式继承,⽽所有的⾮私有操作属于显式继承。
class A{
private String mgs;
public void setMgs(String mgs) {
this.mgs = mgs;
}
public String getMgs() {
return mgs;
}
}
class B extends A {
public void fun() {
System.out.println(msg);
}------------------错误代码
}
public class Demo {
public static void main(String[] args) {
B b=new B();
b.setMgs("hello");
System.out.println(b.getMgs());
}
}
上述代码中虽然然 B 继承 A 的所有操作,但是不能在 B 中直接访问 A 的私有属性,这样也不能否定 B 继承了 A 的所有操作,只不过对于私有属性,属于隐式继承。
●在⼦类对象构造之前⼀定会默认调⽤⽗类的⽆参构造,以保证⽗类的对象,先实例化在实例化⼦类对象。
class A{
public A() {
System.out.println("A 类的⽆参构造");
}
}
class B extends A {
public B() {
System.out.println("B 类的⽆参构造");
}
}
public class Demo {
public static void main(String[] args) {
B b=new B();
}
}
此代码可以发现,当两个类都没有添加任何操作时,在只实例化 B 类对象后,先输出了 A 的⽆参构造语句,⼜输出了 B 的⽆参构造语句,说明在⼦类实例化对象之前,先实例化⽗类的对象,并且调⽤了⽗类的⽆参构造。
那么此时对于⼦类⽽⾔,就相当于隐含了⼀个 super();
class B extends A {
public B() {
super(); //当⽗类有⽆参构造⽅法时,super 可加可不加
System.out.println("B 类的⽆参构造");
}
}
但是,在⽗类中不存在⽆参构造时,必须要加上 super()来明确调⽤⽗类中的有参构造⽅法。
class A{
public A(String title) {
System.out.println("A 类的⽆参构造");
}
}
class B extends A {
public B(String title) {
super(title); //当⽗类有⽆参构造⽅法时,super 可加可不加
System.out.println("B 类的⽆参构造");
}
}
public class JiChengXIngDemo {
public static void main(String[] args) {
B b=new B("hello");
}
}
通过上述代码发现,“super()”主要是由⼦类调⽤⽗类中的构造⽅法时使⽤的,并且要放在⼦类构造⽅法的⾸⾏,这⼀点和“this”关键字类似。
11.重载(Overload)
如果说现在有⼀个⽅法名称,有可能要执⾏多项操作,例如:⼀个 add()⽅法,它可能执⾏两个整数的相加,也可能执⾏ 3 个数相加,也可能 2 个⼩数相加,这样就可以使⽤⽅法重载,⽅法的名称相同,但是⽅法的数据类型不同,参数的类型、顺序和个数不同。
// 例子
public static void main(String[] args) {
System.out.println("两个整数的和:"+add(20,30));
System.out.println("三个整数的和:"+add(20,30,10));
System.out.println("两个⼩数的和:"+add(20.6,30.2));
}
public static int add(int x,int y) {
return x+y;
}
public static int add(int x,int y,int z) {
return x+y+z;
}
public static double add(double x,double y) {
return x+y;
}
//注意:“System.out.println()”所有类型都能输出,说明这个⽅法是被重载之后的⽅法。
构造方法重载(无参构造方法、有参构造方法)
●在同⼀个类⾥⾯,允许存在⼀个以上同名⽅法,只要他们参数类型和参数个数不同即可。方法重载特点:与返回值无关,只看参数列表。
void show(int a, char b, double c){}1、void show(int x, char y, double z){} 不是重载,是同一个方法2、int show(int a, double c, char b){} 是重载,顺序不一样也是重载3、void show(int a, double c, char b){} 是重载4、boolean show(int c, char b){} 是重载5、void show(double c){ } 是重载6、double show(int x, char y, double z){} 不是重载
12.重写/覆写(Override)
●当⼦类定义了与⽗类⽅法名相同、参数类型及个数、返回值相同的⽅法时就称为发⽣了覆写。
class AA{
public void fun() {
System.out.println("输出 A 类中的 fun()⽅法");
}
}
class BB extends AA{
public void fun() {//此处为⽅法覆写
System.out.println("输出 B 类中的 fun()⽅法");
}
}
public class FuXieDemo {
public static void main(String[] args) {
BB b=new BB();
b.fun();
}
}
//当⼦类与⽗类发⽣⽅法覆写,主⽅法⾥⾯实例化⼦类的对象,调⽤的⽅法⼀定是⼦类⾃⼰的⽅法,输出的也⼀定是⾃⼰类中定义的操作;如上述代码,实例化 BB 对象后调⽤的 fun()⼀定输出 BB 中的语句。
● 分析覆写结果要素:
观察实例化是哪个⼦类的;
观察这个实例化对象类的⾥⾯是否已经被覆写过,如果没有被覆写,那么就调⽤⽗类⾥⾯的⽅法。
● 分析什么时候需要覆写(被动原则):
如果发现⽗类中的⽅法名称功能不⾜(不适合本⼦类),但是⼜必须使⽤这个⽅法名称的时候,就需要采⽤覆写这⼀概念的实现。
对于已经实现了覆写功能的⼦类,但是如果想要实现更好的覆写操作功能,那么覆写的⽅法不能拥有⽐⽗类更严格的访问控制权限。
// 对于访问控制权限我们已经学过三个了:public > default >private;也就是说 private 是最为严格的访问权限,即:如果⽗类是⽤ public,那么⼦类覆写必须也得⽤ public;如果⽗类⽤的 default 那么我们⼦类覆写只能使⽤ default 或者 public。99%的覆写权限都⽤ public。
//正确的覆写:
class AA{
public void fun() {
System.out.println("输出 A 类中的 fun()⽅法");
}
}
class BB extends AA{
public void fun() {//此处为⽅法覆写
System.out.println("输出 B 类中的 fun()⽅法");
}
}
//⼦类⽗类同时⽤ public 是最为正确的覆写,没有严格的访问控制权限。
//错误覆写:
class AA{
public void fun() {
System.out.println("输出 A 类中的 fun()⽅法");
}
}
class BB extends AA{
void fun() {//此处为⽅法覆写
System.out.println("输出 B 类中的 fun()⽅法");
}
}
//此时的⼦类使⽤了 default 定义,权限范围相对于⽗类的 public 是在变得更为严格。
●如果⽗类中使⽤了 private 声明,⼦类中使⽤了 public 声明。那么这个是正确的覆写吗?
从概念上来讲是对的,public ⼤于 private 的权限范畴,⽽覆写就是从⽗类⼩权限向⼦类⼤权限覆写。但是:
先分析⼀个正确覆写调⽤:
class AA{
public void fun() {
print();
}
public void print() {
System.out.println("输出 AA");
}
}
class BB extends AA{
public void print() {//此处为⽅法覆写
System.out.println("输出 BB");
}
}
public class FuXieDemo {
public static void main(String[] args) {
BB b=new BB();
b.fun();
}
}
此时结果应该是调⽤ BB 类中的 print()⽅法。
下⾯再分析 private 声明⽗类⽅法:
class AA{
public void fun() {
print();
}
private void print() {
System.out.println("输出 AA");
}
}
class BB extends AA{
public void print() {//此处为⽅法覆写
System.out.println("输出 BB");
}
}
public class FuXieDemo {
public static void main(String[] args) {
BB b=new BB();
b.fun();
}
}
此时结果调⽤的是 AA 类中的 print()⽅法。
这个时候会发现,⼦类中的并没有覆写 print()⽅法,也就是说使⽤了 private 声明⽗类中的⽅法,那么这个⽅法对⼦类⽽⾔是不可⻅的,就算⼦类定义了⼀个与之完全相同的符合于覆写要求的⽅法,那么也不能够发⽣覆写。这个时候就相当于⼦类⾃⼰新创建了⼀个 print()⽅法,这个⽅法与⽗类中的⽅法完全不相同。
●那如果⼜想调⽤⼦类中的覆写⽅法,⼜想调⽤⽗类中的被覆写的⽅法怎么办呢?
class AA{
public void print() {
System.out.println("输出 AA");
}
}
class BB extends AA{
public void print() {//此处为⽅法覆写
super.print();
System.out.println("输出 BB");
}
}
public class FuXieDemo {
public static void main(String[] args) {
BB b=new BB();
b.print();
}
}
观察代码不难发现,在⼦类覆写的⽅法中利⽤关键字“super”调⽤⽗类中的⽅法就可以了。
●⾯试题:请解释重载与覆写的区别??(请解释 Overloading 和 Override 的区别??)在使⽤ Overloading 的时候返回值能否相同?
在发⽣重载关系的时候,返回值可以不同,但是考虑到程序设计的统⼀性,重载时尽量保证⽅法的返回值类型相同。
总结:
① 只要发⽣了继承关系,那么就⼀定会存在覆写的应⽤,覆写的应⽤主要以⽅法的覆写为主。
② 如果现在⼦类要使⽤⽗类指定的⽅法,但是发现⽗类⽅法不能够满⾜⼦类要求的时候,就要使⽤覆写来完善⼦类的功能和保留⽗类的⽅法名称。
③ 被⼦类覆写的⽅法不能拥有⽐⽗类更加严格的访问权限