在学习 Java 教程时,Reflection 和 Late Binding 让我很困惑。在一些教程中,他们写道它们都是相同的,并且反射和后期绑定之间没有任何区别。但是其他教程说有区别。
我很困惑,所以有人可以解释一下 Java 中的反射和后期绑定是什么,如果可能的话,请给我一些真实世界的例子。
谢谢..
在学习 Java 教程时,Reflection 和 Late Binding 让我很困惑。在一些教程中,他们写道它们都是相同的,并且反射和后期绑定之间没有任何区别。但是其他教程说有区别。
我很困惑,所以有人可以解释一下 Java 中的反射和后期绑定是什么,如果可能的话,请给我一些真实世界的例子。
谢谢..
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();
}
}
反射用于描述能够检查其他代码的代码,即。知道类中哪些方法或属性可用,按名称调用方法(或加载类),以及在运行时做很多非常有趣的事情。
反射的一个很好的解释在这里:什么是反射,为什么它有用?
后期绑定(也称为动态分派)不需要反射——它仍然需要知道在编译时动态绑定到哪个成员(即成员的签名在编译时已知),即使绑定到被覆盖的成员发生在运行时。
在进行反射时,您甚至不知道您正在使用哪个成员(在编译时甚至不知道名称,更不用说签名了)——一切都发生在运行时,因此速度要慢得多。
现实世界的例子:
如果您使用 jdesktop 0.8 构建项目,但附带 jdesktop 0.9,您的代码仍将使用 0.9 功能,因为它利用后期绑定,即您的代码调用的代码是类加载器加载的版本,与编译它的版本无关。(这与链接器相反,链接器将调用代码的编译时版本嵌入到应用程序中。)
对于反射,假设您尝试以 Java 1.5 和 1.6 为目标,但如果 1.6 中的选项卡组件可用,那么您将通过在 JTabbedPane 类上使用反射来检查它们的存在以查找setTabComponentAt
方法。在这种情况下,您正在构建 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();
}
}
}