Java——类的继承。
什么是类的继承:
我们知道,在java中的一切语句都在类中执行。然而,当我们在定义了一个类并设置好了所有属性后需要创建一些对象,而有时候我们发现,有时候我们需要创建一些特殊的对象,他们拥有类中的属性,可以执行类中的方法,但又有一些独特的特点。
凭我们的经验知道,同一类中的元素虽然都满足本类的条件却常常大相径庭。例如,我们可以说有生命都属于生物类,生物都会呼吸,但有的微生物有氧呼吸,有的生物无氧呼吸,鱼用腮呼吸,陆地生物大多用肺呼吸,不能一概而论。为了把他们的各种特点区分,科学家们把生物分为微生物,动物和植物,把微生物分为细菌,真菌,病毒。把动物分为哺乳动物与卵生动物……在程序中像这样创建一个子类来继承父类的属性以及方法(函数)的行为就叫作类的继承。显然,不管我们如何把这些动物分类,他们仍旧满足作为生物的所有属性,我们可以将此推广到java中,描述为子类可以调用父类中的所有属性与方法。
注意:以上例子只为帮助读者有一个具象化的,简单的理解,在实际的java中仍有许多不同
例如:java中父类的私有属性和函数不可被子类直接使用。
因此,若我们想对java中类的继承有一个正确的理解,真正在ide中实现其功能是必不可少的。
请各位看接下来的例子,并尝试用相似的逻辑自己体验一下类的继承。
在java中实现类的继承:
在了解继承的概念后我们看看具体的代码该如何实现。首先我们创建一个类作为父类,就以creature(生物)为例,每个类都默认继承Object类。
public class creature /此处可以加 extends Object/{ private String name;
protected void setName(String n) { name=n; } public void getName() { System.out.println(name); } }
我们创建了一个名为creature的类,并给他设置了一个设置名字的函数与一个显示名字的函数。
然后,我们再创建一个名为bird的类来继承这个类。
创建的格式为
访问修饰符 class 子类名 extends 父类名。(implements 接口 接口)
public class bird extends creature{//这里并没有用上接口,自然没有上述的implements。 public bird(){ }
可以看出,此时我们并未为他创建属性,我们在Main函数下创建一个bird的对象看看。
public class Main { public static void main(String[] args) { bird cockatoo = new bird(); cockatoo.setName("Cockatoo"); cockatoo.getName(); } }
此时我们创建的cockatoo是bird的对象,他调用了creature中的函数,并通过此函数间接访问了被标为private的属性name。印证了前面所述的子类可以调用父类中的所有属性与方法。
这样便实现了类的继承中最基本的操作。然而关于继承的内容仍有很多。
子类的函数重载:
在实际的java编程中子类中常常用到与父类中功能相似,但又有不同的函数,遇到这种情况,我们并不再额外创建一个函数,而是进行函数重载。
函数重载有两个要求:
1.有继承关系的两个类之间 2.(访问修饰符大于等于父类)返回值类型,方法名,参数类型(个数,顺序)完全一样
我们现在在creature中直接添加一个名为eat的函数,并在bird类中重写此函数。
public class creature { private String name; cted void setName(String n) { name=n; } public void getName() { System.out.println(name); } public void eat(){ System.out.println(name+"吃食物:"); } }
public class bird extends creature{ public void eat(){ System.out.println("吃种子"); } }
结果:
不过这个程序目前只运行了子类中的函数,此处我们再介绍一种前缀 super 它表示的是当前类的父类的对象(不具有实体)可以在函数被重载的情况下,在子类中调用父类被重载的函数。
public class bird extends creature{ public bird(){ super("magpie"); } public void eat(){ super.eat(); System.out.println("吃种子"); } }
可以看见,当我们加入了一个名为super的对象后程序成功地调用了父类的函数。
构造函数:
Java中的构造函数是一种特殊的函数,用于初始化对象。Java构造函数在对象创建时被调用。它构造值,即提供对象的数据。与函数名相同,无返回值。在子类中的构造函数必须要调用一次父类中的构造函数。这个函数让属性与其他一般函数在其余类中得以被调用
Java类创建时,系统会自动生成一个默认构造函数,不返回值,且子类中的构造函数会自动调用父类的默认构造函数。
public class creature { private String name; public creature(String name){ this.name = name; } public creature(){ }
如图我们此时在creature中手动构建了构造函数,可以看到bird类因此报错。就是因为bird只能默认调用无参的构造函数,我们可以自己在子类中调用它并传入参数来避免这个错误。
public bird(){ super("magpie"); }
上面的在bird类中的操作就是在子类中重新调用构造函数,之后程序不再报错且可以正常运行。
更稳妥的方法是在父类的构造函数下再构建一个无参的构造函数,这样就不必在每个子类的构造函数中调用父类构造函数。
public class creature { private String name; public creature(String name){ this.name = name; } public creature(){ //此处就是重新构建构造函数。 }
自动转型与强制转型:
我们知道,所谓的类也是一种数据类型,因此我们。类比一下其他数据类型的自动转化与强制转化,当我们用int型的值与一个double类型进行运算时,int会被自动转化为double。而我们也可以用(double)a来将int a转化为double a。类的对象的自动转型与之相当类似。除了类似于只值运算的某些情况不用我们操作他们就会自己自动转型,我们还可以通过一下方法手动“自动转型”
父类 对象名 = new 子类()
creature magpie=new bird();//此处的代码位于Main中
像这样我们就成功创建了一个被自动转型为bird的creature对象。我们来调用子类重写过的eat函数试试。
可以注意到,父类与子类中的函数均被调用。
我们再在creature中创建一个名为move的函数并让mapgie对象尝试调用它。
public creature(){ } public void titlename() { System.out.println(name); } protected void setName(String n) { name=n; } public void getName() { System.out.println(name); } public void eat(){ System.out.println(name+"吃食物:"); } public void move(){ //在此处定义. System.out.println("climb"); } }
结果我们发现move无法被调用,这是因为自动转型后该对象只能调用子类中重写的函数。
想要解决这个问题,我们就必须做得绝一点,用强制转型!其格式为
目标类名 新对象 =(目标类名)被转对象
结构与常见的数值类的数据类型的强制转化十分相似。不过强制转型的对象必须经过自动转型。
bird magpies=(bird)magpie; magpies.move();
在强制转型之后,新的对象成功地调用了move函数。
总结:
类的继承是java的类相关知识中极为重要的一环,在java的编程中应用场景非常广,在学会概念之后,务必多练多尝试,这样才能真正掌握java这门语言。