使用继承的重载方法

时间:2012-10-11 04:06:37

标签: java inheritance methods numbers integer

我有两个班级:

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

public class ClassB extends ClassA {            
    public void method(Integer d) {
        System.out.println("ClassB: " + d + " " + d.getClass());
    }
}

但是当我跑步时:

ClassA a = new ClassB(); 
a.method(3);

我明白了:

ClassA: 3 class java.lang.Integer

我的问题是,为什么不使用ClassB的方法? aClassB的一个实例,而ClassB的{​​{1}}有一个method()参数......

11 个答案:

答案 0 :(得分:24)

  

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

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


我认为混淆背后的主要原因是该方法实际上不是重写,而是重载。虽然IntegerNumber的子类型,但由于方法参数在Java中是不变的,因此方法public void method(Integer d)不会覆盖方法public void method(Number n)。因此,ClassB最终会有两个(重载)方法。

静态绑定用于重载方法,编译器选择具有最特定参数类型的方法。但在这种情况下,为什么编译器选择public void method(Number n)而不是public void method(Integer 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 method(Number n),这就是编译器选择的方法。请记住,此处预期的参数类型为Number,但传递的实际参数(整数3)将自动装入类型Integer。它起作用的原因是因为方法参数在Java中是协变的

现在,我认为它打印的原因很清楚

  

ClassA:3类java.lang.Integer

答案 1 :(得分:10)

你的问题源于这样一个事实(正如关于继承的官方Java教程所引用的那样):

  

在子类中,您可以重载从超类继承的方法。这种重载方法既不隐藏也不覆盖超类方法 - 它们是新方法,对于子类来说是唯一的。

有关更多详细信息,请参阅官方Java教程: http://docs.oracle.com/javase/tutorial/java/IandI/override.html

答案 2 :(得分:6)

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

ClassB a = new ClassB(); 

将产生您的预期输出。 Number是Integer的超类型。因此,无论您传入的是什么,都会被自动装箱到适当的子类型,并且将调用ClassA中的方法。尝试传递

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

答案 3 :(得分:4)

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

答案 4 :(得分:4)

因为数字3会自动装箱为整数。

请看以下链接:     http://www.javabeat.net/articles/print.php?article_id=31

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

答案 5 :(得分:1)

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

 public void method(Number n)  and
 public void method(Integer n)

默认情况下执行a.method(3)时3会被转换为Integer对象。 您可以通过调用

来验证这一点
a.method((Number)3);      //this would call the second method/operation.

您还可以通过使用反射来迭代B类的方法来验证这一点。

答案 6 :(得分:1)

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

  }// class ClassA

  public class ClassB
     extends
        ClassA
  {
     public void method( Integer d )
     {
        System.out.println( "ClassB: " + d + " " + d.getClass() );
     }// void method( Integer d )

     public static void main( String[] args )
     {
        ClassB b = new ClassB(); 
        ClassA a = b; 
        a.method( new Integer( 3 )); // 1. ClassA: 3 class java.lang.Integer
        b.method( new Integer( 4 )); // 2. ClassB: 4 class java.lang.Integer
        b.method( new Float( 5.6 )); // 3. ClassA: 5.6 class java.lang.Float
     }// void main( String[] args )

  }// class ClassB
  1. 由于两个方法都没有重载且实例属于类a,因此从A到B不会发生任何调度
  2. B有最佳匹配方法,然后选择
  3. B无法处理Float类型的参数,因此选择了一种方法

答案 7 :(得分:1)

要清除我在show()classA中添加的classB方法。

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,类B中的方法不可见。 这就是你调用classA方法的原因。 但是对于show()方法,因为它是重写方法,所以调用类B的show()方法。

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

答案 8 :(得分:0)

您有以下代码

Class A a = new ClassB(); 
a.method(3);

但是想象一下你有一个方法,其中“a”和“3”作为参数传递给你,你仍然执行相同的代码

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

编译器不知道您是要传递A类还是B类(或数字或整数)。它仍然必须解析该方法,以便它可以从a.method

进行返回值的类型检查

答案 9 :(得分:0)

我在这个问题上做了一些R& D并提出解决方案来消除你的困惑。希望它能帮助你理解。

查找以下代码:

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);
    }
}

如果您将运行此代码,您将获得输出:
"在b func"
"在b func"

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

  1. A类同时具有重载方法:func(Number)[说方法1]和func(整数)[说方法2]
  2. 由于继承,
  3. B类也有2种方法。所以它有func(Number)[说方法3]和func(整数)[说方法4]
  4. 现在当你在B的引用上调用b.func(3)时,它将看到"方法3"和"方法4",其中包含最适合派生类的参数。这里,Number和Integer类都适用于参数 3 ,但Integer是从Number派生的,因此将调用func(Integer)[方法3]。因此,输出是"在b func"

    第二个输出也是"在b方法"中,因为相同的逻辑。 首先要记住,你不能在A类没有的A类引用上调用任何方法。所以你只能在它所拥有的A类的引用上调用这些方法。无论实例是A类还是它的子类实例。

    你需要用2个术语来理解它,编译,链接和执行。

    现在,A类同时具有这两种方法,因此当编译器在类A的引用上查看a.func(3)时,编译器将查看"方法1"和"方法2" A类并绑定方法签名,该签名具有最适合派生类的参数。所以" func(整数)"。

    现在在运行时,将执行func(Integer),它被调用为B类,因为实例是B类。(在运行时,方法是从类执行的,其实例调用方法)。因此调用方法4。因此输出。

    我确信,你会感到困惑,为什么不调用方法2而调用方法4。

    如果您将运行以下代码:

    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);
        }
    }
    

    输出将是:
    在B级的b函数中
    在B级b函数中

    现在您可以通过上述说明理解此代码。我们要么在引用A类或B类时调用fun(3)。每次调用B类方法时(方法4)。因为实例属于B类。但是如果A类没有(方法2)。方法4不会在" 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 func中 在一个功能

    现在你可能会感到困惑为什么输出不同?

    请记住,这里不是4种方法。这里只有3种方法:

    1. A类中的func(数字)
    2. B类中的
    3. func(Number),继承自A类
    4. B类
    5. func(整数)
    6. 现在如果你调用a.fun(3),A类没有func(Integer),你就不能在类A的引用上调用哪个类没有。因此编译器不会绑定func(Integer),因为A类中没有这样的方法。但是还有另一种方法func(Number)可以使用相同的代码调用a.func(3)java的自动装箱概念。

      所以当a.func(3)调用时,它基本上调用func(Number)。现在因为实例是B类,所以调用B类的方法func(Number)。因此输出是"在函数中#34;

      这是一个非常大的答案,但我深入解释,因此您可以轻松了解不同用例中输出的不同可能性。

      享受编码!

答案 10 :(得分:-1)

在重载时,方法解析总是由编译器根据引用类型来处理。因此,在重载运行时对象[new ClassB()]不起任何作用。 因此,在您的情况下,执行了ClassA的方法。

ClassA a = new ClassB(); 
a.method(3);