欢迎来到【开开心心学java,快快乐乐写代码】此专栏,本篇博客呢将会为大家仔细讲解关于面向对象的三大特性之一:继承。其他两大特性在我的主页里面也有,想了解的友友们欢迎垂阅。废话不多说,我们直接进入本篇博客正题----继承,光看这两个字是不是还是很抽象很模糊呢,不要担心,本博主依旧还是会讲的很仔细哒,认真看完,肯定会有所收获滴~
目录
1、为什么需要继承
Java中使用类对现实世界中的实体来进行描述,类经过实例化之后会产生对象,对象则可以用来表示现实中的实体。但是现实世界有很多相似的实体,而某些实体也会有一些关联,在程序设计中也是这样。比如:我现在要设计猫和狗这两个类.
定义狗类:Dog.java
//Dog.java
public class Dog{
string name;
int age;
float weight;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}void mew(){
System.out.println(name + "汪汪汪~~~");
}
}
定义猫类:Cat.java
public class Cat{
string name;
int age;
float weight;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}void mew(){
System.out.println(name + "喵喵喵~~~");
}
}
通过观察这两个类,我们不难发现,这两个类中有好多相同的代码,比如这些:
我这里还只是写了两个动物类,如果我还要再写一个鸡类、鸭类或者更多其他动物的类呢,那可能会有更多重复的代码。于是java中就提出了继承的概念,将这些类的共性提出来,实验代码复用,减少重复的代码。
2、继承概念
继承机制:是面向对象程序设计中实现代码复用的最重要手段,它允许程序员在原有类的特性的基础上扩展、增加新功能,从而形成一个新的类,这杨新形成的类就叫做派生类(子类)。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承主要解决的问题是:实现代码复用。
例如:猫和狗都是动物,它们都有名字、年龄和体重,它们都需要吃饭和睡觉。因此我们可以把这些共性抽取出来,形成一个动物类。然后再具体写一个猫类或者狗类的时候直接继承动物类就行。在这里,动物类就相当于是父类(超类/基类),狗类或猫类就相当于是子类(派生类)。这时猫类或者狗类就有了之前抽取共性而组成动物类的特性,写猫类或狗类时就不需要再写那些共性特征了,并且可以在父类基础上进行扩展,比如增加属性或者方法。以继承的思想来达到共用,可以实现代码复用。下面是画图的一个简单理解:
从继承的概念中可以看出,继承最大的作用就是可以实现代码复用和多态(下一篇博客中有多态的仔细讲解)。
3、继承的语法
在java中如果要表示类之间的继承关系,需要用到extends关键字。具体如下:
修饰符 class 子类名 extends 父类名{
…………
}
下面是利用继承机制对上述所说猫狗类的一个重新设计:
public class Animal {
String name;
int age;
float weight;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
}
public class Dog extends Animal {
void mew(){
System.out.println(name + "汪汪汪~~~");
}
}
public class Cat extends Animal {
void mew(){
System.out.println(name + "喵喵喵~~~");
}
}
public class Test{
public static void main(String[] args) {
Cat cat=new Cat();
Dog dog=new Dog();
// cat类中并没有定义任何成员变量,name属性肯定是从父类Animal中继承下来的
System.out.println(cat.name);
cat.mew();
System.out.println(dog.name);
dog.mew();
}
}
运行结果:
在这段代码中可以很清楚的看到:Cat类和Dog类都继承了Animal类,所以在子类的类体中就没有再写那些已经从父类中继承过来的属性和方法(注意:子类只能继承父类中没有用private修饰的字段或方法),在Test类中创建子类对象时,对象可以调用从父类继承过来的属性或方法。
注意:子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了。
4、父类成员的访问
在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?
子类中不存在与父类同名的变量时:
public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; // 访问从父类中继承下来的a
b = 20; // 访问从父类中继承下来的b
c = 30; // 访问子类自己的c
}
}
子类中存在与父类同名的变量时:
public class Base {
int a;
int b;
int c;
}
public class Derived extends Base{int a;//与继承过来的a重名
char b;//与父类中成员b同名,但类型不同
public void method(){a=100;//是访问父类继承的a,还是子类自己新增的a?
b=101;// 访问父类继承的b,还是子类自己新增的b?
c=102;// 子类没有c,访问的肯定是从父类继承下来的c
// d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
}
}
在子类方法中,或者通过子类对象去访问成员变量时:
- 如果访问的成员变量子类中自己有,则优先访问自己的。
- 如果访问的成员变量子类中无,而继承的父类中也没有,则编译报错。
- 如果访问的成员变量与父类的成员变量名相同,则优先访问自己的成员,即:子类将父类成员隐藏了。
成员变量访问时遵循就近原则,先从子类中寻找,有就访问自己的,没有再向父类中寻找,如果父类中也没有,则编译报错。
访问成员方法时也是这样:
子类与父类的成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,先在子类方法中找,有则访问,无则在父类方法中寻找,有则访问,无则报错。
子类与父类的成员方法名有相同时,通过子类对象访问子类与父类同名的方法时,优先访问子类自己的方法,而父类的同名方法将不会被访问到。如果对象访问的是父类和子类的方法名相同但参数列表不同的方法时,编译器会根据调用方法时传递的参数来匹配决定调用哪一个方法。
问题:如果子类中存在与父类中相同的成员时,那如何在子类中访问父类相同名称的成员呢?
5、supper关键字
由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果需要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员。
public class Base {
int a;
int b;
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}public class Derived extends Base{
int a; // 与父类中成员变量同名且类型相同
char b; // 与父类中成员变量同名但类型不同
public void methodB(){
System.out.println("Derived中的methodB()方法");}
public void methodC(){
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从父类继承下来的部分
super.a = 200;
super.b = 201;
// 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
methodB();// 如果在子类中要访问被重写的基类方法,则需要借助super关键字
super.methodB(); // 访问基类的methodB()
}
}
如果明确要访问到父类中与子类同名的成员,则必须使用supper关键字。
注意:supper关键字只能在非静态方法中使用。
6、子类的构造方法
java中规定,子类在调用自己的构造方法时,必须先调用父类的构造方法,然后再执行自己的构造方法。
public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,并且只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}运行结果:
注意:
在类中,this(……)用于调用本类的构造方法,supper用于调用父类的构造方法,二者不能同时出现在构造方法中。
this是当前对象的引用,当前对象即调用该成员变量或方法的对象。supper相当于是子类对象从父类继承过来的那一部分属性或方法的引用。可大致用以下图来表示:
以上就是我要今天分享的内容啦,后续我还会继续更新的哒,常看我的博客会学到很多知识哦