关于int,Integer 作为传入参数,子类方法调用的问题
之前一道面试题,把我搞蒙蔽了。 形如下列代码(相关问题和答案写在注释里面了)
package groupId.test;
/**
* 关于传入int和Integer参数,调用有啥区别?
* 答: 对于 子类Son来说,因为继承的关系,同时 存在 M(int n),M(Integer n) 两个方法,
* 根据传入的的参数来调用不同的方法。
* 对于 F f = new Son() 这种情况下,对象f完成上转型,不在视作Son类。
* 此时父类F只有一个方法 M(int n) 或者 M(Integer n),
* 无论传入int或者Integer,它都先执行拆装箱,再传入对应的父类方法FM中。
*/
public class temp {
public static void main(String[] args) {
Son s = new Son();
Father f = new Son();
Son2 s2 = new Son2();
Father2 f2 = new Son2();
// 子类//拆箱
s.doSomething(new Integer(1)); //父类 被执行。。。。1
s.doSomething(1); //子类 被执行。。。。。1
f.doSomething(new Integer(1)); //父类 被执行。。。。1
f.doSomething(1); //父类 被执行。。。。1
// 子类//装箱
s2.doSomething(new Integer(1)); //子类2 被执行。。。。。1
s2.doSomething(1); //父类2 被执行。。。。1
f2.doSomething(new Integer(1)); //父类2 被执行。。。。1
f2.doSomething(1); //父类2 被执行。。。。1
}
}
class Father{
public void doSomething(Integer n){
System.out.println("父类 被执行。。。。"+n);
}
}
class Son extends Father{
//拆箱
public void doSomething(int n){
System.out.println("子类 被执行。。。。。"+n);
}
}
class Father2{
public void doSomething(int n){
System.out.println("父类2 被执行。。。。"+n);
}
}
class Son2 extends Father2{
//装箱
public void doSomething(Integer n){
System.out.println("子类2 被执行。。。。。"+n);
}
}
索性,扩展一下:
放大或缩小父类的参数类型(即用它的父类或者子类做参数)
package groupId;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class LspOverriedOrOverwriteTest {
public static void main(String[] args) {
//invoke1();//父类1 被执行。。。。
//invoke11();//父类1 被执行。。。。 放大输入类型参数,重载,调用的还是父类的方法
//invoke2();//父类2 被执行。。。。。
//invoke21();// 子类21 被执行。。。。缩小输入类型参数, 覆写
// 子类21 缩小参数输入范围,子类重载了父类方法,子类行为不同于父类,在设计角度父类无法预料子类的行为,
// 这是非常危险的
//invoke3(); //父类3 被执行。。。。
//invoke31();//子类31 被执行。。。。。 缩小或等于输出类型参数, 此时相当于覆写了父类方法
//invoke4(); //父类4 被执行。。。。
//invoke41(); //父类4 被执行。。。。//放大输出类型参数,编译不通过 ,所以执行的还是父类的方法
//invoke5(); //父类5 被执行。。。。1
//invoke51();//输入类型 子类参数 Integer,"装箱",,父类5 被执行。。。。1 (子类传入 1) 子类51 被执行。。。。。1 (子类传入new Integer(1))
//invoke6(); //父类6 被执行。。。。1
//invoke61();//输入类型 子类 参数 int,"拆箱",子类61 被执行。。。。1 (子类传入 1) 父类5 被执行。。。。。1 (子类传入new Integer(1))
//invoke7(); //父类7 被执行。。。。1
//invoke71(); //父类7 被执行。。。。1 输出值 "拆箱",编译不通过 即 方法名,参数类型,个数,位置相同,不允许出现返回值不同的方法
//invoke8(); //父类8 被执行。。。。1
//invoke81(); //父类8 被执行。。。。1 输出值 "装箱",编译不通过 即 方法名,参数类型,个数,位置相同,不允许出现返回值不同的方法
invoke9(); //父类9 被执行。。。。
invoke91(); //父类9 被执行。。。。 在子类的输出参数缩小,输入参数放大的情况下,执行父类方法,{重载}
/**
* 总结,针对输出参数,子类的返回值在只能缩小或等于父类的情况下,整体上 子类是趋向于{覆写}父类方法的,
* 所以一般返回值类型视作相同。
* 针对输入参数,子类的输入参数在放大父类的情况下,或者多于父类同名方法的参数个数,或者参数位置调整情况,
* 整体子类是{重载}的,
* 子类调用父类的同签名方法,执行的是父类的方法,形如 father.dosomething(? supper Father T)
*
* 子类子类的输入参数在小于等于父类的情况下,{覆写} 父类方法
*
* 同时,1, int与Integer做两个测试; int与Integer作为输入参数,视作两个不同的参数类型
* 不会收到 jvm 默认拆装箱的影响, 同样 作为返回类型 他们不能同时存在子类相同方法名上,编译会报错。
* 又java规定 方法名,参数类型,个数,位置相同,不允许出现返回值类型不同的方法,故作为参数时,
* int 与Integer是两个完全不同的参数,其他原始类型与包装类型 类似。
* 补: F f = new Son() 这种情况下:若父类F只有一个方法 FM(int n) 或者 FM(Integer n),
* 无论传入int或者Integer,它都先执行拆装箱,再传入对应的父类方法FM中。
* 2,在子类的输出参数缩小,输入参数放大的情况下:
* invoke91() 执行父类方法,{重载} . 说明 一般情况下,无需考虑返回类型,子类的行为
* 取决于输入参数的类型, 输入参数类型>父类的,{重载},调用父类方法
* 输入参数<= 父类的,{覆写} ,调用子类方法、
*
* 因为输出参数>父类的,编译报错,所以不考虑 子类的输出参数放大,输入参数缩小的情况。
*/
}
public static void invoke1(){
//父类存在的地方,子类就应该能够存在
Father1 f = new Father1();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke11(){
//父类存在的地方,子类就应该能够存在
Son1 f = new Son1();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke2(){
//父类存在的地方,子类就应该能够存在
Father2 f = new Father2();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke21(){
//父类存在的地方,子类就应该能够存在
Son2 f = new Son2();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke3(){
//父类存在的地方,子类就应该能够存在
Father3 f = new Father3();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke31(){
//父类存在的地方,子类就应该能够存在
Son3 f = new Son3();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke4(){
//父类存在的地方,子类就应该能够存在
Father4 f = new Father4();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke41(){
//父类存在的地方,子类就应该能够存在
Son4 f = new Son4();
HashMap map = new HashMap();
f.doSomething(map); //放大输出类型参数,编译不通过 ,所以执行的还是父类的方法
}
public static void invoke5(){
//父类存在的地方,子类就应该能够存在
Father5 f = new Father5();
f.doSomething(1);
}
public static void invoke51(){
//父类存在的地方,子类就应该能够存在
Son5 f = new Son5();
HashMap map = new HashMap();
f.doSomething(new Integer(1)); //装箱
//f.doSomething(1); //装箱
}
public static void invoke6(){
//父类存在的地方,子类就应该能够存在
Father6 f = new Father6();
f.doSomething(1);
}
public static void invoke61(){
//父类存在的地方,子类就应该能够存在
Son6 f = new Son6();
HashMap map = new HashMap();
//f.doSomething(new Integer(1)); //装箱
f.doSomething(1); //装箱
}
public static void invoke7(){
//父类存在的地方,子类就应该能够存在
Father7 f = new Father7();
f.doSomething(1);
}
public static void invoke71(){
//父类存在的地方,子类就应该能够存在
Son7 f = new Son7();
HashMap map = new HashMap();
//f.doSomething(new Integer(1)); //装箱
f.doSomething(1); //装箱
}
public static void invoke8(){
//父类存在的地方,子类就应该能够存在
Father8 f = new Father8();
f.doSomething(1);
}
public static void invoke81(){
//父类存在的地方,子类就应该能够存在
Son8 f = new Son8();
HashMap map = new HashMap();
//f.doSomething(new Integer(1)); //装箱
f.doSomething(1); //装箱
}
public static void invoke9(){
//父类存在的地方,子类就应该能够存在
Father9 f = new Father9();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void invoke91(){
//父类存在的地方,子类就应该能够存在
Son9 f = new Son9();
HashMap map = new HashMap();
f.doSomething(map); //放大输出类型参数,编译不通过 ,所以执行的还是父类的方法
}
}
class Father1{
public Collection doSomething(HashMap map){
System.out.println("父类1 被执行。。。。");
return map.values();
}
}
class Son1 extends Father1{
//放大输入类型参数
public Collection doSomething(Map map){
System.out.println("子类11 被执行。。。。。");
return map.values();
}
}
class Father2{
public Collection doSomething(Map map) {
System.out.println("父类2 被执行。。。。。");
return map.values();
}
}
class Son2 extends Father2{
//缩小输入参数范围
public Collection doSomething(HashMap map){
System.out.println("子类21 被执行。。。。");
return map.values();
}
}
class Father3{
public Iterable doSomething(Map map){
System.out.println("父类3 被执行。。。。");
return map.values();
}
}
class Son3 extends Father3{
//缩小或等于输出类型参数
public Collection doSomething(Map map){
System.out.println("子类31 被执行。。。。。");
return map.values();
}
}
class Father4{
public Collection doSomething(Map map){
System.out.println("父类4 被执行。。。。");
return map.values();
}
}
class Son4 extends Father4{
//放大输出类型参数,编译不通过
/*public Iterable doSomething(Map map){
System.out.println("子类41 被执行。。。。。");
return map.values();
}*/
}
class Father5{
public Collection doSomething(int n){
System.out.println("父类5 被执行。。。。"+n);
return new HashMap().values();
}
}
class Son5 extends Father5{
//装箱
public Collection doSomething(Integer n){
System.out.println("子类51 被执行。。。。。"+n);
return new HashMap().values();
}
}
class Father6{
public Collection doSomething(Integer n){
System.out.println("父类6 被执行。。。。"+n);
return new HashMap().values();
}
}
class Son6 extends Father6{
//拆箱
public Collection doSomething(int n){
System.out.println("子类61 被执行。。。。。"+n);
return new HashMap().values();
}
}
class Father7{
public Integer doSomething(Integer n){
System.out.println("父类7 被执行。。。。"+n);
return n;
}
}
class Son7 extends Father7{
//输出值 拆箱,编译不通过 即 方法名,参数类型,个数,位置相同,不允许出现返回值不同的方法
/*public int doSomething(Integer n){
System.out.println("子类71 被执行。。。。。"+n);
return n.intValue();
}*/
//输出值 不同,编译不通过 即 方法名,参数类型,个数,位置相同,不允许出现返回值不同的方法
/*public boolean doSomething(Integer n){
System.out.println("子类71 被执行。。。。。"+n);
return n.intValue();
}*/
}
class Father8{
public int doSomething(Integer n){
System.out.println("父类8 被执行。。。。"+n);
return n.intValue();
}
}
class Son8 extends Father8{
//输出值 装箱,编译不通过, 即 方法名,参数类型,个数,位置相同,不允许出现返回值不同的方法
/*public Integer doSomething(Integer n){
System.out.println("子类81 被执行。。。。。"+n);
return n.intValue();
}*/
}
class Father9{
public Iterable doSomething(HashMap map){
System.out.println("父类9 被执行。。。。");
return map.values();
}
}
class Son9 extends Father9{
//测试 子类的输出参数缩小,输入参数放大的情况
public Collection doSomething(Map map){
System.out.println("子类91 被执行。。。。。");
return map.values();
}
}