在学习继承后,很多同学会混淆:继承后重载,重写和多态的问题,我就写了一个小程序对下面对几个事情进行下解释。
我建议不理解或则有疑惑的地方,可以自己写个类测试一下就会明白其中的含义。
有些图由于csdn网站的原因,一直显示服务器存在错误,我明天再次上传。
1.首先大家需要先理解重载和重写对定义。
我简单对介绍一下哈,重载就是发生在一个类中,同名函数但是不同参数的多个函数的称呼。而重写就是发生在继承之后,子类重写了父类的一些函数,子类可能因为某些原因认为父类函数过于抽象等原因,进行重写。
二者的区别如下:
下面的例子可以很好的解释我刚的话
参考:https://www.quora.com/What-is-the-difference-between-overload-and-override
2. 用代码来解释一些问题
2.1对继承后,构造函数的理解
如果父类的变量是public修饰时,会被子类继承,那么子类的构造函数的写法就要注意,因为要取决于父类的写法。
2.1.1
先简单的写个父类:都是public修饰,并且只有一个有参的构造函数。
public class Dog { public String name; public Dog(String name) { this.name = name; } //只有一个代参的构造函数时 public Dog(String name) { this.name = name; } }
讯享网
子类对其进行继承后,对几种构造函数的解释。
讯享网package helloword; public class hund extends Dog{ public int size; //对构造函数的解释 //空参数---会报错,因为hund继承了Dog的name,因此它的构造函数一定是有参数的, public hund() { } // 当构造函数只有一个String是可以的,那么默认,在使用的时候,hund中定义的size就是0,不可以是别的值 public hund(String name) { //调用Dog的构造函数 super(name); } //错误,没有name的定义 public hund(int size) { this.size = size; } //正确 public hund(String name,int size) { super(name); this.size = size; } }
测试:
public static void main(String args[]) { hund h1 = new hund(); // 报错 hund h2 = new hund("dog"); // name = dog ;size = 0; hund h3 = new hund(2); //报错 hund h4 = new hund("luckly",2); name = luckly size = 2 }
也就是说使用hund 的实例的时候,必须有name的传参,但是这主要取决于父类Dog的构造函数,只有一个带参数的name
2.1.2
但是如果Dog的构造函数如下,添加一个无参构造函数时,结果就不同。
讯享网package helloword; public class Dog { public String name; private double price; public Dog() { } public Dog(String name) { this.name = name; } public void eat() { System.out.print("eat food"); } public void drink() { System.out.print("drink water"); } }
hund类如下,则都可以声称和运行。
package helloword; public class hund extends Dog{ public int size; //对构造函数的解释 public hund() { } // 当构造函数只有一个String是可以的,那么默认,在使用的时候,hund中定义的size就是0,不可以是别的值 public hund(String name) { //调用Dog的构造函数 super(name); } public hund(int size) { this.size = size; } public hund(String name,int size) { super(name); this.size = size; } public static void main(String args[]) { hund h1 = new hund(); System.out.print(h1.size); System.out.print(h1.name); hund h2 = new hund(2); hund h4 = new hund("luckly",2); } }
2.1.3 子类对实例优先调用父类对构造函数
父类如下:
讯享网package helloword; public class Dog { public String name; private double price; public Dog() { System.out.println("我是父类无参构造函数"); } public Dog(String name) { this.name = name; System.out.println("我是父类有参构造函数"); } }
子类:
package helloword; public class hund extends Dog{ public int size; //对构造函数的解释 public hund() { System.out.println("我是子类无参构造函数"); } // 当构造函数只有一个String是可以的,那么默认,在使用的时候,hund中定义的size就是0,不可以是别的值 public hund(String name) { //调用Dog的构造函数 super(name); System.out.println("我是子类有参name构造函数"); } public hund(int size) { this.size = size; System.out.println("我是子类有参size构造函数"); } public hund(String name,int size) { super(name); this.size = size; System.out.println("我是子类有参size+name构造函数"); } public static void main(String args[]) { hund h1 = new hund(); hund h2 = new hund(2); hund h4 = new hund("luckly",2); } }
测试:
讯享网我是父类无参构造函数 我是子类无参构造函数 我是父类无参构造函数 我是子类有参size构造函数 我是父类有参构造函数 我是子类有参size+name构造函数
2.2 重写和重载
2.2.1 普通重写
父类定义了一个函数eat
public class Dog { public String name; public Dog(String name) { this.name = name; } public void eat() { System.out.print("我是父类的eat函数"); } }
子类重写了这个函数:
讯享网package helloword; public class hund extends Dog{ public int size; public hund(String name,int size) { super(name); this.size = size; } public void eat() { System.out.println("我是子类的eat函数"); } public static void main(String args[]) { hund h4 = new hund("luckly",2); h4.eat(); } }
在h4调用eat函数的时候,观察结果是调用了子类的函数,而不是父类的,输出结果如下:
我是子类的eat函数
结论:通过这里例子可以发现,其实重写就是覆盖了父类的eat函数,但是如果定义的是父类的子类,肯定父类的eat函数还是可以使用的。
2.2.2 重载和重写
当我们把子类的eat函数,添加一个int的参数时,调用eat(),就是调用父类的eat()了,而调用eat(2)就是调用子类的eat(int temp)函数
父类:
public class Dog { public String name; public Dog(String name) { this.name = name; } public void eat() { System.out.println("我是父类的eat函数"); } }
子类;
讯享网public class hund extends Dog{ public int size; public hund(String name,int size) { super(name); this.size = size; } public void eat(int temp) { System.out.println("我是子类的eat函数:我吃了"+temp+"食物"); } public static void main(String args[]) { hund h4 = new hund("luckly",2); h4.eat(); h4.eat(2); } }
结果:
我是父类的eat函数
我是子类的eat函数:我吃了2食物
结论:其实本质上讲,子类继承了父类的eat(),但是写了一个eat(int temp)也就是带参数的函数,那么这里的eat()就不是重写了,而是重载了。所以当使用h4.eat()的时候,调用的其实是父类的eat(),而使用h4.eat(2)的时候,就是使用子类自己定义的函数。
其实子类也函数在运行的时候可以理解成如下的形式,而eat()是父类给它的
public class hund extends Dog{ public int size; public String name; public hund(String name,int size) { super(name); //这里的super(name)就是调用父类public Dog(String name)函数,这里没法加入 this.size = size; } public void eat() { System.out.println("我是父类的eat函数"); } public void eat(int temp) { System.out.println("我是子类的eat函数:我吃了"+temp+"食物"); } public static void main(String args[]) { hund h4 = new hund("luckly",2); h4.eat(); h4.eat(2); } }
2.3. 多态
2.3.1 普通多态
父类:
讯享网public class Dog { public String name; public Dog(String name) { this.name = name; } public void eat() { System.out.println("我是父类的eat函数"); } public void drink() { System.out.println("我是子类的drink函数"); } }
子类:
package helloword; public class hund extends Dog{ public int size; public hund(String name,int size) { super(name); this.size = size; } // drink函数重写 public void drink() { System.out.println("我是子类的drink函数"); } // eat函数重载 public void eat(int temp) { System.out.println("我是子类的eat函数:我吃了"+temp+"食物"); } public static void main(String args[]) { Dog h4 = new hund("luckly",2); h4.eat(); h4.drink(); } }
结果:
我是父类的eat函数
我是子类的drink函数
但是如果使用下面的语句,会报错:
h4.eat(2);
结论:eat是重载的,因此调用的肯定是父类的eat函数,drink是重写的,调用的肯定是子类重写之后的函数
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
3. 经典案例分析
下面来看一个经典的案例
讯享网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
解释:
其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
首先解释下第二个,a1.show(c),为什么是 A-A
因为根据优先级,会先找A类的show(C),但是函数不存在,而A类的super函数是object,所以第二个super.show(C)也是没有的。然后就是看第三个,this.show((super)C),因为C继承B,B继承A,因此AB都是C的父类。因此就调用A类的函数:public String show(A obj)。
下面的都同理!!
参考:https://www.cnblogs.com/chenssy/p/3372798.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/23709.html