“import”关键字实际上并不导入任何内容.基本上它只是一种通过类名引用类的完整路径的方法.所以当我们说
import java.lang.String;
那么我们可以在代码中用它的名字“String”来引用那个类.在编译时,我们将类“String”的任何地方替换为“java.lang.String”.而已.
这也是为什么如果您有多个具有相同名称但在不同包中的类,您最多只能导入其中一个.您必须通过其完全限定名称引用的另一个类.
在问题上:
1. A.class是否在其内部存储了一些关于B的信息?只是名称,被调用的方法,使用的最终变量?如果在编译之后A.class中没有关于B的那么多信息 – 为什么我们不能编译A而没有B.class?
并不是的.在调用其他类时,A类仅使用完全限定的类名和方法签名.使用我们的String示例,调用
mystring.charAt(0)
将编译成字节代码,看起来像这样:
aload_1 [myString]
iconst_0
invokevirtual java.lang.String.charAt(int)
除了可能的内联常量之外,其他类的内部状态都不存储在我们的类A中.因此,如果价值可能在未来发生变化,请务必将领域公之于众. (见下面的解决方法)
我们在编译A类时需要B.class,因此编译器可以确保B类具有我们想要使用的那些方法.
2.如果我们将B.class中的B.class替换为另一个B.class – 当它工作时,何时不工作?
如果完整的限定名称(包等)相同并且它具有我们尝试使用的正确方法签名,则新的B.class将起作用.新的B类可以添加新方法,甚至可以使用我们使用的方法的不同实现.但是,它不能修改我们使用的方法的方法签名.如果旧方法不再存在或其签名不同,我们将在编译时获得java.lang.LinkageError.
3.如果A.class使用新的B.class运行正常,A.class是否可以使用OLD B.class中的一些信息,这些信息在编译期间被合并到A.class中?即我们的项目中最终可能有B.class的混合逻辑吗?
唯一的问题可能是来自旧B的内联常量.这就是为什么Java Coding Guidelines第31项(第115页)说“不要将公共final应用于其值可能在以后的版本中变化的常量”.
相反,制作一个getter方法:
例如:
class BadFoo{
//bad, VERSION could be inlined
//and later when we change the version, other classes will have the old value!
public static final int VERSION =1;
}
class BetterFoo{
private static int version =1;
//outside classes must call method getVersion()
//field version can not be inlined at compile time.
//JIT may inline at runtime which is OK
public static final int getVersion(){
return version;
}
}
4.基于上述问题的答案:我们能否以某种方式编译依赖于其他类的类而不知道它们在编译时的确切实现,并仅在运行时提供依赖性?
是的,接口代码.
接口应包含您需要调用的所有方法.我们的A类应仅通过接口引用调用者.如果传入我们要调用的对象实例,那么A类不知道(或需要知道)实际类型是什么,并且在编译时不需要知道它.
除了依赖注入之外,对接口进行编码也具有优势.例如,如果我们使用Map而不是HashMap,我们稍后可以通过仅更改代码中的一个位置来更改代码以使用不同的Map实现(如ConcurrentHashMap).我们的其余代码只会工作,因为它只知道它是一个Map.