java中的继承(extends)详解
继承(extends)
1. ⽗类与⼦类
⽗类也叫基类、超类
⼦类也叫派⽣类
在继承的⽽关系中,“⼦类就是⼀个⽗类“。也就是说,⼦类可以被当做⽗类来看待。例如⽗类是员⼯,⼦类是⽼师,那么我们可以说**”⽼师就是⼀个员⼯“**。
2. 继承的格式
2.1 定义⽗类的格式:(⼀个普通的类定义)
public class⽗类名称{
//.....
}
2.2 定义⼦类的格式
public class⼦类名称extends⽗类名称{
//.....
}
2.3 代码演⽰(⽼师类继承员⼯类)
2.3.1 Employee类
public class Employee(){
public void method(){
System.out.println("⽅法执⾏")
}
}
2.3.2 Teacher类,继承⾃Employee类
public class Teacher extends Employee{
//我们先不在⾥⾯添加任何东西
}
2.3.3 在main中,创建⼀个Teacher类的对象
public class Main {
public static void main(String[] args){
Teacher one =new Teacher();
java重写和重载的区别//Teacher类继承了Empolyee类的⽅法
}
}
/*输出结果:
执⾏⽅法
*/
2.3.4 ⼩结论
Teacher类继承了Employee类,也就继承了它的 public void method() ⽅法,达到了代码复⽤的效果,当⽗类有我们⼦类需要⽤的⽅法时,我们就不⽤再去重新打⼀次,直接可以拿来⽤。
3. 继承中成员变量的访问特点
3.1 成员变量之间的访问 (变量不重名的情况)
3.1.1 先创⽴⼀个⽗类Fu
public class Fu {
public int numFu =10;//关键字为public,可以直接通过(对象.变量名)访问,⽅便说明问题
}
3.1.2 再创⽴⼀个⼦类Zi
public class Zi extends Fu{
public int numZi =20;
}
3.1.3 在main中分别建⽴⽗类和⼦类的对象
public class Demo02ExtendsField {
public static void main(String[] args){
//创建⽗类对象
Fu fu =new Fu();
//⽗类只能到⾃⼰的成员numFu,并没有到⼦类的成员numZi
System.out.println(fu.numFu);
//创⽴⼀个⼦类对象
Zi zi =new Zi();
//⼦类对象既可以打印⽗类的成员numFu,也可以打印⾃⼰的成员numZi
//还是那句"先⼈不知道后⼈的事情,⽽后⼈知道先⼈的事情"
System.out.println(zi.numFu);
System.out.println(zi.numZi);
}
}
3.2 成员变量之间的访问 (变量重名的情况)
有两种情况:
1. 直接通过对象访问成员变量:
等号左边是谁,就优先⽤谁,没有则向上
2. 间接通过成员⽅法访问成员变量
该⽅法属于谁,就优先⽤谁,没有则向上
假设现在⽗类 Fu 和⼦类 Zi 都有⼀个变量名叫num
Fu 类
public class Fu {
public int num =10;
public void methodFu(){
//这⾥打印的num,⼀定是本类的,不会再往下⼦类的
System.out.println(num);
}
}
Zi类
public class Zi extends Fu{
public int num =20;
public void methodZi(){
//这⾥打印的num,如果本类有,就优先打印本类的,如果没有再往上        System.out.println(num);
}
}
第⼀种情况:直接通过对象访问成员变量
等号左边是谁,就优先⽤谁,没有则向上。Fu fu = new Zi();等号的左边是⽗类
public class Demo02ExtendsField {
public static void main(String[] args){
// Zi zi = new Fu(); 不能通过⽗类来构造⼦类,先⼈(⽗类)根本不知道后⼈(⼦类)长什么样⼦        Fu fu =new Zi();//可以通过⼦类来构造⽗类,这时等号左边是⽗类
System.out.println(fu.num);//10,打印的是⽗类的num
}
}
第⼆种情况:间接通过成员⽅法访问成员变量
public class Demo02ExtendsField {
public static void main(String[] args){
Fu fu =new Fu();
Zi zi =new Zi();
//打印的是⽗类的num,因为该类没有继承其它类,他⾃⼰肯定有⼀个num,才能写出这个⽅法        fu.methodFu();//⽗类的num 10,补充:没有fu.methodZi(), 先⼈不知道后⼈的⽅法//如果⼦类有⼀个num,那就优先打印本类的,没有的话再往⽗类那⾥
//重点!⼦类⽤的是⽗类的⽅法打印num,这就要看这个⽅法属于谁,是谁定义的这个⽅法
//因为methodFu()这个⽅法是属于⽗类的,打印的当然就是⽗类的num
}
}
4. 区分⼦类⽅法中的重名
假如有好多个num,⽗类有⼀个,⼦类有两个,怎么才能正确地打印想要的那个num呢?
}
4.2 ⼦类
public class Zi extends Fu {
public int num =20;
public void methodZi(){
int num =30;
System.out.println(num);//30, 局部变量
System.out.println(this.num);//20, 本类的成员变量
System.out.println(super.num);//10, ⽗类的成员变量
}
}
4.3 看看⼦类⽅法 methodZi() 能不能正确区分三个num
public class Demo03Main {
public static void main(String[] args){
Zi zi =new Zi();
}
}
4.4 总结:要想正确地打印想要的num,可以这样打
局部变量,上⾯的那个num = 30,就可以直接写
本类的成员变量,上⾯的num = 20, ⽤this.成员变量名
⽗类的成员变量,上⾯的num = 10, ⽤super.成员变量名
5. 继承中成员⽅法重名的问题
假如⼦类和⽗类都有⼀个⽅法叫 method() , 那怎么知道⽤的是哪⼀个呢?
System.out.println("⽗类重名⽅法执⾏");
}
}
5.2 ⼦类
public class Zi extends Fu {
public void method(){
System.out.println("⼦类重名⽅法执⾏");
}
}
5.3 在main中调⽤ method() ⽅法
public class Demo04Main {
public static void main(String[] args){
Fu fu1 =new Fu();
Fu fu2 =new Zi();//通过⼦类来构造fu2
Zi zi =new Zi();
}
}
结论 :
1. 创建的对象是谁,⽤谁的类来构造对象的,就优先⽤谁,如果没有就向上。⽐如Fu fu2 = new Zi();,fu2是⽤⼦类来构造的,
那hod()就是⽤的⼦类的⽅法
2. 注意!⽆论是成员变量还是成员⽅法,如果没有都是向上⽗类,绝对不会向下⼦类的。
6. 继承⽅法中的覆盖重写
由 5. 继承中成员⽅法重名的问题,我们可以引出重写(Override)的概念
重写:在继承关系中,⽅法的名称⼀样,参数列表也⼀样
6.1 重写 (Override) 和重载 (Overload) 的区别
重写:⽅法的名称⼀样,参数列表【也⼀样】。也叫覆盖、覆写
重载:⽅法的名称⼀样,参数列表【不⼀样】。
6.2 覆盖重写的注意事项 (了解)
6.2.1 必须保证⽗⼦类之间⽅法的名称相同,参数列表也相同,否则⽆法进⾏覆盖重写
6.2.2 注解:@Override,这个注解写在⽅法的前⾯,⽤来检验是不是有效的覆盖重写,例如当⽅法名写错了,@Override底下就
会出现红⾊的波浪线,提⽰你这不是有效的覆盖重写。
public class Zi extends Fu {
@Override
public void method(){
System.out.println("⼦类重名⽅法执⾏");
}
}