-
引入:
-
子类可以继承父类中的所有属性和方法,包括private修饰的属性和方法;但是子类只是拥有父类private修饰的属性和方法,却不能直接使用它,也就是无法直接访问到他们(子类可以通过调用父类的public声明的get方法来获取父类的private属性,但无法访问父类的private方法)
-
同时子类可以对继承的方法进行重写,并且新建自己独有的方法
向上转型
假设有一个Fruit类,Fruit类中有一个show()方法,代码如下:
public class Fruit { public void show(){ System.out.println("this is a fruit!"); } }
有一个Apple类继承自Fruit类,该类有自己的方法eat(),并且重写了父类的show()方法,代码如下:
public class Apple extends Fruit{ @Override//重写标志!!! public void show(){ System.out.println("this is a apple!"); } public void eat(){ System.out.println("要多吃苹果!"); } }
实例化Apple类,并新建一个Fruit类的引用变量引用该实例,调用实例的show()方法:
public class Test { public static void main(String[] args) { /*父类的引用指向子类!方法的调用只和左边、定义的数据类型有关*/ Fruit fruit = new Apple();//子类重写父类的方法 fruit.show();//this is a apple! System.out.println("=========="); fruit.eat();//报错!!!必须是继承父类的方法 } }
分析:这里用到了向上转型!就是用父类的引用变量去引用子类的实例,这是允许的。当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法。上面举例中由于子类重写了父类的show()方法,所以调用的show()方法是子类的show()方法,输出结果为:“this is a apple”而调用子类的eat()方法则会报错!
以上两张图简单总结规律:
-
看有没有继承标志@Override!!!需要注意的是没有这个标志,但方法完全一致,不叫重写!必须有标志
-
如果没有继承关系:父类的引用指向不了子类,就调用的自己本身(父类)的方法
-
有继承关系:父类的引用指向子类,调用继承自父类的方法(方法被重写)
向下转型
并不是所有的对象都可以向下转型,只有当这个对象原本就是子类对象通过向上转型得到的时候才能够成功转型。
实例化Apple类,并新建一个Fruit类的引用变量“fruit”引用该实例,然后新建一个Apple类的引用变量,引用向下转型的“fruit”变量,代码如下:
Fruit fruit = new Apple(); Apple apple = (Apple) fruit;
上述代码是允许的,因为fruit引用的对象原本就是Apple对象向上转型得到的,在对fruit向下转型后得到的还是Apple类的对象,能够被Apple类的引用变量引用。
假设有一个Orange类继承自Fruit类,代码如下:
public class Orange extends Fruit { @Override public void show(){ System.out.println("this is a orange"); } public void test(){ System.out.println("I am a orange"); } }
实例化Apple类,并新建一个Fruit类的引用变量“fruit”引用该实例,然后新建一个Orange类的引用变量,引用向下转型的“fruit”变量,代码如下:
Fruit fruit = new Apple(); Orange orange = (Orange) fruit;
上述代码虽然能够编译成功,但是在运行的时候会报错,因为fruit对象是由Apple对象向上转型得到的,只能够向下转型成Apple对象,不能够向下转型成Orange对象。
转型的好处
通过向上向下转型肯定是有好处的,比如可以减少编程代码。
假设在主类中定义了一个run()方法,该方法传入一个Fruit参数,并调用了Fruit对象的show()方法,代码如下:
public class Test { public static void main(String[] args) { run(new Fruit()); run(new Apple()); run(new Orange()); } public static void run(Fruit fruit){ fruit.show(); } } //this is a fruit! //this is a apple! //this is a orange
上述代码中,调用run()方法时的参数不仅是Fruit对象,也可以是Apple对象和Orange对象,当传入的是Apple对象和Orange对象时,就会向上转型成Fruit对象,但是调用的show()方法还是Apple对象和Orange对象的show()方法。这样就不需要在主类中同时重载三个run()方法,减少了代码量。