继承的定义与使用
继承:在已有基础上继续进行功能的扩充。
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{
private String name;
private int age;
private int sno;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
}
观察上述代码含有大量的重复性代码,学生相对于人来说,只多了一个sno属性,这时候想要消除结构定义上的重复,就要用到继承。
继承的实现
class 子类 extends 父类
说明:子类在一些书上也被称为派生类,父类也被称为超类(super class)。
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 int sno;//扩充的新属性
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
}
public class Test{
public static void main(String[] args) {
Student stu = new Student();
stu.setName("Tom");
stu.setAge(20);
stu.setSno(101);
System.out.println("姓名: "+stu.getName()+",年龄: "+stu.getAge()+",学号: "+stu.getSno());
}
}
通过上述代码可以发现,当发生了继承关系之后,子类可直接继承父类的操作,可以实现代码的重用。子类可以进行功能的扩充,例如:扩充属性和方法。
继承的限制
- 子类对象在进行实例化前一定会首先实例化父类对象。默认先调用父类的构造方法再调用子类的构造方法进行子类对象初始化。
class Person{
public Person(){
System.out.println("--Person类对象--");
}
}
class Student extends Person {//定义了一个子类
public Student(){
System.out.println("--Student类对象--");
}
}
public class Test{
public static void main(String[] args) {
new Student();
}
}
执行结果为:
--Person类对象--
--Student类对象--
通过上述代码我们发现,没有任何一条语句调用父类构造方法。因此,子类对象实例化之前一定显示先实例化父类对象。
注意:
- 实际在子类的构造方法中,相当于隐含了一个语句super();
- 如果父类没有提供无参构造,这时候就必须使用super()明确指明你要调用的父类方法;
- java只允许单继承,不允许多继承。
若一个C类想同时拥有A类和B类中的操作,可以采用多层继承的方法。
class A{}
class B extends A{}
class C extends B{}
这个层数不建议太多,类的继承关系最多3层。
总结:
- 在进行继承的时候,子类会继承父类的所有结构。所有的非私有操作属于显示继承(可以直接调用),所有的私有操作属于隐式继承(通过其他方式调用,例如getter或setter)。
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person {//定义了一个子类
public void display(){
System.out.println(getName());
}
}
public class Test{
public static void main(String[] args) {
Student stu=new Student();
stu.setName("Tom");
System.out.println(stu.getName());
stu.display();
}
}
此时父类的属性的确被子类所继承了,但是子类能够使用的是所有非private操作,而所有的private操作无法直接被使用,所以称为隐式继承。
继承总结:
- 继承目的(扩展已有类的功能,使代码复用);
- 子类对象的实例化流程:一定先实例化父类对象;
- 不允许多重继承,只允许多层继承。
覆写(override)
如果子类出现了和父类相同的方法或属性时,这样的操作就称为覆写。
方法的覆写
子类定义了与父类方法名称、参数类型及个数完全相同的方法,但是被覆写不能够拥有比父类更为严格的访问控制权限。‘’
class Person{
public void print() {
System.out.println("1.Person类的print方法");
}
}
class Student extends Person{
public void print(){
System.out.println("2.Student类的print方法");
}
}
public class Test{
public static void main(String[] args) {
Student stu=new Student();
stu.print();
}
}
执行结果为:
2.Student类的print方法
说明:
- 你当前调用的方法是通过那个类new的。
- 当调用某个方法时,如果该方法被子类所覆写了,那么调用的一定是被覆写过的方法。
- 访问权限的严格性:public<default<private
建议:
- 写方法,建议使用public;
- 写属性,建议使用private。
范例:父类用private定义的方法,子类中用public覆写。
class Person{
public void print() {
this.print();
}
//父类方法使用private定义,表示该方法只能被父类使用,子类无法使用。换言之,子类根本不知道父类有这样的方法。
private void display(){
System.out.println("1.Person类的print方法");
}
}
class Student extends Person{
//这个方法还是子类定义的新方法,并没有和父类的方法有直接的关系
public void dispiay(){
System.out.println("2.Student类的print方法");
}
}
public class Test{
public static void main(String[] args) {
new Student().dispiay();
}
}
重载和覆写的区别。
属性的覆写
class Person{
public String name="Per";
}
class Student extends Person{
//按照就近取用原则,肯定找被覆盖的属性
public String name="Stu";
}
public class Test{
public static void main(String[] args) {
System.out.println(new Student().name);
}
}
这种操作本身没有意义,因为类中属性都要求使用private封装。