6

在学习 Java 教程时,Reflection 和 Late Binding 让我很困惑。在一些教程中,他们写道它们都是相同的,并且反射和后期绑定之间没有任何区别。但是其他教程说有区别。

我很困惑,所以有人可以解释一下 Java 中的反射和后期绑定是什么,如果可能的话,请给我一些真实世界的例子。

谢谢..

4

5 回答 5

3

Java 使用后期绑定来支持多态性;这意味着应该使用许多方法中的哪一个的决定被推迟到运行时。

以 N 个类实现接口的抽象方法(或抽象类,fwiw)为例。

public interface IMyInterface {

    public void doSomething();    
}

public class MyClassA implements IMyInterface {

    public void doSomething(){ ... }
}

public class MyClassB implements IMyInterface {

    public void doSomething(){ ... }
}

public class Caller {

    public void doCall(IMyInterface i){
        // which implementation of doSomething is called?
        // it depends on the type of i: this is late binding
        i.doSomething(); 
    }
}

反射用于描述能够检查其他代码的代码,即。知道类中哪些方法或属性可用,按名称调用方法(或加载类),以及在运行时做很多非常有趣的事情。

反射的一个很好的解释在这里:什么是反射,为什么它有用?

于 2012-01-24T09:51:45.547 回答
2

后期绑定(也称为动态分派)不需要反射——它仍然需要知道在编译时动态绑定到哪个成员(即成员的签名在编译时已知),即使绑定到被覆盖的成员发生在运行时。

在进行反射时,您甚至不知道您正在使用哪个成员(在编译时甚至不知道名称,更不用说签名了)——一切都发生在运行时,因此速度要慢得多。

于 2012-01-24T09:45:22.887 回答
2

现实世界的例子:

如果您使用 jdesktop 0.8 构建项目,但附带 jdesktop 0.9,您的代码仍将使用 0.9 功能,因为它利用后期绑定,即您的代码调用的代码是类加载器加载的版本,与编译它的版本无关。(这与链接器相反,链接器将调用代码的编译时版本嵌入到应用程序中。)

对于反射,假设您尝试以 Java 1.5 和 1.6 为目标,但如果 1.6 中的选项卡组件可用,那么您将通过在 JTabbedPane 类上使用反射来检查它们的存在以查找setTabComponentAt方法。在这种情况下,您正在构建 Java 1.5,它根本没有这些功能,因此您不能直接调用它们,否则编译将失败。但是,如果在最终用户的系统上,您发现自己在运行 1.6(后期绑定在这里发挥作用),您可以使用反射来调用 1.5 中不存在的方法。

它们是相关的;反射的许多用途都依赖于后期绑定才能发挥作用,但它们是语言及其实现的根本不同方面。

于 2012-01-24T09:58:26.500 回答
1

“后期绑定”解决的一个重要问题是多态性,即沿着类层次结构调用正确的覆盖方法是在运行时确定的,而不是在编译期间确定的。反射是在运行时收集和操作有关对象的信息的功能。例如,您可以在运行时使用对象的“类”属性获取对象的所有属性或方法名称,并调用这些方法或操作其属性。

在下面的代码中,您可以通过反射动态创建一个新对象(查看如何使用类检索和访问构造函数,而不是简单地使用 object obj = new MyClass("MyInstance") 之类的东西)。以类似的方式,可以访问其他构造函数形式、方法和属性。有关 java 中反射的更多信息,请访问:http: //java.sun.com/developer/technicalArticles/ALT/Reflection/


... in some method of some class ...
Class c = getClass();
Constructor ctor = c.getConstructor( String.class );
Object obj = ctor.newInstance( "MyInstance" );

于 2012-01-24T10:01:24.560 回答
0

我不得不不同意这里的大多数回应-

每个人都将 Java 在运行时将方法实现归零的做法称为后期绑定,但在我看来,将术语后期绑定用于 Java 所做的事情是不正确的。

后期绑定意味着在编译时绝对不会检查方法调用,如果方法不存在,也不会出现编译错误。

但是,如果该方法在限定方法调用的类型的类型层次结构中的某处不存在,Java 将引发编译错误(在此处描述行为时有些近似)。这不是纯粹的传统后期绑定。Java 在普通的非私有非最终非静态方法调用中所做的最好称为动态调度。
但是,如果我们在 Java 中使用反射,那么 Java 会执行纯后期绑定,因为编译器根本无法验证被调用的方法是否存在。这是一个例子:

class A
{
    public void foo()
    {
        System.out.println("Foo from A");
    }
}

class B extends A
{
    public void foo()
    {
        System.out.println("Foo from B");
    }
}
public class C
{
   public static void main(String [] args)
    {
         A a=new A();
         B b=new B();
         A ref=null;
         Class ref1 = null;
         ref1 = b.getClass();
         ref.foo1();//will not compile because Java in this normal method
         //call does some compile time checks for method and method 
         //signature existence. NOT late binding in its pure form.
         try {
            ref1.getMethod("foo1").invoke(null); //will throw a 
            //NoSuchMethodException at runtime, but compiles perfectly even 
            //though foo1 does not exist. This is pure late binding.
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
       }
}
于 2017-09-22T20:41:29.297 回答