继承
Java三大特性之一
一、定义
- Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
public class Student extends Person{}
- Student称为子类(派生类),Person称为父类(基类或超类)
二、好处
- 可以把多个子类中重复的代码抽取到父类中了,减少代码冗余,提高代码的复用性。
- 子类可以再父类的基础上,增加其他的功能,使子类更强大。
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种
就可以考虑使用继承,来优化代码
三、特点
Java只支持单继承,不支持多继承,但支持多层继承。
单继承:一个子类只能继承一个父类
不支持多继承:子类不能同时继承多个父类
多层继承:子类A继承父类B,父类B可以继承父类C。
每一个类都直接或间接地继承于Object
子类只能访问父类中非私有的成员
例如:
public class Furniture{
String name;
String material;
String shape;
}
class Desk extends Furniture{
public void effect()
{
System.out.println("可以放东西");
}
}
以上例子表示桌子类继承了家具类所有的属性,比如名字,材料,形状。
而桌子类又有自己独有的特点“可以放东西”。
四、子类到底能继承父类中的哪些内容
构造方法 | 非私有 不能 | 私有 不能 |
---|---|---|
成员变量 | 非私有 能 | private 能 |
成员方法 | 非私有 能 | private 不能 |
1.构造方法
public class Furniture{
String name;
String material;
public F(){}
public F(String name,String material)
{
this.name = name;
this.material = material;
}
}
public class Desk extends Furniture{
public F(){}
public F(String name, String material)
{
this.name = name;
this.material = material;
}
}
注:如果一个类中没有构造方法,虚拟机会自动的给你添加一个默认的空参构造
2.成员变量
非私有的可以直接访问并继承
private修饰的成员变量需要通过成员方法访问
public class Furniture{
private String name;
String material;
public void setName()
{
this.name = name;
}
public String getName()
{
return name;
}
public void setMaterial()
{
this.material = material;
}
public String getMaterial()
{
return material;
}
}
class Desk extends Furniture{
}
public class test{
public static void main(String[] args)
{
Desk d = new Desk();
d.material = "木头";
d.name = "桌子"//错误写法,因为Fu的name被private修饰,Zi无法继承。
//正确写法
d.setName("桌子");
}
}
3.成员方法
只有父类的虚方法表里的方法会被子类继承
public class Furniture{
public void Fshow1()
{
System.out.println("我是家具");
}
private void Fshow2()
{
System.out.println("我是家具");
}
}
class Desk extends Furniture{
public void DShow(){
System.out.println("我是桌子");
}
}
public class test{
public static void main(String[] args)
{
Desk d = new Desk();
d.Dshow();
d.Fshow1();
d.Fshow2();//错误写法,方法fushow2被private所修饰,不能被子类继承。
}
}
五、继承中,成员变量,成员方法,构造方法的访问特点。
1.成员变量的访问特点
就近原则:谁离我近,我就用谁。
先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
**super关键字:**直接访问父类成员
public class Furniture{
String name = "家具";
}
class Desk extends Furniture{
String name = "桌子";
public void show(){
String name = "小桌子";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
以上代码执行结果为
小桌子
桌子
家具
如果出现了同名的变量:
System.out.println(name);//先从局部位置开始往上找
System.out.println(this.name);//先从本类位置开始往上找
System.out.println(super.name);//先从父类位置开始往上找
2.成员方法的访问特点
- 直接调用:就近原则
- super关键字:直接访问父类方法
例如:
public class test{
public static void main(String[] args)
{
Desk D = new Desk();
D.effect();
}
}
class Furniture{
public void effect1()
{
System.out.println("装饰");
}
public void effect2()
{
System.out.println("家庭多元化");
}
}
class Desk extends Furniture{
public void effect1()
{
System.out.println("放东西");
}
public void effect2()
{
System.out.println("放很多东西");
}
public void effect()
{
//先在子类查看effect方法,有就调用子类的,没有就会往上调用从父类中继承下来的effect方法
this.effect1();
this.effect2();
//直接调用父类的effect方法
super.effect1();
super.effect2();
}
}
以上代码运行结果为:
放东西
放很多东西
装饰
家庭多元化
方法的重写
应用环境:
当父类的方法不能满足子类现在的需求时,需要对方法进行重写
书写格式:
在继承体系中,子类出现了和父类一模一样的方法声明,我们就称子类这个方法是重写的方法
@Override重写注释
- @Override是放在重写后的方法上行,校验子类重写时语法是否正确
- 加上注解后如果有红色波浪线,表示语法错误
- 建议重写方法都加@Override注解,代码安全,优雅!
如:
class Furniture{
public void effect1()
{
System.out.println("装饰");
}
public void effect2()
{
System.out.println("家庭多元化");
}
}
class Desk extends Furniture{
@Override
public void effect1()
{
System.out.println("放东西");
}
@Override
public void effect2()
{
System.out.println("放很多东西");
}
}
方法重写的本质
如果发生了重写,则会覆盖。
方法重写注意事项和要求
- 重写方法的名称,形参列表必须与父类中的一致
- 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致
- 只有被添加到虚方法表中的方法才能被重写
3.构造方法的访问特点
- 父类的构造方法不会被子类继承。
- 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。
为什么?
-
子类在初始化的时候,有可能会使用到父类中的数据,
如果父类没有完成初始化,子类将无法使用父类的数据。
-
子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
怎么调用父类构造方法的?
- 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行。
- 如果想调用父类有参构造,必须手动写super进行调用。
public class test{
public static void main(String[] args)
{
Desk D = new Desk("桌子","木头");
System.out.println(D.name + "," + D.material)
}
}
class Furniture {
String name;
String material;
public Furniture()
{
System.out.println("父类的无参构造");
}
public Furniture(String name,String material)
{
this.name = name;
this.material = material;
}
}
class Desk extends Furniture {
public Desk()
{
//子类构造方法中隐藏的super()去访问父类的无参构造
super();
System.out.println("子类的无参构造");
}
public Desk(String name,String material)
{
super(name,material);
}
}
上述代码执行结果如下:
桌子,木头
this,super使用总结
- **this:**理解为一个变量,表示当前方法调用者的地址值;
- **super:**代表父类存储空间。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 | this.成员方法(…) | this(…) |
super | super.成员变量 | super.成员方法(…) | super(…) |
ial)
{
super(name,material);
}
}
上述代码执行结果如下:
```java
桌子,木头
this,super使用总结
- **this:**理解为一个变量,表示当前方法调用者的地址值;
- **super:**代表父类存储空间。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 | this.成员方法(…) | this(…) |
super | super.成员变量 | super.成员方法(…) | super(…) |