继承与覆写的性质
继承的引出
- 继承性是java的三大特性之一,可为什么会有这一概念的诞生,它是为了解决哪些问题,这个是我们需要去了解的。
- java中的简单java类是类和对象的基本形式,但如果我们所有东西都用简单java类的形式出现,则有可能会出现问题,下面我们来使用简单java类来描写一个图书类和一个数学图书类进行对比
Book类 | MathBook类 |
---|---|
class Book{ private String title; private String author; private double price;<br/> public Book(){ } public Book(String title,String author,double price){ this.title=title; this.author=author; this.price=price; } public void setTitle(String title){ this.title=title; } public void setAuthor(String author){ this.author=author; } public void setPrice(double price){ this.price=price; } public String getTitle(){ return this.title; } public String getAuthor(){ return this.author; } public double getPrice(){ return this.price; } } | class MathBook { private String title; private String author; private double price; private String type; public MathBook(){ } public MathBook(String title,String author,double price,String type){ this.title=title; this.author=author; this.price=price; this.type=type; } public void setTitle(String title){ this.title=title; } public void setAuthor(String author){ this.author=author; } public void setPrice(double price){ this.price=price; } public String getTitle(){ return this.title; } public String getAuthor(){ return this.author; } public double getPrice(){ return this.price; } public void setType(String type){ this.type=type; } public String getType(){ return this.type; } } |
- 在以上的程序中,我们实现了两个简单java类,这样的实现在整个程序中是没有语法错误的,但该程序中加粗的代码,两个类都存在。
- MathBook类相较与Book类,只是多了一个成员属性 String type ,这样的情况,大大浪费了程序的性能,所以才会有继承性的特性存在
继承的定义
-
了解了继承的特性,那么我们来研究与你继承的定义,在java中如果要进行继承的定义,我们可以用关键字 extends来实现,其基本语法如下
class 子类 extendx 父类{}
-
在很多面向对象的概念中,父类又被称为超类(super class),子类又被称为派生类,下面我们通过具体的程序来实现这种继承带来的优点
class Book{ private String title; private String author; private double price; public Book(){ } public Book(String title,String author,double price){ this.title=title; this.author=author; this.price=price; } public void setTitle(String title){ this.title=title; } public void setAuthor(String author){ this.author=author; } public void setPrice(double price){ this.price=price; } public String getTitle(){ return this.title; } public String getAuthor(){ return this.author; } public double getPrice(){ return this.price; } } class MathBook extends Book{ } public class YootkDemo{ public static void main(String arge[]){ MathBook book=new MathBook(); book.setTitle("线性代数"); book.setAuthor("马老师"); book.setPrice(49.8); System.out.println(String.format("图书的名称为:%s 、图书的作者为:%s 、图书的价格为:%5.2f",book.getTitle(),book.getAuthor(),book.getPrice())); } } //图书的名称为:线性代数 、图书的作者为:马老师 、图书的价格为:49.80
-
在上面的程序中,我们可以看到,作为子类的MathBook中是没有的代码的,但依旧可以输出内容,这个情况就可以体现出,子类继承了父类的所有方法和属性。
-
事实上子类的定义出来,是要比父类更加严格,同时所描述的范围更加小,那么此时我们可以考虑在子类中加入自己的操作结构,
-
范例 在子类进行功能的扩充
class Book{ private String title; private String author; private double price; public Book(){ } public Book(String title,String author,double price){ this.title=title; this.author=author; this.price=price; } public void setTitle(String title){ this.title=title; } public void setAuthor(String author){ this.author=author; } public void setPrice(double price){ this.price=price; } public String getTitle(){ return this.title; } public String getAuthor(){ return this.author; } public double getPrice(){ return this.price; } } class MathBook extends Book{ private String type; public void setType(String type){ this.type=type; } public String getType(){ return this.type; } } public class YootkDemo{ public static void main(String arge[]){ MathBook book=new MathBook(); book.setTitle("线性代数"); book.setAuthor("马老师"); book.setPrice(49.8); book.setType("高等数学"); System.out.println(String.format("图书的名称为:%s 、图书的作者为:%s 、图书的价格为:%5.2f 、图书的学科为:%s",book.getTitle(),book.getAuthor(),book.getPrice(),book.getType())); } } //图书的名称为:线性代数 、图书的作者为:马老师 、图书的价格为:49.80 、图书的学科为:高等数学
-
这个时候MatehBook类既可以调用父类中的方法和属性,也可以调用自己类中定义的方法和属性
子类对象实例化流程
- 现在我们已经掌握了继承的概念,也通过extends的关键字来实现继承的相关定义,但是我们要正确的使用继承开发,还必须了解子类对象的实例化过程
- 在对象进行实例化的时候,所有使用关键字new实例化的对象,都必须调用类中的构造方法,下面我们来观察类继承构造方法的调用问题
class Book{
public Book(){System.out.println("【Book中的构造方法】");
}
}
class MathBook extends Book{
public MathBook(){System.out.println("【MathBook中的构造方法】");
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
}
}
//【Book中的构造方法】
//【MathBook中的构造方法】
- 通过结果我们可以知道,在继承的关系中,是先调用父类中的构造方法,再调用子类中的构造方法
- 事实上这种情况是相当于在子类的构造中隐藏了一个**super()语句,这个super()**指的就是父类的无参构造
- 范例 super() 构造
class Book{
public Book(){
System.out.println("【Book中的构造方法】");
}
}
class MathBook extends Book{
public MathBook(){
super();
System.out.println("【MathBook中的构造方法】");
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
}
}
/*
【Book中的构造方法】
【MathBook中的构造方法】
*/
- 此时,我们使用了super()的构造方法,结果同样没有改变,在使用super()方法的时候,必须要在构造方法的首行
继承的限制
- 虽然通过继承可以实现父类方法的重用,但在java程序的设计过程之中,对于继承也有若干个限制
- 限制一:一个子类只能继承一个父类,存在单继承的限制
- 范例 观察错误的继承
class Book{ //图书类
}
class Emp{ //雇员类
}
class MathBook extends Book,Emp{
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
}
}
/*
程序的编译结果
YootkDemo.java:5: 错误: 需要'{'
class MathBook extends Book,Emp{
^
1 个错误
*/
-
在其他的编程语言中,这样的程序是不会出现错误的,这也体现了java单继承的概念
-
限制二: 继承性虽然继承父类的所有的方法和属性,但是对于父类中的 privata 的属性及方法,不能直接的进行调用
-
范例 观察访问的限制
class Book{ //图书类 private String getInfo(){ return "【图书类中的方法】"; } } class MathBook extends Book{ } public class YootkDemo{ public static void main(String arge[]){ MathBook book=new MathBook(); book.getInfo(); } } /* YootkDemo.java:11: 错误: 找不到符号 book.getInfo(); ^ 符号: 方法 getInfo() 位置: 类型为MathBook的变量 book 1 个错误 */
-
private 的属性及方法具有封装性,当然是不能随意被调用的
覆写的定义
- 在类继承当中结构中,我们可以实现一个类结构中的复用,但这里面也有一些问题,父类中的一些名称标记是具有代表性的,这个时候我们就希望可以被保留下来,并且根据自己的需要再进行扩写,这就是覆写
方法的覆写
- 在类继承结构中如果定义了和父类相同的方法,那么这个时候就是方法的覆写,但是在进行覆写的时候,一定要保证,所有覆写的方法,返回值类型、参数类型及个数、方法名和父类的方法相同
- 范例 实现方法的覆写
class Book{ //图书类
public void print(){
System.out.println("【Book类】我是一个图书类");
}
}
class MathBook extends Book{
public void print(){
System.out.println("【MathBook类】我是一个数学图书类");
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
book.print();
}
}
//【MathBook类】我是一个数学图书类
- 此时MathBook类中的print()方法覆写了Book类中的方法,所以此时实例化的MathBook类调用的是覆写后的方法
- 在程序设计中一旦有了覆写的概念之后,实际上就会出现一个问题,同一个方法父类出现,子类也可能出现,虽然父类的方法不能满足于子类全部的需要,但是也有很大的相同,此时就可以用super.父类方法() 来形式来进行调用
class Book{ //图书类
public String getInfo(){
return "【Book】这是一个图书类";
}
}
class MathBook extends Book{ //数学图书类
public String getInfo(){
return super.getInfo()+"、【MathBook】这是一个数学图书类";
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
System.out.println(book.getInfo());
}
}
//【Book】这是一个图书类、【MathBook】这是一个数学图书类
- 这样的方法就能使程序的代码得到更好的利用,也使代码的结构更加清晰。
- 如果在子类中调用覆写过的父类的方法,那么就不要使用this.方法()去调用父类中覆写的方法,若处理不当,会出现程序溢出的情况,并且程序的可读性也会有很大的限制,所以,如果我们要在子类中调用父类的方法,我们就用super.方法(),在子类中调用自己的方法就用this.方法(),这样就会避免错误的调用。
方法覆写的限制
- 方法的覆写是有一个访问权限的限制的,子类覆写的方法不能比父类的访问权限更加严格,我们现在接触到的的访问控制权限实际上有3个,其大小关系为:private<default<public ,按照这样的的概念限制,使用default修饰的方法,我们可以用default和public的来覆写,使用public修饰的方法,我们可以用public来覆写
- 范例 观察正确的覆写
class Book{ //图书类
String getInfo(){
return "【Book】这是一个图书类";
}
}
class MathBook extends Book{ //数学图书类
public String getInfo(){
return "【MathBook】这是一个数学图书类";
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
System.out.println(book.getInfo());
}
}
//【MathBook】这是一个数学图书类
- 如上面的程序,父类使用了default(默认的),子类使用了public的权限来覆写。
- 事实上由于private的封装性,private的方法是无法被覆写的
- 范例 private的方法无法覆写
class Book{ //图书类
private String getInfo(){
return "【Book】这是一个图书类";
}
public void fun(){
System.out.println(this.getInfo()); //父类定义的方法,子类可以直接继承
}
}
class MathBook extends Book{ //数学图书类
public String getInfo(){
return "【MathBook】这是一个数学图书类";
}
}
public class YootkDemo{
public static void main(String arge[]){
MathBook book=new MathBook();
book.fun();
}
}
//【Book】这是一个图书类