------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、 继承的概述
1、继承就是从已经存在的类中继承信息创建新类的过程。这时被继承信息的类称为父类(超类、基类);继承信息而来的类称为子类。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。注意:子类只能从一个父类中继承信息,不能从多个类中继承,但是可以从多个接口中实现功能。
2、通过 extends 关键字让类与类之间产生继承关系。
3、注意事项:
!. 子类可以直接访问父类中的非私有的属性和行为。
!!.子类无法继承父类中私有的内容。
!!!.父类怎么来的?共性不断向上抽取而来的。
二、 继承的特点
1、 提高了代码的复用性。多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
2、 让类与类之间产生了关系。有了这个关系,提供了多态的前提。
3、 Java只支持单继承,不支持多继承。即一个类只能有一个父类,不可以有多个父类。因为多继承容易出现问题。两个父类中有相同的方法,子类到底要执行哪一个是不确定的。所以java不支持多继承,但将这种机制换了另一个安全的方式来体现,也就是多实现。
三、 子类的实例化过程
1、this和super
this和super的用法很相似,his代表本类对象的引用,super代表父类的内存空间的标识。当本类的成员和局部变量同名用this区分,当子父类中的成员变量同名用super区分父类。
2、 构造函数
(1)类对象进行初始化时,父类的构造函数也会运行。那是因为子类的每一个构造函数默认第一行有一条隐式的语句super();Super()会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();
(2)为什么子类一定要访问父类中的构造函数。因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时,要先访问一下父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。在上面的示例中已经有了很好的体现。注:super语句一定定义在子类构造函数中的第一行。
(3)构造函数结论:子类的所有构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();当父类中没有空参数的构造函数时,子类必须手动通过supe语句或者this语句形式来指定要访问的构造函数。当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。
3、 对象的实例化过程
4、 一个对象实例化过程,以Person p = newPerson();为例:
(1)JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下)。
(2) 在内存中开辟空间,并分配地址。
(3)并在对象空间中,对对象的属性进行默认初始化。
(4)调用对应的构造函数进行初始化。
(5)在构造函数中,第一行会先到调用父类中构造函数进行初始化。
(6) 父类初始化完毕后,再对子类的属性进行显示初始化。
(7) 再进行子类构造函数的特定初始化。
(8) 初始化完毕后,将地址值赋值给引用变量。
示例:
/*
学生包含 3 个属性:
姓名、学号以及成绩。优秀生也是员工,除了含有学生的属性外,另为还有一个
自学属性。请使用继承的思想设计出学生类和优秀生类。要求类中提供必要的方
法进行属性访问。
学生类:name id score ,方法learning
优秀生类:继承了学生,并有自己特有的方法self_learning。
*/
//学生类,也是父类
class Student
{
private String name;//姓名
private String id; //工号
private double score; //成绩
//自定义构造函数初始化
student(String name,String id,double score)
{
this.name = name;
this.id = id;
this.score = score;
}
//学习方法
public abstract void learning()
{
System.out.println("learning");
}
}
//优秀生类,继承学生类
class ExcellentStudents extends Student
{
ExcellentStudents(String name,String id,double bonus)//子类的构造方法
{
super(name,id,score);//调用父类中的构造器
}
public void self_learning()//优秀生类的特有工作方法内容
{
System.out.println("by yourself");
}
}
//普通学生类,继承学生类
class OrdinaryStudents extends Student
{
Pro(String name,String id,double score)
{
super(name,id,score);
}
public void work()//普通学生类的学习方法内容,覆盖父类
{
System.out.println("by teacher");
}
}
class AbstractDemo
{
public static void main(String[] args)
{
ExcellentStudents es = new ExcellentStudents("estudent","001",100);
es.learning();
es.self_learning();
OrdinaryStudents os = new OrdinaryStudents("ostudent","020",80);
os.learning();
}
}
四、 多态的概述
1、 多态性简单说就是一个对象对应着不同类型,同时同样的对象引用调用同样的方法但是做了不同的事情。要实现多态需要做两件事:
(1) 方法重写(子类继承父类并重写父类中已有的或抽象的方法);
(2) 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
2、 实现多态的前提是:
(1)需要存在继承或者实现关系。
(2) 需要有覆盖操作:父类中有方法被子类重写。
3、 多态的体现
(1)父类的引用指向了自己子类的对象。
(2)父类的引用也可以接收自己的子类对象。
如: Person p = new Worker();
其中就将父类型的 p 引用指向了子类的对象。
4、 多态的利弊
(1) 好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容。
(2) 前期定义的内容不能使用(调用)后期子类的特有内容。
示例:
<span style="color:#999999;">class Fu{
int num =3;
}
class Zi extends Fu{
int num =4;
}
class DuoTaiDemo{
publicstatic void main(String[] args){
Zi f1 = new Zi();
System.out.println(f1.num);
Fu f2 = new Zi();
System.out.println(f2.num);
}
}</span>
五、 多态的特点
1、成员变量
编译时:参考引用型变量所属的类中是否有调用的成员变量。有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考等号的左边。
2、成员函数(非静态)
编译时:参考引用型变量所属的类中是否有调用的函数。有,编译通过。没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
示例
</pre><span style="font-size:18px"><span style="color:#666666"> </span></span><pre name="code" class="java">class Fu{
voidshow(){
System.out.println("fu show");
}
}
class Zi extends Fu{
voidshow(){
System.out.println("zi show");
}
}
class DuoTaiDemo{
publicstatic void main(String[] args){
Fu f = new Zi();
f.show();
}
}
3、静态函数
编译时:参考的是对象所属的类中是否有调用的函数。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译和运行看左边。
示例
class Fu{
static voidmethod(){
System.out.println("fu static method");
}
}
class Zi extends Fu{
static voidmethod(){
System.out.println("zi static method");
}
}
class DuoTaiDemo{
publicstatic void main(String[] args){
Fu f = new Zi();
f.method();// fu static method
Fu.method();
}
}