这篇文章主要介绍“重载和重写的区别有哪些”,在日常操作中,相信很多人在重载和重写的区别有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”重载和重写的区别有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
单一调度
class Parent { void print(String a) { log.info("Parent - String"); } void print(Object a) { log.info("Parent - Object"); } } class Child extends Parent { void print(String a) { log.info("Child - String"); } void print(Object a) { log.info("Child - Object"); } }
下面将会打印什么?
String string = ""; Object stringstringObject = string; // 打印什么? Child child = new Child(); child.print(string); child.print(stringObject); Parent parent = new Child(); parent.print(string); parent.print(stringObject);
答案:
child.print(string); // 打印: "Child - String" child.print(stringObject); // 打印: "Child - Object" parent.print(string); // 打印: "Child - String" parent.print(stringObject); // 打印: "Child - Object"
print(string)和 parent.print(string)是 Java 面向对象程序设计的教科书示例。被调用的方法取决于实际的实例类型,而不是声明的实例类型。例如,无论你将变量定义为 Child 还是 Parent,因为实际的实例类型是 Child,都将调用 Child: : print。
第二组则更为复杂,因为都是完全相同的字符串。唯一的区别是字符串被声明为 String,而 stringObject 被声明为 Object。在处理方法参数时,重要的是参数的声明类型,而不是它的实际类型。即使实际参数类型是 String,也会调用 print (Object)
隐式重写
class Parent { void print(Object a) { log.info("Parent - Object"); } } class Child extends Parent { void print(String a) { log.info("Child - String"); } }
打印什么?
String string = ""; Parent parent = new Child(); parent.print(string);
答案:
parent.print(string); // 打印: "Parent - Object"
实际的实例类型是 Child,声明的参数类型是 String,我们确实有一个为 Child: : print (String)定义的方法。实际上,这正是在前一个示例中调用 parent.print (string)时选择的内容。但是,这并不是在这里调用的方法。
在检查子类重写之前,Java 似乎首先选择要调用哪个方法。在这种情况下,声明的实例类型是 Parent,Parent 中唯一匹配的方法是 Parent: : print (Object)。然后,当 Java 检查 Parent: : print (Object)的任何潜在重写时,它没有找到任何重写,因此这就是执行的方法。
显式重写
class Parent { void print(Object a) { log.info("Parent - Object!"); } void print(String a) { throw new RuntimeException(); } } class Child extends Parent { void print(String a) { log.info("Child - String!"); } }
打印什么?
String string = ""; Parent parent = new Child(); parent.print(string);
答案:
parent.print(string); // 打印: "Child - String!"
这个示例与前面的示例之间的唯一区别是,我们添加了一个新的 Parent: : print (String)方法。这个方法实际上从来没有被执行过——如果它运行了,它会抛出一个异常!然而,它的存在使 Java 执行了一个不同的方法。
在计算 Parent.print (String)时,运行时现在找到一个匹配的 Parent: : print (String)方法,然后看到这个方法被 Child: : print (String)重写。
模糊参数
class Foo { void print(Cloneable a) { log.info("I am cloneable!"); } void print(Map a) { log.info("I am Map!"); } }
下面打印的是什么?
HashMap cloneableMap = new HashMap(); Cloneable cloneable = cloneableMap; Map map = cloneableMap; // What gets printed? Foo foo = new Foo(); foo.print(map); foo.print(cloneable); foo.print(cloneableMap);
答案:
foo.print(map); // 打印: "I am Map!" foo.print(cloneable); // 打印: "I am cloneable!" foo.print(cloneableMap); // 编译不通过
与单一调度示例类似,这里重要的是参数的声明类型,而不是实际类型。另外,如果有多个方法对于给定的参数同样有效,Java会抛出一个编译错误,并强制你指定应该调用哪个方法。
多重继承-接口
interface Father { default void print() { log.info("I am Father!"); } } interface Mother { default void print() { log.info("I am Mother!"); } } class Child implements Father, Mother {}
下面打印的是什么?
new Child().print();
与前面的示例类似,这个示例也编译不通过。具体地说,Child 的类定义本身将无法编译,因为在 Father 和 Mother 中存在冲突的缺省方法。你需要修改 Child 类指定 Child: : print 的行为。
多重继承-类和接口
class ParentClass { void print() { log.info("I am a class!"); } } interface ParentInterface { default void print() { log.info("I am an interface!"); } } class Child extends ParentClass implements ParentInterface {}
打印什么?
new Child().print();
答案:
new Child().print(); // 打印: "I am a class!"
如果类和接口之间存在继承冲突,那么类方法优先。
传递性重写
class Parent { void print() { foo(); } void foo() { log.info("I am Parent!"); } } class Child extends Parent { void foo() { log.info("I am Child!"); } }
打印什么?
new Child().print();
答案:
new Child().print(); // 打印: "I am Child!"
重写方法甚至对传递调用也会生效,阅读 Parent 类的人可能认为 Parent: : print 总是会调用 Parent: : foo。但是如果该方法被重写,那么 Parent: : print 将调用重写后的 foo ()版本。
私有重写
class Parent { void print() { foo(); } private void foo() { log.info("I am Parent!"); } } class Child extends Parent { void foo() { log.info("I am Child!"); } }
打印什么?
new Child().print();
答案:
new Child().print(); // 打印: "I am Parent!"
除了一点不同之外,这个与前一个例子完全相同。现在将 Parent.foo()声明为 private。因此,当 Parent.print()调用 foo()时,不管子类中是否存在 foo()的其他实现,也不管调用 print()的实例的实际类型如何。
静态重写
class Parent { static void print() { log.info("I am Parent!"); } } class Child extends Parent { static void print() { log.info("I am Child!"); } }
打印什么?
Child child = new Child(); Parent parent = child; parent.print(); child.print();
答案:
parent.print(); // 打印: "I am Parent!" child.print(); // 打印: "I am Child!"
Java 不允许重写静态方法。如果在父类和子类中定义了相同的静态方法,那么实例的实际类型根本不重要。只有声明的类型用于确定调用两个方法中的哪一个。
这是使用@override注解标记所有重写方法的另一个原因。在上面的例子中,在向 Child: : print 添加注解时,你会得到一个编译错误,告诉你由于方法是静态的,因此无法重写该方法。
静态链接
class Parent { void print() { staticMethod(); instanceMethod(); } static void staticMethod() { log.info("Parent::staticMethod"); } void instanceMethod() { log.info("Parent::instanceMethod"); } } class Child extends Parent { static void staticMethod() { log.info("Child::staticMethod"); } void instanceMethod() { log.info("Child::instanceMethod"); } }
打印什么?
Child child = new Child(); child.print();
答案:
Parent::staticMethod Child::instanceMethod
这是我们之前讨论过的一些不同概念的组合。例如,即使调用方位于父方法中,重写也会生效。但是,对于静态方法,即使变量的声明类型是 Child,也要调用 Parent: : staticMethod,因为有中间 print ()方法。
到此,关于“重载和重写的区别有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。