目录
1.定义
一个类在现有类的基础上,对父类进行扩充,也就是子类继承父类的特征和行为,一个类只有一个直接父类,如果没有声明父类,则默认的父类为Object类。
继承主要解决的问题就是共性抽取,如在一个坦克大战的游戏中,坦克有很多种(敌方坦克1,敌方坦克2……,我方坦克),而这些坦克共同的属性有生命值,位置坐标等等,共同的行为有移动,发射子弹等等。如果我们对每种类型的坦克都定义一次这些属性和方法,就会使我们的代码量加大。此时我们便可以通过继承的思想,抽取他们的共性,定义在一个父类中,然后让每个类型的坦克都继承这个父类的属性和方法,而子类中只需定义他们特有的内容,这样就可以使问题得到简化。
2.继承的格式
(1)首先我们定义一个父类,并写一个父类执行方法。
//定义一个父类
public class Father {
public void fatherWork(){
System.out.println("父类执行了!");
}
}
(2)接着我们再定义两个子类继承父类,并且子类中没有任何信息。
//子类1
public class Son1 extends Father{
}
//子类2
public class Son2 extends Father{
}
(3)这时我们实例化子类,发现子类能够执行父类的方法,说明子类继承了父类。
public static void main(String[] args){
Son1 son1 = new Son1();
son1.fatherWork();
Son2 son2 = new Son2();
son2.fatherWork();
}
结果为:
父类执行了!
父类执行了!
3.继承的访问特点示意图
如图所示,子类中包含了父类的属性和方法,并且有自己特有的属性和方法。当我们在子类中调用属性和方法时,同样遵循就近原则,现在当前类中寻找需要调用的属性和方法,如果没有才会进入父类中去寻找。
例如在子类中调用属性3和方法3,系统会优先在子类中寻找,发现属性3和方法3在子类中,直接调用;
若要调用方法1,系统会先在子类中寻找,找不到就进入父类寻找,并从父类中调用方法1。
4.继承的注意事项
(1)子类只能继承父类所有非私有(非private)的成员变量和成员方法。
(2)继承中构造方法的访问特点:
①子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
②子类构造方法在调用时会首先调用父类的构造方法,然后再执行子类的构造方法。
③若父类没有写构造方法,子类构造方法调用时系统会赠送一个无参的父类构造方法。
④每个子类构造方法只能同时调用一个父类构造方法。
⑤父类的构造方法只能由子类构造方法调用,其他子类成员方法不能调用。
//定义一个父类
public class Father {
public Father() {
System.out.println("父类无参构造方法");
}
public Father(int a) {
System.out.println("父类参数为" + a + "的构造方法");
}
}
//子类1
public class Son1 extends Father {
public Son1() {
super();//调用了父类无参构造方法,可省略不写,默认调用无参构造方法。
System.out.println("子类无参构造方法");
}
public Son1(int a) {
super(a);//调用了父类带参数的构造方法
System.out.println("子类参数为" + a + "的构造方法");
}
}
下面我们分别用无参和带参构造方法构造子类Son1
public class Start {
public static void main(String[] args){
Son1 sonA = new Son1();//无参构造
Son1 sonB = new Son1(3);//带参构造
}
}
结果为:
父类无参构造方法
子类无参构造方法
父类参数为3的构造方法
子类参数为3的构造方法
5.super、this关键字的用法
(1)super、this关键字都是用来解决变量重名问题的,但super关键字针对子类与父类成员变量重名,this关键字针对本类成员变量与局部变量重名。
(2)super关键字的用法
①在子类成员方法中访问父类成员变量。
②在子类成员方法中访问父类成员方法。
③在子类构造方法中访问父类构造方法。
(3)this关键字的用法
①在本类的成员方法中访问本类的成员变量。
②在本类的成员方法中访问本类的另一个成员方法。
③在本类的构造方法中访问本类的另一个构造方法。
(4)下面举一个实例:
//定义一个父类
public class Father {
String name = "父类";//父类成员变量
//父类成员方法
public void function(){
System.out.println("父类成员方法");
}
//父类构造方法
public Father() {
System.out.println("父类构造方法");
}
}
//子类
public class Son1 extends Father {
String name = "子类";//子类成员变量
//子类成员方法
public void function(){
System.out.println("子类成员方法");
}
//子类构造方法
public Son1() {
super();
System.out.println("子类构造方法");
}
//打印子类信息
public void print(){
System.out.println("父类:" + super.name);
System.out.println("子类:" + this.name);
super.function();
this.function();
}
}
调用打印方法打印结果为:
父类构造方法
子类构造方法
父类:父类
子类:子类
父类成员方法
子类成员方法
(5)内存示意图
6.继承中方法的覆盖重写
(1)定义
方法的重写是当程序中父类的某一个方法并不能满足子类的需求时,子类可以重新定义该方法的内容与功能来满足子类的需求的一种操作。
(2)格式
我们在上面所定义的子类 Son1 中对父类的 fatherWork( ) 方法进行重写。
@Override
public void fatherWork() {
System.out.println("方法被重写了!");
}
此时我们再次调用此方法,发现 Son1 所调用的是重写后的方法。而 Son2 没有重写该方法,因此调用的还是原方法。
public static void main(String[] args){
Son1 son1 = new Son1();
son1.fatherWork();
Son2 son2 = new Son2();
son2.fatherWork();
}
结果为:
方法被重写了!
父类执行了!
(3)注意事项
补充:@override是一个注解,用来检测重写方法的格式是否正确。
①重写的方法名和参数列表必须与父类一致。
②子类方法的返回值范围必须小于等于父类方法的返回值范围。
③子类方法的访问权限必须大于等于父类方法的访问权限(public > protected > (default) > private)
(4)重写与重载的比较
重写:儿子继承了父亲的公司,并且根据自己的需要进行改造。
重载:创立公司时买了三辆相同车型不同颜色的汽车,根据需要来使用。