|
|
JavaSE_Start
JavaSE-No.6.2——封装与static
JavaSE-No.6.3——代码块与内部类
注: 关于继承将分成两篇文章讲解,那我们就开始吧~
目录- 1. 为什么需要继承
- 2. 继承的概念
- 2.1 继承的语法
- 3 父类成员的访问
- 3.1 子类访问父类的成员变量和成员方法
- 3.2 super关键字
- 4. 子类构造方法
- 5. super和this的比较
1. 为什么需要继承
Java中使用类对现实世界中实体来进行描述,事物之间可能会存在一些关联,那在设计程序时就需要考虑。
例如: 猫和狗,他们都是动物。
我们分别来定义一个猫类和一个狗类:
class Dog {
public String name;
public int age;
public String color;
public void eat() {
System.out.println(name+"正在吃饭!");
}
public void walk() {
System.out.println(name+"正在和主人散步。");
}
}
class Cat {
public String name;
public int age;
public String color;
public void eat() {
System.out.println(name+"正在吃饭!");
}
public void play() {
System.out.println(name+"正在玩球。");
}
}
我们对比一下,发现两个类有一些相同的成员与方法。
那能否将这些共性抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。
2. 继承的概念
那么什么是继承呢?
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
简单来说就是将他们的共性进行抽取,把抽取出来的共性放到一个类当中,我们创建一个Animal类:
class Animal {
public String name;
public int age;
public String color;
public void eat() {
System.out.println(name+"正在吃饭!");
}
}
这时我们会发现Dog类和Cat类都报错了,怎么才能让Dog和Cat类访问到name呢?
这时我们要用到extends关键字:
修饰符 class 子类 extends 父类 {
// ...
}
更改Dog和Cat类
class Dog extends Animal{
public void walk() {
System.out.println(name+"正在和主人散步。");
}
}
class Cat extends Animal{
public void play() {
System.out.println(name+"正在玩球。");
}
}
我们再来简单解释一下,此处我们的Dog又被称为:子类、派生类;Animal被称为:父类、基类、超类。
我们在主函数中实例化一个dog
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "修勾";
dog.age = 6;
dog.color = "white";
dog.eat();
dog.walk();
}
}
总结:
- 子类会将父类中的成员变量或者成员方法继承到子类中了
- 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了
3 父类成员的访问 3.1 子类访问父类的成员变量和成员方法
子类和父类不存在同名成员变量或成员方法
class Base {
public int a = 1;
public int b = 2;
public void func1() {
System.out.println("父类中func1方法");
}
}
class Derived extends Base{
public int c = 3;
public int d = 4;
public void func2() {
System.out.println("子类中func2方法");
}
public void func() {
System.out.println(this.a);//访问从父类中继承下来的a,b
System.out.println(this.b);
System.out.println(this.c);//访问子类自己的c,d
System.out.println(this.d);
this.func1();//调用父类中继承的func1()方法
this.func2();//调用子类中继承的func2()方法
}
}
子类和父类成员变量或成员方法同名
class Base {
public int a = 1;
public int b = 2;
public void func1() {
System.out.println("父类中func1方法");
}
}
class Derived extends Base{
public int a = 11;
public int b = 22;
public void func1(int n) {
System.out.println("子类中func1方法(n)");
}
public void func1() {
System.out.println("子类中func1方法");
}
public void func() {
System.out.println(this.a);//输出什么??
System.out.println(this.b);
this.func1();//输出什么??
this.func1(1);
}
}
我们思考一下,此时会输出1、2,还是11、12?会运行父类中的func1还是子类中的func1?
答:11 12,子类中的func1。如果访问的成员变量或成员方法与父类中的同名,则优先访问自己的。
运行结果展示:
# 注意事项 #
- 如果访问的成员变量子类中有,优先访问自己的成员变量。如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
- 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
- 如果访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。
- 如果访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;
3.2 super关键字
如果我们想要在子类父类成员变量和成员方法同名的情况下,想在子类中访问父类这时我们就要用到super关键字
public void func() {
System.out.println(this.a);//访问子类中的a,b
System.out.println(this.b);
System.out.println(super.a);//访问父类中的a,b
System.out.println(super.b);
this.func1();//调用子类中的func1方法
super.func1();//调用夫类中的func1方法
}
运行结果展示:
# 注意事项 #
- 只能在非静态方法中使用
- 在子类方法中,访问父类的成员变量和方法。
- super指代的是子类从父类继承过来的内容这块空间的地址。
- super();调用父类的构造方法,接下来就讲到。
4. 子类构造方法
我们回到Animal和Dog类中,我们现在想给Animal提供一个构造方法:
class Animal {
public String name;
public int age;
public String color;
//新增构造方法
public Animal(String name,int age,String color) {
this.name = name;
this.age = age;
this.color = color;
}
public void eat() {
System.out.println(name+"正在吃饭!");
}
}
这时我们发现,# Dog类报错了 #,我们将其屏蔽,Dog类没有报错。
那么这是为什么呢?
父子父子,先有父再有子,即:子类对象构造时,需要先调用父类构造方法,然后执行子类的构造方法。
我们这里就要在子类的构造中,先对父类进行初始化。
class Dog extends Animal{
//构造方法
public Dog(String name, int age, String color) {
super(name, age, color);//显示的调用父类的构造函数,来初始化此时子类继承过来的父类的属性
}
public void walk() {
System.out.println(name+"正在和主人散步。");
}
}
# 注意 # super();只能在子类构造方法的第一行。
idea生成
为什么一开始没有写任何构造函数的时候也没有报错呢?
在我们在父类和子类中没有写构造方法时,编译器默认在父类和子类中提供构造方法。
例如: 在Animal类中提供
public Animal() {
}
在Dog类中提供
public Dog() {
super();
}
总结: 子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
# 注意事项 #
-
若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用
-
如果父类构造方法只有一个是带有参数的,此时编译器不会再给子类生成默认的构造方法,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
-
在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
-
super(...)只能在子类构造方法中出现一次,并且不能和this同时出现
5. super和this的比较
相同点
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
不同点
| this | super | |
|---|---|---|
| 当前对象的引用,当前对象即调用实例方法的对象 | 子类对象中从父类继承下来部分成员的引用 | |
| 非静态成员方法 | 访问本类的方法和属性 | 访问父类继承下来的方法和属性 |
| 非静态成员方法 | 是一个隐藏参数 | 不是隐藏的参数 |
| 构造方法 | 调用本类构造方法 | 调用父类构造方法 |
| 构造方法中 | this(...)用户不写编译器不会自动生成 | 一定会存在super(...)的调用,用户没有写编译器也会增加 |
|
|
以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!关于继承相关的知识还没有结束,下一篇文章会继续讲述,期待大家支持,谢谢~



