继承

上述图中,存在的类,我们在构造时,可能有一些共同的属性或者方法,比如,age,name,在每一个类中,我们都需要去定义,这样代码重复性就很高了,这时,我们引入了继承了概念。
继承的好处
① 减少了代码的冗余,提高了代码的复用性
② 便于功能的扩展
③ 为之后多态性的使用,提供了前提
继承的格式
class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
子类和父类的关系,不同于子集和集合的关系。
extends:延展、扩展
规定
Java中关于继承性的规定:
- 一个类可以被多个子类继承。
- Java中类的单继承性:一个类只能有一个父类
- 子父类是相对的概念。
- 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
- 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
注意
- 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
- 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
- 意味着,所有的java类具有java.lang.Object类声明的功能。
练习
package cap12;
//Person.java
public class Person {
public String name;//公共的字符串类型的名字
protected int sex;//受保护的整型的性别,0代表男,1代表女
private int age;//私有的整型的年龄
int weight;//缺省的整型的体重
public void walk() {
System.out.println("行走");
}
protected void talk() {
System.out.println("交谈");
}
void run() {
System.out.println("跑步");
}
private void sleep() {
System.out.println("睡觉");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cap12;
public class Student extends Person {
public void test() {
walk();
System.out.println(name);
System.out.println(sex);
System.out.println(weight);
System.out.println(getAge());
//System.out.println(age);//报错
//sleep();//报错
walk();
run();
run();
}
}
package cap12;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.name = "";
s.sex = 1;//不报错是因为在同一个包下
s.weight = 100;//不报错是因为在同一个包下
s.walk();
s.test();
s.talk();
s.run();
}
}
package cap12Test;
import cap12.Student;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.name = "";
s.sex = 1;//报错,not visible
s.weight = 100;//报错,not visible
s.walk();
s.test();
s.talk();//报错,not visible
s.run();//报错,not visible
s.sleep();//报错,not visible
}
}
cap12Test.Test和cap12.Test的目的是为了说明,对象名.方式去访问的时候,并不是强制规定那种修饰权限才能行得通,也要看位置。
同样的,不同包的继承
package cap12Test;
import cap12.Person;
public class Student1 extends Person{
public void Test() {
name = "李四";
sex = 1;
age = 19;//报错,not visible
weight = 20;//报错,not visible
walk();
talk();
run();//报错,not visible
sleep();//报错,not visible
}
}
更多的,我觉得继承的时候,更像是一种全路径的继承
如果是缺省—>cap12.Person.xxx();必须要在同包下
如果是public–>*.Person.xxx();同一个工程
如果是protected–>*.Person.xxx(); extends Person,可以不同包,但是不同包必须要有继承关系
如果是private–>不可见,可以通过getXxx()或者setXxx()去访问
这就是四种权限修饰符的作用范围
方法的重写
定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
要求:
- 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
- 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
- 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
- 子类不能重写父类中声明为private权限的方法
- 子类方法抛出的异常不能大于父类被重写方法的异常
注意:子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。
package cap12override;
public class Person {
public void walk() {
System.out.println("行走");
}
protected void talk() {
System.out.println("交谈");
}
void run() {
System.out.println("跑步");
}
private void sleep() {
System.out.println("睡觉");
}
}
package cap12override;
public class Student extends Person{
@Override
public void walk() {
System.out.println("学生行走");
}
@Override
protected void talk() {
System.out.println("学生交谈");
}
@Override
void run() {
System.out.println("学生跑步");
}
private void sleep() {
System.out.println("学生睡觉");
}
}
package cap12overrideTest;
import cap12.Person;
public class Student extends Person{
@Override
public void walk() {
System.out.println("学生行走");
}
@Override
protected void talk() {
System.out.println("学生交谈");
}
@Override//说明方法是重写的,去掉这个下面就不报错了,去掉的话,这就是一个类的方法,不是从父类继承的
void run() {//报错,无法重写,因为不可见
System.out.println("学生跑步");
}
private void sleep() {//不是重写,就是该类的一个方法
System.out.println("学生睡觉");
}
}
总结:可见可重写,不可见不可重写。能否重写其实归结起来就是四种权限修饰符的作用范围
super关键字
在Java类中使用super来调用父类中的指定操作:
- super可用于访问父类中定义的属性
- super可用于调用父类中定义的成员方法
- super可用于在子类构造器中调用父类的构造器
注意:
- 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
- super的追溯不仅限于直接父类(父类的父类,直到Object)
- super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识
调用父类的构造器
- 子类中所有的构造器默认都会访问父类中空参数的构造器
- 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语 句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行
- 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错
| 区别点 | this | super |
|---|---|---|
| 访问属性 | 访问本类中的属性,如果本类没有此属性则从父类中继续查找 | 直接访问父类中的属性 |
| 调用方法 | 访问本类中的方法,如果本类没有此方法则从父类中继续查找 | 直接访问父类中的方法 |
| 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
子类对象实例化过程



4443

被折叠的 条评论
为什么被折叠?



