龙空技术网

初识Java—(十七)类的继承

IT研究僧 140

前言:

现时兄弟们对“java继承一个类可以被自定执行吗对吗”大体比较讲究,朋友们都想要学习一些“java继承一个类可以被自定执行吗对吗”的相关知识。那么小编在网上搜集了一些关于“java继承一个类可以被自定执行吗对吗””的相关知识,希望姐妹们能喜欢,我们快快来学习一下吧!

5.6 类的继承继承引入

我们在编写了多个类后,难免会出现这么一种情况,在定义同类型的类时,例如:学生类,员工类,经理类等等。类中的变量,方法有的是重复性的。如果只是一两个类,我们重复写没有问题,那我们写一些新的类时,都要把这些方法和变量写再一遍,很显然,这样写起来比较麻烦,那我们考虑一下要如何把代码改进一下呢?

我们可不可以把这些类中的相同内容给提取到一个类中定义。然后,让这多个类与这个独立的类产生一个关系,有了这个关系后,这多个类就可以具备这个独立类的特性以及功能,那现在我们就把继承这个概念引入一下,也是我们学到的面向对象三大特征的接触到的第二个特征。

这样,多个类的相同属性和方法我们提取到一个单独的类中,那么多个类就可以不用定义这些属性和方法,只要继承这个类就可以了。

继承的格式:

class Fu{一系列的属性与方法}class Zi extends Fu{}
5.6.1 继承的特点

继承是面向对象的又一大特征,也是实现软件复用的重要手段。

Java的继承通过extends关键字来实现(extends其实是“扩展”的意思,这里叫继承,除了历史原因,还有就是子类扩展了父类,也从父类那里继承了属性和方法),实现继承的类被称为子类,被继承的类被称为父类(或者称为基类、超类)。父类和子类的关系是一种一般和特殊的关系。子类扩展了父类,将可以获得父类全部的Filed成员变量和方法。

Java的继承具有单继承的特点,每个子类只有一个直接父类,但是Java类可以有无限多个间接父类。

例如:

public class HighGradeCar extends Car {}public class BmwCar extends HighGradeCar{}

BmwCar类有两个父类,一个是Car,一个是HighGradeCar。

如果定义一个Java类时并未显示指定这个类的直接父类,则这个类默认扩展java.lang.Object类,因此java.lang.Object类是所有类的父类,要么是其直接父类,要么是其间接父类。

类与类产生了关系了,也就相应的出现了继承的一个弊端。类的耦合性增加了。我们开发有一个原则,“高内聚,低耦合”,耦合就是类与类的关系,内聚就是自己完成某件事的能力。也就是说,自己能做完的事情就不要麻烦别人,避免你用了别人的东西,那别人不给你用了,或者代码更改了,那你也得跟着改。所以说继承也是一把双刃剑。看情况用。

5.6.2 重写父类的方法

子类扩展了父类,子类是一个特殊的父类。大部分情况下子类总是以父类为基础,额外增加新的Field和方法.但是有一种特殊的情况例外:子类需要重写父类的方法。

举例1:父类Bird类

package com.langsin.test;public class Bird {public void fly(){System.out.println("可以在天空中飞翔....");}}package com.langsin.test;public class Ostrich extends Bird {@Override 鸵鸟public void fly() {System.out.println("只能在地上跑......");}public static void main(String[] args) {Ostrich os = new Ostrich();os.fly();}}

程序执行时,不再执行父类Bird中fly()方法,而是执行了自身的fly()方法,这种子类包含与父类同名方法的现象称为重写,也称为方法覆盖(Override)。

方法的重写要遵循如下规则:

1、 方法名相同、形参列表相同

2、 子类方法返回值类型应比父类方法返回值类型相等或者更小。返回值类型比父类的要小,这个返回值一定是有父子关系才行的,基本类型之间没有父子关系。

3、 子类方法声明抛出的异常类应该比父类方法更小或相等。

4、 子类权限比父类权限大或者相等

当子类覆盖了父类方法后,子类对象将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法,需要使用super关键字。如果父类方法具有private访问权限,则该方法对其子类是隐藏的,也就无法重写该方法。如果子类中定义了一个与父类private方法相同的方法名、相同形参列表、相同返回值类型的方法,依然不是重写,只是在子类中定义了一个新的方法而已。

举例2:

package com.langsin.test;public class Bird {public void fly(){System.out.println("可以在天空中飞翔....");}private void getFood(){System.out.println("得到小虫子");}}package com.langsin.test;public class Ostrich extends Bird {@Overridepublic void fly() {super.fly();System.out.println("只能在地上跑......");}public void getFood(){//子类自定义的方法,不是重写的Brid类中的getFood()方法}public static void main(String[] args) {Ostrich os = new Ostrich();os.fly();}}

父类中定义的fly方法,使用super可以调用到,但是getFood()方法却无法调用到,因为此方法是私有方法,只有父类本身可调用。使用super关键字调用fly()方法,就可以执行父类中被重写的方法。

继承的注意事项:

(1) 子类只能继承父类所有非私有的成员。子类不能继承父类的构造方法,但是可以通过super关键字来访问父类的构造方法。

(2) 在子类中重写了父类的方法,那么调用的是子类中重写后的方法,如果还想继续用父类中的方法,可以使用super关键字。

(3) 不要为了一小部分功能而去继承。A类中有两个方法,B类中有两个方法,其中他们中有一个是重复的,你写继承了。是,这样是的确可以得到想要的,但是你想一想,你不用的那个方法,不属于你的那个,是不是自己也拿到了?

那我们考虑一下,什么时候用继承呢?继承其实体现的是一种关系:“is a”,如果有两个类,只要他们符合谁是谁的一种时,用继承。

继承中成员变量的关系:

(1) 子类中的成员变量名称和父类中的成员变量名称不一样。在子类方法中作输出,测试一下。

(2) 子类中的成员变量名称和父类中的成员变量名称一样。在子类方法中作输出,测试下。

在子类方法中访问一个变量的查找顺序:子类方法的局部范围------子类成员范围------父类成员范围。找不到就报错。

5.6.3 super限定与this关键字的应用及区别

当我们在子类中定义了一个成员变量,方法中定义一个同名的变量,我想输出两个变量的值,怎么办?如果父类中也一个同名的成员变量,我想在子类中输出这个变量的值,怎么办?我们根据前面的学习知道了,我们可以用this关键字指向本类的引用。那么如果是想用父类的呢?

super是Java提供的关键字,super用于限定该对象调用从父类继承得到的Field成员变量或方法。

举例1:

package com.langsin.test;public class Bird {Bird(){System.out.println("=========");}private String name = "";public void setName(String name){this.name = name;}public String getName(){return this.name;}public void fly(){System.out.println("可以在天空中飞翔....");}}子类:package com.langsin.test;public class Ostrich extends Bird {Ostrich(){super.setName("小鸟");}private String name = "鸵鸟";public String getName(){return this.name;}@Overridepublic void fly() {System.out.println("只能在地上跑");System.out.println(super.getName());System.out.println(this.getName());}public static void main(String[] args) {Ostrich os = new Ostrich();os.fly();}}
5.6.4 调用父类构造器

我们在父类中写两个构造方法,一个有参,一个无参。子类中写两个构造方法,一个有参,一个无参。新建一个子类的对象,运行一下,会出现什么样的结果呢?

我们会发现,子类继承父类,子类在实例化时会首先调用父类的构造方法,对父类成员进行初始化。

那我就问了,为什么?因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类在初始化之前,一定要先完成父类数据的初始化。

如果父类的构造方法是隐式的,那么Java会帮我们进行自动调用。而如果父类的构造方法是显式的,那么子类就必须声明一个显示的构造方法,同时在构造器中显示的调用父类的构造器。

如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的Field,而不是该类自己定义的Field。

在子类进行实例化时,会首先调用父类的构造方法,对父类中的Field成员变量或者方法进行初始化,但不会创建父类对象。

举例1:

package com.langsin.test;public class Bird {Bird(String name){System.out.println("=========");}}package com.langsin.test;public class Ostrich extends Bird {Ostrich() {super("小鸟");}}

继承中出现构造方法时需要注意:

在父类中写一个有参构造,在子类中写一个无参构造,一个与父类同样的有参构造。也就是说如果父类没有无参构造方法,那么子类的构造方法会出现什么现象?怎么解决?

(1) 直接在父类中添加一个无参构造。

(2) 子类在构造方法中通过使用super去显示调用父类其它的构造方法。(在子类的无参有参中都调用父类的有参构造,并给个值)

(3) 子类通过this去调用本类的其它构造方法。而被调用的那个子类中一定去访问了父类的构造方法,否则父类数据就没有初始化。

注意一点:this(…)或者super(…)语句必须写在构造器的第一行。为什么?如果不显示写出super(),会有一个默认的空的super()进行初始化,你如果在一些语句后又显示写了一个super(),那你要再一次初始化吗?

5.6.5题目:

做题之前,我先把注意点重复一下。(1)成员变量取值,有一个就近原则。(2)this,super分别指的是访问哪里的成员?(3)子类构造方法执行前默认先执行父类的构造方法(4)一个类的初始化过程是什么来着?先对成员变量进行初始化:默认初始化—显示初始化—构造方法初始化。

5.6.5.1题目一:

class Father{public int num = 3;public Father(){System.out.println("father");}}class Son extends Father{public int num = 4;public Son(){System.out.println("son");}public void print(){int num = 5;System.out.println(num);System.out.println(this.num);System.out.println(super.num);}}class ExtendsTest {public static void main(String[] args) {Son s = new Son();s.print();}}
5.6.5.2题目二:
class Father {static {System.out.println("静态代码块Father");}{System.out.println("普通代码块Father");}public Fu() {System.out.println("构造方法Father");}}class Zi extends Fu {static {System.out.println("静态代码块Zi");}{System.out.println("普通代码块Zi");}public Zi() {System.out.println("构造方法Zi");}}class ExtendsTest2 {public static void main(String[] args) {new Zi();}}父类静态代码块子类静态代码块父类普通代码块父类构造器子类普通代码块子类构造器
5.6.5.3题目三:

我们说过了一个类的初始化过程,而B b = new B();这是一个引用类型的成员变量。那么看一下下面这个题。

class A {A() {System.out.print("A");}B b = new B();}class B {B() {System.out.print("B");}}public class C extends A {B b = new B();C() {//super();System.out.print("C");}public static void main(String[] args) {new C(); //}}

虽然我们也说过了初始化的过程。但子父类初始化是一个分层初始化。虽然子类中构造方法有一个super();,但初始化的时候不是按照之前顺序执行的,而是按照分层初始化进行的,它仅仅表示要先初始化数据,再初始化子类数据。

所以先把父类A初始化完毕,输出BA,再初始化子类,打印BC。

5.6.5.4题目四:(多态后做)

class A {public String show(D obj) {return ("A and D");}public String show(A obj) {return ("A and A");}}class B extends A {public String show(B obj) {return ("B and B");}public String show(A obj) {return ("B and A");}}class C extends B {}class D extends B {}public class Demo1 {public static void main(String[] args) {A a1 = new A();A a2 = new B();B b = new B();C c = new C();D d = new D();System.out.println(a1.show(b));System.out.println(a1.show(c));System.out.println(a1.show(d));System.out.println(a2.show(b));System.out.println(a2.show(c));System.out.println(a2.show(d));System.out.println(b.show(b));System.out.println(b.show(c));System.out.println(b.show(d));}}答案:A and AA and AA and DB and AB and AA and DB and BB and BA and D
5.6.5.5题目五:

Override和Overload的区别?

5.6.5.6题目五:

this关键字和super关键字的分别代表什么?以及他们各自的使用场景和使用。

标签: #java继承一个类可以被自定执行吗对吗