Java 继承与多态
1.父类与子类
子类从它的父类中继承可访问的数据域和方法,还可以添加新数据域和新方法。
父类中的私有数据域在该类之外是不可访问的。因此,不能在子类中直接使用。但是,如果父类中定义了公共的访问器 / 修改器,那么可以通过这些公共的访问器 / 修改器来访问和修改它们。
2.super关键字
语句 super() 调用父类的无参构造方法,而语句 super (arguments) 调用与参数匹配的父类的构造方法。语句 super() 和 super (arguments) 必须出现在类构造方法的第一行,这是显式调用父类构造方法的唯一方式。
构造方法可以调用重载的构造方法或父类的构造方法。如果它们都没有被显式地调用,编译器就会自动地将 super() 作为构造方法的第一条语句。
public class Faculty extends Employee {
public static void main(String[]args){
new Faculty();
}
public Faculty() {
System.out.println("(4) Performs Faculty's tasks");
}
}
class Employee extends Person {
public Employee(){
this("(2)Invoke Employee's overloaded constructor");
System.out.println("(3)Performs Employee's tasks ");
}
public Employee(String s){
System.out.println(s);
}
}
class Person {
public Person() {
System.out.println("(l)Performs Person's tasks");
}
}
/* 输出
(1) Performs Person's tasks
(2) Invoke Employee' s overloaded constructor
(3) Performs Employee's tasks
(4) Performs Faculty's tasks
*/
关键字 super 不仅可以引用父类的构造方法,也可以引用父类的方法。所用语法如下:
super.方法名(参数);
3.方法重写
·仅当实例方法是可访问时,它才能被覆盖。因为私有方法在它的类本身以外是不能访问的,所以它不能被覆盖。如果子类中定义的方法在父类中是私有的,那么这两个方法完全没有关系。
·与实例方法一样,静态方法也能被继承。但是,静态方法不能被覆盖。如果父类中定义的静态方法在子类中被重新定义,那么在父类中定义的静态方法将被隐藏。可以使用语法:父类名 .静态方法名( SuperClassName.staticMethodName) 调用隐藏的静态方法。
方法重写与方法重载不同 要主要区分:
• 方法重写发生在通过继承而相关的不同类中;方法重载可以发生在同一个类中,也
可以发生在由于继承而相关的不同类中。
•方法重写具有同样的签名和返回值类型;方法重载具有同样的名字,但是不同的参
数列表。
4.多态
(1)子类重写父类的方法。使子类具有不同的方法实现。
(2)把父类类型作为参数类型,该父类及其子类对象作为参数转入。
(3)运行时,根据实际创建的对象类型动态决定使用那个方法。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
5.动态绑定
所谓动态绑定,通俗的是指,对象在调用方法的时候能够自己判断该调用谁的方法。所以动态绑定一般发生在继承、方法重载时。
那么发生方法重载时,编译器如何确定调用的方法呢,例如,调用c.f(arg)时,首先需要将c声明为B类的对象,此时,如果在B类中,存在多个f方法,只是f的参数类型不同,调用f(int)或者f(String)时。编译器会注意列举B类中所有名为f的方法以及B类超类中的访问权限为public的名为f的方法。如果存在与c.f(arg)中arg类型相匹配的方法,那么就调用这个方法。由此,调用哪个方法隐式参数的实际类型。这个过程就是一个动态绑定的过程。
package chapeter04;
class Test
{
public Test() { }
public void setName(String n)
{
this.name=n;
System.out.println("在父类中");
}
public String getName()
{
return this.name;
}
private String name;
}
public class Sample4_12 extends Test
{
public void setArea(String a)
{
this.area=a;
}
public String getArea()
{
return this.area;
}
public static void main(String[] args)
{
// TODO Auto-generated method stub
Sample4_12 child = new Sample4_12();
Test test []=new Test[2];
test[0]=child;
test[0].setName("silence");
test[1]=new Test();
}
private String area;
}
/*
运行结果:
在父类中
*/
上面的例子执行过程如下:
查看test[0]声明类型,即Sample4_12 类,然后获得方法名 setName ,接着把PolymorphicTest 类中的所有名为setName的public方法列举出来。若没有名为setName的方法,则调用失败,否则转换到2。
根据调用方法的参数类型来对上一步列出来的所有方法进行匹配,直到找到一个匹配的转到3,否则匹配失败。
若test[0]所指向(refer to)的对象的类型为其一个子类,则需要查看子类有没有覆盖该方法,若有,则执行子类中的方法。
如果这个方法是private、static、final类型的,就不用进行动态绑定了,因为编译器可以很准确的知道要调用那个方法。且查询匹配方法时,是按照继承树逐级向上查找的,直到找到第一个匹配的方法为止。
但是由于Java中允许类型转换,所以寻找一个合适的方法是个复杂的过程,如果编译器没有找到合适的方法,或者发现类型转换后有多个方法与之匹配,则编译器会报错。
6.incetanceof
instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
1.类的实例包含本身的实例,以及所有直接或间接子类的实例
2.instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误。
下面是一个完整的样例
package sample;
public class person{
public String name;
public int age;
public person(String a,int b) {
name = a;
age = b;
}
public void eat() {
System.out.println(this.name+"吃");
}
public void sleep() {
System.out.println(this.name+"睡");
}
public void work() {
System.out.println(this.name+"工作");
}
public void show() {
this.eat();
this.sleep();
this.work();
}
}
package sample;
public class master extends person{
public master(String a,int b) {
super(a,b);
}
public void work() {
System.out.println(this.name+"练功");
}
}
package sample;
public class student extends person{
public student(String a,int b) {
super(a,b);
}
public void work() {
System.out.println(this.name+"学习");
}
}
package sample;
public class test {
public static void main(String[] args) {
show(new student("田所浩二",24)); // 以 学生 对象调用 show 方法
show(new master("马保国",69)); // 以 大师 对象调用 show 方法
person a = new student("田所浩二",24); // 向上转型
a.eat(); // 调用的是 学生 的 eat
student c = (student)a; // 向下转型
c.work(); // 调用的是 学生 的 work
}
public static void show(person a) {
// 类型判断
if (a instanceof student) { // 学生做的事情
student c = (student)a;
c.show();
} else if (a instanceof master) { // 大师做的事情
master c = (master)a;
c.show();
}
}
}
输出结果为:
田所浩二吃
田所浩二睡
田所浩二学习
马保国吃
马保国睡
马保国练功
田所浩二吃
田所浩二学习