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