【发布时间】:2012-01-24 09:41:04
【问题描述】:
在学习 Java 教程时,反射和后期绑定让我感到困惑。在一些教程中,他们写道它们都是相同的,并且反射和后期绑定之间没有任何区别。但是其他教程说有区别。
我很困惑,所以有人可以解释一下 Java 中的反射和后期绑定是什么,如果可能的话,请给我一些现实世界的例子。
谢谢..
【问题讨论】:
标签: java reflection late-binding
在学习 Java 教程时,反射和后期绑定让我感到困惑。在一些教程中,他们写道它们都是相同的,并且反射和后期绑定之间没有任何区别。但是其他教程说有区别。
我很困惑,所以有人可以解释一下 Java 中的反射和后期绑定是什么,如果可能的话,请给我一些现实世界的例子。
谢谢..
【问题讨论】:
标签: java reflection late-binding
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();
}
}
反射用于描述能够检查其他代码的代码,即。知道类中哪些方法或属性可用,按名称调用方法(或加载类),以及在运行时做很多非常有趣的事情。
这里有一个很好的反射解释:What is reflection and why is it useful?
【讨论】:
后期绑定(也称为动态调度)不需要反射——它仍然需要知道哪个成员在编译时动态绑定(即成员的签名在编译时是已知的),即使绑定到被覆盖的成员是在运行时发生的。
在进行反射时,您甚至不知道您正在使用 哪个 成员(在编译时甚至不知道 name,更不用说签名了) -- 一切都发生在运行时,所以速度要慢很多。
【讨论】:
现实世界的例子:
如果您使用 jdesktop 0.8 构建项目,但附带 jdesktop 0.9,您的代码仍将使用 0.9 功能,因为它利用后期绑定,即您的代码调用的代码是由类加载器,与编译它的版本无关。 (这与链接器相反,链接器将被调用代码的编译时版本嵌入到应用程序中。)
对于反射,假设您尝试以 Java 1.5 和 1.6 为目标,但如果 1.6 中的选项卡组件可用,那么您将通过在 JTabbedPane 类上使用反射来检查它们是否存在以查找 @ 987654321@ 方法。在这种情况下,您正在构建 Java 1.5,它根本没有这些功能,因此您不能直接调用它们,否则编译将失败。但是,如果在最终用户的系统上您发现自己在运行 1.6(此处使用后期绑定),您可以使用反射来调用 1.5 中不存在的方法。
它们是相关的;反射的许多用途都依赖于后期绑定才能发挥作用,但它们是语言及其实现的根本不同方面。
【讨论】:
“后期绑定”解决的一个重要问题是多态性,即沿着类层次结构调用正确的覆盖方法是在运行时确定的,而不是在编译期间确定的。反射是在运行时收集和操作有关对象的信息的功能。例如。您可以在运行时使用对象的“类”属性获取对象的所有属性或方法名称,并调用这些方法或操作其属性。
在下面的代码中,您可以通过反射的方式动态创建一个新对象(查看如何使用类检索和访问构造函数,而不是简单地使用像 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" );
【讨论】:
我不得不不同意这里的大多数回复-
每个人都将 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();
}
}
}
【讨论】: