Java 使用继承的重载方法

Java 使用继承的重载方法,java,inheritance,methods,numbers,integer,Java,Inheritance,Methods,Numbers,Integer,我有两门课: public class ClassA { public void method(Number n) { System.out.println("ClassA: " + n + " " + n.getClass()); } } 以及: 但当我跑步时: ClassA a = new ClassB(); a.method(3); 我得到: ClassA: 3 class java.lang.Integer 我的问题是,为什么不使用ClassB的方

我有两门课:

public class ClassA {
    public void method(Number n) {
        System.out.println("ClassA: " + n + " " + n.getClass());
    }
}
以及:

但当我跑步时:

ClassA a = new ClassB(); 
a.method(3);
我得到:

ClassA: 3 class java.lang.Integer

我的问题是,为什么不使用ClassB的方法
a
ClassB
的一个实例,
ClassB
method()
有一个
Integer
参数…

,因为参数中的数字和整数创建了两个不同的方法签名。因此,类B只有两种不同的方法可供使用。

您的问题源于以下事实(引用自官方Java继承教程):

在子类中,可以重载从超类继承的方法。这种重载方法既不隐藏也不重写超类方法,它们是新方法,是子类特有的`

有关更多详细信息,请参阅官方Java教程:
因为数字3自动装箱为整数

请参阅下面的链接:

一般规则:参数被隐式加宽以匹配方法参数。
从一个包装类扩展到另一个包装类是不合法的。

因为这两个操作有不同的参数(参数)类型(即使它们是子类),它们被认为是不同的(不同于C)。您没有用第二个方法覆盖第一个方法。相反,您最终得到了类B,它现在有两个方法

 public void method(Number n)  and
 public void method(Integer n)
默认情况下,当您执行此操作时,方法(3)3被强制转换为整数对象。 您可以通过调用

a.method((Number)3);      //this would call the second method/operation.
您还可以通过使用反射来迭代类B的方法来验证这一点

我的问题是,为什么不使用ClassB的方法

不是真的。使用的方法是
ClassB
的方法,它继承自
ClassA


我认为造成这种混乱的主要原因是,该方法实际上并没有被覆盖,而是被重载。尽管
Integer
Number
的一个子类型,但由于方法参数在Java中是不变的,因此方法
public void方法(Integer d)
不会覆盖方法
public void方法(Number n)
。因此,
ClassB
最终有两个(重载)方法

静态绑定用于重载方法,具有最特定参数类型的方法由编译器选择。但是在这种情况下,为什么编译器选择
公共无效方法(数字n)
而不是
公共无效方法(整数d)
。这是因为您用来调用该方法的引用的类型是
ClassA

ClassA a = new ClassB(); //instance is of ClassB (runtime info)
a.method(3);             //but the reference of type ClassA (compiletime info)
ClassA
拥有的唯一方法是
public void方法(编号n)
,因此编译器会选择这种方法。请记住,此处预期的参数类型是
Number
,但实际参数,即传递的整数3,会自动装箱到类型
integer
。它之所以有效是因为方法参数在Java中是协变的

现在,我想很清楚为什么它会打印

ClassA:3类java.lang.Integer

  • 由于这两个方法没有重载,并且实例是类a,因此从a到B不会发生调度
  • B有一个最佳匹配方法,然后选择它
  • B无法处理Float类型的参数,因此选择了一种方法

  • a是ClassA类型,因此ClassB中的方法对于实例a不可见,除非它被声明为ClassB

    ClassB a = new ClassB(); 
    
    将产生您的预期输出。Number是整数的超类型。因此,您传入的任何内容都将自动装箱到相应的子类型,并将调用ClassA中的方法。试着传球

    a.method(3.0f) // Float
    a.method(3.0) // Double
    

    为了清除,我在
    classA
    classB
    中都添加了
    show()
    方法

    public void show() {
            System.out.println(getClass());
        }
    
    我这样叫,

        // Case 1       
        ClassA a = new ClassB();
        a.method(3);// ClassA: 3 class java.lang.Integer
        a.show(); // class ClassB
    
        // Case 2       
        ClassB b = new ClassB();
        b.method(3);// ClassB: 3 class java.lang.Integer
        b.show(); // class ClassB
    
    这里方法(数字n)和方法(整数d)具有不同的签名。 它不是压倒一切的。它超载了

    但是show()方法是方法重写

    在案例1中, 对象A只能访问类A的方法。a是classA类型,classB中的方法不可见。 这就是调用classA方法的原因。 但对于被重写的show()方法,调用类B的show()方法

    在案例2中,
    类A和B的两个方法都可以通过对象B访问,因为类B扩展了类A

    Class A a = new ClassB(); 
    a.method(3);
    
    但是假设您有一个方法,其中“a”和“3”作为参数传递给您,并且您仍然执行相同的代码

    public void foo(A a, Number n)
    {
        a.method(n);
    }
    

    编译器不知道您是要传递类A还是类B(或数字或整数)。它仍然必须解决该方法,以便可以对a.method的返回值进行类型检查。我对此问题进行了一些研究,并提出了解决方案,以消除您的混淆。希望它能帮助你理解

    请查看以下代码:

    class A {
        public void func(Number obj){
            System.out.println("In a func");
        }
        public void func(Integer obj){
            System.out.println("In b func");        
        }
    }
    
    class B extends A {
    }
    
    public class X {
    
        public static void main(String s[]){
            B b = new B();
            b.func(3);
    
            A a = new B();
            a.func(3);
        }
    }
    
    class A {
        public void func(Number obj){
            System.out.println("In a func");
        }
        public void func(Integer obj){
            System.out.println("In b func");        
        }
    }
    
    class B extends A {
        public void func(Number obj){
            System.out.println("In a func of class B");
        }
        public void func(Integer obj){
            System.out.println("In b func of class B");     
        }
    }
    
    public class X {
    
        public static void main(String s[]){
            B b = new B();
            b.func(3);
    
            A a = new B();
            a.func(3);
        }
    }
    
    class A {
        public void func(Number obj){
            System.out.println("In a func");
        }
    }
    
    class B extends A {
        public void func(Integer obj){
            System.out.println("In b func");        
        }
    }
    public class X {
    
        public static void main(String s[]){
            B b = new B();
            b.func(3);
    
            A a = new B();
            a.func(3);
        }
    }
    
    如果运行此代码,您将获得以下输出:
    “在b函数中”
    “在b函数中”

    在这种情况下,有4种方法:

  • 类A同时具有重载方法:func(Number)[say method 1]和func(Integer)[say method 2]
  • 由于继承,类B也有2个方法。所以它有func(Number)[say method 3]和func(Integer)[say method 4]
  • 现在,当您对b的引用调用b.func(3)时,它将看到“方法3”和“方法4”,它们的参数与最合适的派生类匹配。这里Number和Integer类都适用于参数3,但Integer是从Number派生的,因此将调用func(Integer)[方法3]。因此,输出为“在b func中”

    由于相同的逻辑,第二个输出也是“在b方法中”。 首先请记住,您不能对类A引用调用任何类A没有的方法。所以您只能在类A的引用上调用它所拥有的那些方法。无论实例是类A还是子类的实例

    您需要从编译、链接和执行两个方面来理解它

    现在类A同时拥有这两个方法,所以当编译器
    class A {
        public void func(Number obj){
            System.out.println("In a func");
        }
        public void func(Integer obj){
            System.out.println("In b func");        
        }
    }
    
    class B extends A {
        public void func(Number obj){
            System.out.println("In a func of class B");
        }
        public void func(Integer obj){
            System.out.println("In b func of class B");     
        }
    }
    
    public class X {
    
        public static void main(String s[]){
            B b = new B();
            b.func(3);
    
            A a = new B();
            a.func(3);
        }
    }
    
    class A {
        public void func(Number obj){
            System.out.println("In a func");
        }
    }
    
    class B extends A {
        public void func(Integer obj){
            System.out.println("In b func");        
        }
    }
    public class X {
    
        public static void main(String s[]){
            B b = new B();
            b.func(3);
    
            A a = new B();
            a.func(3);
        }
    }
    
    ClassA a = new ClassB(); 
    a.method(3);