继承是为了重用父类代码。两个类若存在IS-A的关系就可使用继承。同时继承也为实现多态作了铺垫。php
多态就是指程序中定义的引用变量所指向的具体类型和经过该引用变量发出的方法调用在编程时并不肯定,而是在程序运行期间才肯定,即一个引用变量倒底会指向哪一个类的实例对象,该引用变量发出的方法调用究竟是哪一个类中实现的方法,必须在由程序运行期间才能决定。由于在程序运行时才肯定具体的类,这样,不用修改源程序代码,就可让引用变量绑定到各类不一样的类实现上,从而致使该引用调用的具体方法随之改变,即不修改程序代码就能够改变程序运行时所绑定的具体代码,让程序能够选择多个运行状态,这就是多态性。java
多态,简而言之就是同一个行为具备多个不一样表现形式或形态的能力。好比说,有一杯水,我不知道它是温的、冰的仍是烫的,可是我一摸我就知道了。我摸水杯这个动做,对于不一样温度的水,就会获得不一样的结果。这就是多态。
编程
对于java而言,多态的实现机制遵循一个原则:当父类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,可是这个被调用的方法必须是在父类中定义过的,也就是被子类覆盖的方法。bash
子类引用的对象转换成父类类型成为向上转型。通俗的说就是将子类对象转成父类对象。此处父类对象能够是接口。ui
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void run(){
System.out.println("我会跑");
}
}
public class Main {
public static void main(String[] args) {
animal = new Dog();//向上转型
animal.eat();
}
}复制代码
输出:狗吃骨头复制代码
这就是向上转型,Animal animal = new Dog();将子类对象Dog转化为父类对象Animal。这个时候animal这个引用调用的方法是子类方法。
this
animal.run()
会报错。Dog d = (Dog)new Animal()
这样是不行的。与向上转型相对应的就是向下转型了。向下转型是把父类对象转为子类对象。(请注意!这里是有坑的。)
spa
//仍是上面的animal和cat dog
Animal a = new Cat();
Cat c = ((Cat) a);
c.eat();
//输出 我吃鱼
Dog d = ((Dog) a);
d.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Cat cannot be cast to com.chengfan.animal.Dog
Animal a1 = new Animal();
Cat c1 = ((Cat) a1);
c1.eat();
// 报错 : java.lang.ClassCastException:com.chengfan.animal.Animal cannot be cast to com.chengfan.animal.Cat
复制代码
为何第一段代码不报错呢,由于a自己就是Cat对象,因此固然能够转型为Cat,由于是Cat因此不能转为Dog。code
而a1是Anmail对象,它不能向下转型Wie任何子类对象。好比发现一个古生物化石,知道它是一种动物,但你不能直接说他是猫或者他是狗。对象
向下转型注意事项继承
向下转型只能转型为本类对象(猫是不能变成狗的)。
instanceof 关键字:instanceof是Java、php的一个二元操做符(运算符),和==,>,<是同一类东西。因为它是由字母组成的,因此也是Java的保留关键字。它的做用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据。能够用来判断继承中的子类的实例是否为父类的实现。
instanceof通常放在类型转换的前面,合理规避异常产生!
public void eat(Animal a){
/*
* 向下转型(强制转型)
* 子类引用指向父类的实例(对象),此处必须今习惯强制类型转换
* 该实例能够调用子类特有的方法
* 必须知足转型条件才能转换(),子类间不能随意强制转换,可是子类引用指向父类实例,能够强制转换
* instanceof运算符:返回true/false,
*/
if(a instanceof Dog){
Dog d = (Dog)a;
d.eat();
d.run();//狗有一个跑的方法
}
if(a instanceof Cat){
Cat c = (Cat)a;
c.eat();
System.out.println("我也想跑,可是不会"); //猫会抱怨
}
a.eat();//其余动物只会吃
}
eat(new Cat());
eat(new Cat());
eat(new Dog());复制代码
向下转型花木兰替父亲花弧从军。那么这时候花木兰是子类,花弧是父类。花弧有本身的成员属性年龄,姓名,性别。花木兰也有这些属性,可是很明显两者的属性彻底不同。花弧有本身的非静态成员方法‘骑马杀敌’,一样花木兰也遗传了父亲同样的方法‘骑马杀敌’。花弧还有一个静态方法‘自我介绍’,每一个人均可以问花弧姓甚名谁。同时花木兰还有一个本身特有的非静态成员方法‘涂脂抹粉’。可是,如今花木兰替父从军,女扮男装。这时候至关于父类的引用(花弧这个名字)指向了子类对象(花木兰这我的),那么在其余类(其余的人)中访问子类对象(花木兰这我的)的成员属性(姓名,年龄,性别)时,其实看到的都是花木兰她父亲的名字(花弧)、年龄(60岁)、性别(男)。当访问子类对象(花木兰这我的)的非静态成员方法(骑马打仗)时,其实都是看到花木兰本身运用十八般武艺在骑马打仗。当访问花木兰的静态方法时(自我介绍),花木兰本身都是用她父亲的名字信息在向别人做自我介绍。而且这时候花木兰不能使用本身特有的成员方法‘涂脂抹粉’。
-----多态中的向上转型 那么终于一将功成万骨枯,打仗旗开得胜了,花木兰告别了战争生活。有一天,遇到了本身心爱的男人,这时候爱情的力量将父类对象的引用(花弧这个名字)强制转换为子类对象原本的引用(花木兰这个名字),那么花木兰又重新成为了她本身,这时候她彻底是她本身了。名字是花木兰,年龄是28,性别是女,打仗依然那样生猛女汉子,自我介绍则堂堂正正地告诉别人我叫花木兰。OMG!终于,终于可使用本身特有的成员方法‘涂脂抹粉’了。今后,花木兰彻底回到了替父从军前的那个花木兰了。而且和本身心爱的男人幸福的过完了一辈子。-----多态中的向下转型
你们记得哈,向上转型向下转型必定是在多态这个前提下哈,不然强制将女儿变成父亲,或者将父亲变成女人,就变成东方不败了,系统此时就会报错非法类型转换。哈哈哈哈哈。另外开发中通常是利用多态声明形式参数,并将建立子类的匿名对象做为实际参数。以上。
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
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("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}复制代码
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D复制代码
分析这个题须要记住如下几点
当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,
引用变量类型决定可调用的方法。若是子类中没有覆盖该方法,那么会去父类中寻找。复制代码
先看一个例子
class X {
public void show(Y y){
System.out.println("x and y");
}
public void show(){
System.out.println("only x");
}
}
class Y extends X {
public void show(Y y){
System.out.println("y and y");
}
public void show(int i){
}
}
class main{
public static void main(String[] args) {
X x = new Y();
x.show(new Y());
x.show();
}
}
//结果
//y and y
//only x
复制代码
其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、
this.show((super)O)、super.show((super)O)。复制代码
Y继承了X,覆盖了X中的show(Y y)方法,可是没有覆盖show()方法。
这个时候,引用类型为X的x指向的对象为Y,这个时候,调用的方法由Y决定,会先从Y中寻找。执行x.show(new Y());,该方法在Y中定义了,因此执行的是Y里面的方法;
可是执行x.show();的时候,有的人会说,Y中没有这个方法啊?它好像是去父类中找该方法了,由于调用了X中的方法。
事实上,Y类中是有show()方法的,这个方法继承自X,只不过没有覆盖该方法,因此没有在Y中明确写出来而已,看起来像是调用了X中的方法,实际上调用的仍是Y中的。
这个时候再看上面那句难理解的话就不难理解了吧。X是引用变量类型,它决定哪些方法能够调用;show()和show(Y y)能够调用,而show(int i)不能够调用。Y是被引用对象的类型,它决定了调用谁的方法:调用y的方法。
abcd的关系是这样的:C/D ---> B ---> A
本篇文章的内容大致上就是这些了。咱们来总结一下。