Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.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_Overriding - Fatal编程技术网

在像Java这样的静态类型语言中,动态方法解析背后的原因是什么

在像Java这样的静态类型语言中,动态方法解析背后的原因是什么,java,overriding,Java,Overriding,我想我对Java中引用变量的动态/静态类型和动态方法解析的概念有点困惑 考虑: public class Types { @Override public boolean equals(Object obj){ System.out.println("in class Types equals()"); return false;//Shut-up compiler! } public static void main(Stri

我想我对Java中引用变量的动态/静态类型和动态方法解析的概念有点困惑

考虑:

public class Types {

    @Override
    public boolean equals(Object obj){
        System.out.println("in class Types equals()");
        return false;//Shut-up compiler!
    }

    public static void main(String[] args){
        Object typ = new Types();
        typ.equals("Hi");//can do this as String is a subclass of Object
    }
}
第一:引用变量
typ
是类型,不是吗

那么,typ具有用于方法重写的静态类型对象和动态类型类型背后的原因是什么

第二:编译器没有足够的信息来调用正确的equals()

如果类类型没有重写的equals(),那么它可以调用
Object.equals()
方法

在这种情况下,类类型会这样做,编译器也知道这一点


为什么这不能像重载一样是早期绑定?为什么要把它留给JVM呢?

这是面向对象编程的基础

它归结为多态性。请参阅以获取进一步阅读

您绝对希望子类可以覆盖行为;因为这允许您保持客户端代码不变;但你仍然能够引入新的/不同的行为;只需将另一个对象传递给该客户机代码


客户端代码知道调用哪个方法;但调度必须在运行时进行。这仅仅是因为编译器不知道(在大多数情况下)传入参数的确切类型。

示例中的引用变量
typ
属于
Object
类型

它引用的对象的类型为
类型

编译器没有足够的信息来知道对象实际上是
Types
,并且使用
Type.equals(object)

这可能令人困惑。如果你写信

Object typ = new Types();
那么编译器肯定知道
typ
中包含的是
类型。它只是将这些信息编译成代码

但是,如果您决定将该行更改为

Object type = new ObjectFactory().choose(choice).use(decision).build();
好吧,现在您实际上不知道
构建将产生什么。只有在ObjectFactory决定如何处理
choice
decision
的值之后,才会在运行时知道这一点

所以在这种情况下,编译器不知道。唯一可用的信息是变量的静态类型。如果使用
new
时编译器的行为与使用上述工厂时编译器的行为不同,那将是非常糟糕的

现在看看这个场景:

public class Types {
     public boolean equals( Object obj ) {
        // something
     }

     public boolean equals( String str ) {
        return false;
     }
}

public class Main {

    public static void main(String[] args) {
       Object typ = new Types();
       System.out.println( typ.equals("foo" ) );
    }
}
现在,在本例中,
Types
Main
是两个独立的编译单元(不同的文件等)。假设编译器决定根据
typ
Types
这一事实进行编译。然后它将使用
类型.equals(String)

但是现在您可以编辑
类型
,删除
等于(字符串)
,并且只重新编译
类型
。当你运行程序时,你会得到一个“没有这样的方法异常”,因为编译器假定
Types
有一个
equals(String)
方法。因此,您的程序失败了,尽管它是一个完全合法的Java程序,并且在新的
类型中有一个合适的匹配方法
equals(Object)


因此,真正的编译器使用静态类型来确定一个方法是否存在,并且在给定的静态参数下是否合法,并且只有在运行时,JVM才能找到实际类型,并调用该方法的适用重写。

编译器只知道一个vriable的
静态类型
,并使用它检查java中的一些约束

拳头:

引用变量typ是一种类型,不是吗

我认为编译器将变量
类型
视为
对象
,当然
类型
是指向
类型
对象的实点,因为每个类都是
对象
的子类型,所以它可以分配给变量
类型

第二:

编译器没有足够的信息来调用正确的equals()

不知道。编译器只知道程序调用变量
typ
的方法
equals()
,但不知道
typ
是指向
Types
实例还是其他类型实例。因此,在编译时,真正调用的方法并不确定

查看以下代码:

    Object typ = new Main();
    Object o=new Object();
    typ.equals("Hi");//can do this as String is a subclass of Object
    o.equals("Hi");
请参阅JVM中的指令集:

    16: aload_1
    17: ldc           #42                 // String Hi
    19: invokevirtual #43                 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
    22: pop
    23: aload_2
    24: ldc           #42                 // String Hi
    26: invokevirtual #43                 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
注意

19:invokevirtual#43//Method java/lang/Object.equals(Ljava/lang/Object;)Z

26:invokevirtual#43//方法java/lang/Object.equals:(Ljava/lang/Object;)Z

typ.equals(“Hi”)
o.equals(“Hi”)
编译相同的指令集。但将调用哪个方法取决于实际实例的方法引用表

#43 = Methodref          #41.#132      // java/lang/Object.equals:(Ljava/lang/Object;)Z

#43
是指向实际方法的方法引用。jvm中的每个实例都有一个方法引用表。如果类
重写其继承方法的某个方法,方法引用将更改为
覆盖
方法。

抱歉,静态拼写错误。引用变量
类型
为静态类型
对象
和运行时类型
类型
。不,编译器只知道
typ
Object