Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用派生类实例化基类?_Java_Inheritance_Polymorphism - Fatal编程技术网

Java 使用派生类实例化基类?

Java 使用派生类实例化基类?,java,inheritance,polymorphism,Java,Inheritance,Polymorphism,这是我的代码,我无法解释为什么输出会是这样。如果有人能解释的话 import java.io.*; class b { void m(b a){ System.out.println(" b"); } } class bcd extends b { void m(bcd a){ System.out.println("bcd"); } } class cde extends bcd { void m(cde a){ System.out.println("cde"); }

这是我的代码,我无法解释为什么输出会是这样。如果有人能解释的话

import java.io.*;
class b {
void m(b a){
System.out.println(" b");
}  
}
class bcd extends b {
    void m(bcd a){
System.out.println("bcd");
 }  
}
class cde extends bcd {
void m(cde a){
System.out.println("cde");
}  
}
public class ABC{
public static void main(String[] args){
b ob1= new cde();
cde ob2=new cde();
ob1.m(ob2);
}
}

当您调用
ob1.m(ob2)时然后调用类b的方法。
类中定义的方法

class bcd extends b {
    void m(bcd a) {
        System.out.println("bcd");
    }
}

class cde extends bcd {
    void m(cde a) {
        System.out.println("cde");
    }
}

重载的方法不是重写的方法。

在您的示例中,将调用类b中的方法。我认为您希望显示覆盖或重载示例,但这不是覆盖,也不是重载

对于覆盖,请使用后期绑定。在这种情况下,在知道方法签名的情况下,虚拟机将分析对象的实例化(真实)类型,该对象被调用该方法,以准确地确定采用被调用方法的定义的类。 对于重载,请使用早期绑定。在这种情况下,编译器将检查对象的形式类型

很好的示例解释了覆盖或重载:

public class Test{

    public static class Parent{

        public void test(){
            System.out.println("parent class");
        }
    }

    public static class Child extends Parent{

        public void test(){
            System.out.println("child class");
        }
    }

    public static class Tester{

        public void test(Parent obj){
            System.out.println("Parent method");
            obj.test();
        }

        public void test(Child obj){
            System.out.println("Child method");
            obj.test();
        }
    }

    public static void main(String[] args){
        Parent obj = new Child();
        Tester t = new Tester();
        t.test(obj);
    }
}
结果执行:

父方法

儿童班

编辑: 1) 编译器不查看类型参数。它根据调用它的实类型对象确定调用什么方法:例如,这是b类,我的示例是Tester类。2)如果一个类中有两个方法具有相同的名称,但方法中的类型参数不同(重载),那么java虚拟机会查看类型参数(在我的示例中是如何实现的:两个方法具有相同的名称,但传输了类Parent的对象和使用Parent参数调用方法)

在您的示例中,如果是这样的:

class B {
   void m(B a){
          System.out.println(" b");
   }  

   void m(Cde a){
         System.out.println("cde");
   }  
}

public class ABC{
       public static void main(String[] args){
          B ob1= new Cde();
          Cde ob2=new Cde();
          ob1.m(ob2);
       }
}
这是一个重载示例,将调用
void m(cde a)

EDIT2:
是的,您的ob1对象是实例cde,但java虚拟机仅在大小写重写(当两个类中的方法签名相同时)时才检查对象的实例化(实)类型。因此,您需要记住两件事:重写和重载,在其他情况下,编译器查看形式类型引用,在您的示例中,这是b

但是有一件有趣的事情是覆盖

如果 返回类型是引用类型 返回类型可替换性支持协变返回,即 将返回类型专门化为子类型

A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2,
当且仅当以下条件成立时:

    If R1 is void then R2 is void.

    If R1 is a primitive type, then R2 is identical to R1.

    If R1 is a reference type then:

        R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or

        R1 = |R2|
如果此代码具有不同的返回类型,但参数相同,则它也将被示例覆盖:

class Bcd extends B {
    @Override
    Bcd m(Cde a) {
        System.out.println("bcd");
        return a;
    }
}

class Cde extends Bcd {
    @Override
    Cde m(Cde a) {
        System.out.println("cde");
        return a;
    }
}

class B {
    B m(Cde a) {
        System.out.println("b");
        return a;
    }
}

class Test {

    public static void main(String[] args) {
        final B ob1 = new Cde();
        final Cde ob2 = new Cde();
        ob1.m(ob2);
    }
}
结果:

cde


因为这也是重写。

为什么它会让您感到困惑?它将b打印为输出,为什么不是cde?在我的代码中,为什么b被打印而不是cde。当我传递cde类的对象时,就像传递父对象和它打印的父方法一样,为什么它没有被调用?但在我的示例中,如果我调用ob1.m,cde应该是called,因为现在我的引用位于cde,然后我将cde对象作为参数发送,因此我希望cde作为输出。在您的示例中,它不会覆盖和重载案例。不会覆盖,因为您有不同类型的参数(在我的示例中,我想说明它可能会被不同的返回类型覆盖,但需要上面答案中写的条件和相同的类型参数)。不重载,因为方法位于不同的类中。编译器查看调用方法的形式类型引用对象(而不是实例类型)。在您的示例中为ob1.m(ob2)ob1的形式类型是b。所以,您需要记住两件事:重写和重载,在其他情况下,编译器查看形式类型引用,在您的示例中,这是b。