继承

来源:互联网 发布:意大利尚尼 知乎 编辑:程序博客网 时间:2024/05/17 06:38

继承体现的是一般与特殊的关系。

如果两个类(类型)存在一般与特殊的关系时,我们就成特殊的类型继承了一般的类型。

特殊的类型称为子类,一般的类型称为父类。

如果子类继承父类,子类就具有父类的一切功能。父类能做到的的事情,子类也可以完成。


如果A继承B, A就会称为一种特殊的B,A就是子类,B就是父类

A就会从B类中继承功能(成员)。A具有B类的一切能力


子类继承了父类,子类就会继承父类的成员,(子类可以使用父类中继承的成员,就好像子类中自己声明的一样)


Java中,使用extends 表示继承

子类继承父类,子类还可以在父类的基础上增加自己的功能。同事,也可以把父类的功能进行改造。  (重写){父类的功能可能并非完全适合与子类}


如果一个类没有显示的使员extends继承另外一个类,则该类隐式继承Object类,(object是Java中最根层次的类)

所有的类都是object的直接或者间接子类。

一个子类只能继承一个父类。(类不支持多重继承)


通过继承。我们可以避免代码的重复,


当父类与子类在同一个包中时,子类可以继承父类的public  ,protected与默认访问权限的成员,不能继承父类private访问权限的成员

当父类和子类不在同一个包中时,子类可以继承父类public,protected访问权限的成员,不能继承默认与private访问权限的成员


public protected访问权限的成员一定可以被子类继承,private访问权限的成员一定不会被子类继承,如果子类和父类在同一个包中,则子类继承父类默认访问权限的成员。如果子类与父类不在同一包中,则不继承 父类默认访问权限的成员


构造器不是方法,可也不是类的成员。因此,构造器不会被子类继承。(public修饰的也不可以)


调用父类构造器

尽管子类不会继承父类的构造器,但是,在子类的构造器中,会首先调用父类的构造器。父类的构造器中,也会调用其父类的构造器。这是一个递归的过程,一直调用到object类为止。


当我们没有显示调用父类构造器时,编译器会为我们补上一条调用父类构造器的语句

super();

super的作用:

1 通过super调用父类的构造器

2 通过super访问父类的成员

super调用父类构造器的语句要求:

1 调用方式

需要使用super调用父类的构造器,而不能通过父类构造器的名字调用。

2 调用位置

只能在子类构造器中通过super调用父类的构造器,而不能在子类构造器之外调用父类的构造器

3 语句顺序

使用super调用父类构造器必须是子类构造器中的第一条语句

补充说明:

当我们没有显示调用父类构造器时,编译器会自动补充super调用父类无参的构造器,条件:仅当当前的构造器没有使用this调用其他构造器时,才会补充super。(这是为了避免)


方法的重写:

当父类的方法不完全适合于子类时,子类就可以对父类的方法进行改造(父类的方法在子类中重新声明)

方法重写的语法规则:

1 子类方法与父类方法的名字相同。

2 子类方法与父类方法的参数列表相同,或者,与父类方法参数列表擦除之后的类型相同。

3 子类方法的返回类型需要时父类方法返回类型的可替换类型

可替换类型:1)当父类方法返回类型是void或者基本类型时,子类方法返回类型与父类方法返回类型相同

    2)当父类方法返回类型是引用类型时,子类方法返回类型与父类方法返回类型相同或者是父类方法返回类型的子类型

4  子类方法的访问权限不能低于父类方法的访问权限。(可以相同)

5 子类方法不能比父类方法抛出更多的受检异常


@Override 注解可以给编译器提供一种要重写父类方法的信息

如果使用@Override标记的方法没有重写父类中的方法。将会产生编译错误

我们在重写父类方法时,应该养成总是用@Override的好习惯


成员变量的隐藏

在子类中声明与父类具有相同名称的成员变量

隐藏的规则比较简单,只要名字相同即可(和类型无关)


引用类型之间的转换

自动转换: 子类型向父类型的转换是自动转换

强制转换:由父类型向子类型转换,需要类型转换符(编译通过你,但是运行产生异常)


为什么要使用强制类型转换

通过父类额引用只能访问父类的成员,不能访问子类新增的成员,即使父类的引用指向的就是子类型的对象,也不可以

如果需要访问子类新增的成员,则需要首先将父类引用转换成子类的类型,然后再进行访问(子类新增的成员)


instanceof 是一个二元运算符。返回的是布尔类型,用来判断左侧操作数(对象类型)是否是右侧操作数的类型,或者是右侧操作数的子类型。

null不表示任何有效的对象,因此null  instanceof任何类型,结果都是false

instanceof两侧的操作数一定要存在继承关系,否则在编译期间会产生编译错误



public class Convert {
public static void main(String[] args) {
Person p = new Person();
Student s = new Student();
/*
因为子类是一种特殊的父类,所有的子类都是父类类型,
因此,我们可以将子类的对象赋值给父类的引用。
换一种说法:父类的引用不仅可以指向父类的对象,也可以
指向所有子类型的对象。子类的引用只能指向子类的对象,
不能指向父类的对象。
*/
//正确,所有的学生都是人
//p = new Student();
//错误,不是所有的人都是学生。
//s = new Person();
//自动转换
//p = s;
//强制转换
//如果想要令强制转换能够成功,则p指向的对象类型必须
//是Student类型的对象才可以。否则,在编译期间没有问题,
//但是,在运行时会产生ClassCastException异常。
p = new Student();
//p.talk();
/*
为什么要使用强制类型转换?
通过父类的引用只能访问父类的成员,不能访问子类新增的成员。
即使父类的引用指向的就是子类型的对象,也不可以。


如果需要访问子类新增的成员,则需要首先将父类引用转换成
子类的类型,然后再进行访问(子类新增的成员)。
*/
//p.gotoSchool();
//Student stu = (Student)p;
//stu.talk();
//stu.gotoSchool();
/*
在转换的时候,如果能够保证父类型的引用指向的就是
子类型的对象?(如果能够保证转换的安全性,不至于在
运行时产生ClassCastException异常?
*/
if (p instanceof Student) {
Student stu = (Student)p;
stu.gotoSchool();
}

//引用类型的转换必须发生在具有继承关系的两个类型之间。
//如果两个类型没有继承关系,进行转换将会产生编译错误。
//String str = "abc";
//Student stu2 = (Student)str;


}


public void f(Person p) {
//p.gotoSchool();
}
}


class Person {
public void talk() {


}
}


class Student extends Person {
//子类新增的成员
public void gotoSchool() {


}
}







原创粉丝点击