Java继承和多态

其实这几个名词之间都是有关联的,前面解释了类和对象,这篇来说继承和多态。
继承的意思,其实就跟实际中的继承差不多,子承父业对吧?
继承是针对类来说的,前面一节说我们把客观事物抽象为一个类,比如前一篇的“Person”类,那么这个类下面其实还可以按照不同的标准来分类,比如可以按年龄分成人和儿童,按性别分,按国籍分等等。
比如,无论成年人还是未成年人都是“Person”类的一种。

public class Adult extends Person {

}

public class Child extends Person {

}

关键字extends就表示“继承自”的意思。被继承的类叫做父类,比如“Person”。“Child”和“Adult”叫做子类。也叫派生类,它们是有关系的。父类所拥有的属性和方法子类全部拥有(这大概就是“继承“的意思吧)。在子类中使用super关键字即可访问到父类的属性和方法,甚至是构造器(注意如果父类中是private修饰的,即使是子类也不能访问,父亲也是有私有的秘密的哦)。其实,在子类中,总会有一个构造器会调用到父类的空参构造器的. 那么父类当中的属性在子类中怎么使用呢?很简单,父类中不是提供了public的get和set方法么,既然不能直接用super关键字访问那使用super.方法就可以了。

public class Child extends Person {//以Child举例
    private int age;//这里子类比父类多了一个属性年龄

    public Child(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return  "Child{" +	//这里重写了父类的toString方法
                "age=" + age +
                '}';
    }
}

如果子类里面存在和父类相同的方法签名,于是子类里的方法就会覆盖掉父类里面的方法,这就叫做方法的重写,在编译时,会根据具体的类型去决定调用那个方法。

   public static void main(String[] args) {
        Child child = new Child(18);
        System.out.println(child);
        System.out.println("name = " + child.getName());
        System.out.println("sex = " + child.getSex());
        System.out.println("weight = " + child.getWeight());
        System.out.println("height = " + child.getHeight());
        //可以看到child还是有父类的方法和属性的,这里只不过是默认值,当然还可以修改
        child.setName("tommy");
        System.out.println("name = " + child.getName());
        /*运行结果:
        Child{age=18}
		name = null
		sex = null
		weight = 0
		height = 0
		name = tommy	
        */
    }

于是,子类里面的toString方法还可以这么写:

    @Override
    public String toString() {
        return "name = " + super.getName() + ",sex = " + super.getSex() +
                ",weight = " + super.getWeight() + ",height = " + super.getHeight() + 
                ",age = " + age;
    }
    //上面代码就可以修改为:
        public static void main(String[] args) {
        Child child = new Child(18);
        System.out.println(child);
        child.setName("tommy");
        System.out.println(child);
   		}
/*于是上面代码的运行结果是:
name = null,sex = null,weight = 0,height = 0,age = 18
name = tommy,sex = null,weight = 0,height = 0,age = 18
*/

还有一点就是类之间是可以继承多层的,像上面,子类其实还是可以有子类的,只要愿意可以一直继承下去,但是实际中往往不会写这么多层,多了容易乱,类太多会产生“类爆炸”的问题。
如果“Child”还有一个子类叫做“Baby”,它相对于“Person”而言还是子类,并不是“孙子类”,“Person”也不是”爷爷类“,虽然关系上好像是这样,但是它们还是子类和父类的关系。
有些类,如果不希望它再派生出子类,可以在定义时加上一个关键字“final”来阻止继承,表示这个类不能被继承了。而在jdk源码中,String类其实就是“final”修饰的。
官方文档入口(Java8)
而类之间的这种继承性则可以体现多态,比如:

public class Child extends Person {
    private int age;

    public Child(String name, String sex, int age) {
        super(name, sex);
        this.age = age;
    }

    public Child(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "name = " + super.getName() + ",sex = " + super.getSex() +
                ",weight = " + super.getWeight() + ",height = " + super.getHeight() +
                ",age = " + age;
    }

    public static void main(String[] args) {
    	Person tom = new Child("Tom","boy",18);
    }
}

这个主方法里的代码似乎有点奇怪,定义的时候明明声明了一个”Person“类的变量,但是实际new的时候确是new了一个”Child“类的实例,左右两边看起来”好像“定义的数据类型与实际创建出来的数据类型并不匹配,Java不是强类型吗?这样写真的没有什么问题吗?
这就是Java的多态性了。这样写是完全OK的,而实际中也基本上都是这么写的。一个父类引用指向一个子类实例,这个叫做”向下转型“。在代码编译的时候会根据具体的类型来执行子类或者父类的代码。然而事实上,这样写的时候在调用子类的构造方法时,前面说到总会有一个构造器会调用到父类的空参的构造器,这也就是为什么子类没有声明父类的结构而会具有父类的结构,在这里虽然调用了父类ed构造器,但是实际上是没有创建父类对象的(反正是引用不到这个父类对象的).在Java中,使用父类引用指向子类实例这是很常见的操作。而使用子类引用指向父类实例这样的操作也是有的,叫做向上转型,但是这很少见,用的地方特别少(比如Java设计模式的原型模式里有个深拷贝,而这个操作可能会用到向上转型,注意是可能,意思就是不用也是可以的),既然用的极少,基础部分也就不说这个了,不然又是一堆。除了这种转型能体现多态之外,像后面的抽象类和接口也是建立在多态之上的(后面再说)。而在后续开发中,多态更是见怪不怪了。无论继承关系有多少层,只要是父类,那么就可以指向子类对象。
父类和子类的关系我们可以用“has a”来理解,就是有一个,就是指父类有一个子类;而子类和父类的关系则可以用“is a”来形容,就是子类是一种父类。Java是单继承的,一个父类可以有多个子类但是子类只能直接继承自一个父类,比如上面“Baby”类,虽然“Child”是它的父类,“Person”也是它的父类,但是“Baby”只是间接继承了“Person”类,它是直接继承自“Child”的,并不直接继承自“Person”,所以不能说它有两个父类,在Java中只能直接继承自一个父类。
Java语言面向对象的三大特性:封装,继承,多态我暂时就想到这么多了,也大概就这么多,遇到新知识再说。后面还有一篇关于抽象类和接口的叙述,也是非常爱考的。
欢迎指正。。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值