美文网首页程序员
Java类型检测与类加载

Java类型检测与类加载

作者: weipeng2k | 来源:发表于2018-08-18 21:32 被阅读0次

       Java提供了参数的动态检验,也就是在执行期检测参数是否合法。但是部分的检测还是在编译器的协助下完成的,而这一步要早于真正执行它。Java编译器会开启这种静态检测机制,会使用一组类型检测规则来检测Java字节码,检测这些字节码是否符合规则,如果不符合那么将会被拒绝。这里不讨论类型检测的做法,而是说明类型检测是早于执行的,而这一步将会诱发类加载过程,而这个类加载的顺序将会 颠覆 你对Java类加载的认知。

场景一:方法接受参数

       当出现方法接收的参数在代码中出现了参数类型的子类时,那么参数类型和子类,将会优先于方法所在类进行加载。因为Java需要判定这个方法是否可以接收这个类型,着重点在验证方法参数类型之间的关系。

public class A {

}
public class B extends A {

}
public class Test {

  void m(A a) {

  }
}
public class Main {
  public static void main(String[] args) {
    Test test = new Test();
    test.m(new B());
  }
}

       按照一般的理解,Java在执行main时,首先加载Test类型,然后再加载A和B两个参数类型,但是实际上的加载顺序是:

[Loaded com.murdock.book.jarviewer.typechecking.method.Main from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.method.A from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.method.B from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Void from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded com.murdock.book.jarviewer.typechecking.method.Test from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]

       Java先加载了方法的参数类型和返回值类型(Void),然后再加载了Test类型。 因为我们的代码里面传递给m方法的不是A类型,从而诱发Java的编译器检查,进而促使了参数类型的提前加载。下面我们把方法的参数改为A。

test.m(new A());

       加载顺序和我们平日认知的一致:

[Loaded com.murdock.book.jarviewer.typechecking.method.Main from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Void from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded com.murdock.book.jarviewer.typechecking.method.Test from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.method.A from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]

       先加载了Test类型,然后再加载A类型。

场景二:成员变量赋值

       当一个类的成员变量被赋值一个子类型时,该成员变量的类型和子类型将会优先于成员变量所在类进行加载。

public class A {

}
public class B extends A {

}
public class Test {
  A a = null;
  void m(A a) {

  }
}
public class Main {
  public static void main(String[] args) {
    Test test = new Test();
    test.a = new B();
  }
}

       a指向了子类型B的实例,加载顺序:

[Loaded com.murdock.book.jarviewer.typechecking.assign.Main from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.assign.A from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.assign.B from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Void from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded com.murdock.book.jarviewer.typechecking.assign.Test from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]

       A和B又早于Test进行了加载。

场景三:方法体返回值的类型为签名的子类型

       当一个类中包括的方法,返回的类型是形参的子类时,形参和返回参数的子类型将会提前加载。

public class A {

}
public class B extends A {

}
public class Test {
  A a = null;
  void m(A a) {
  }
}
public class Main {
  public static void main(String[] args) {
    Test test = new Test();
    test.m(new A());
  }

  A check(A a) {
    return new B();
  }
}

       在Main执行过程中,check方法是不会被调用的,但是在Main这个类里面存在一个这个方法,所以当Main被加载之后,Java观察到方法check返回了一个非A的类型,那么就提前加载了A和B类型,加载顺序:

[Loaded com.murdock.book.jarviewer.typechecking.bodyreturn.Main from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.bodyreturn.A from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded com.murdock.book.jarviewer.typechecking.bodyreturn.B from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Void from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded com.murdock.book.jarviewer.typechecking.bodyreturn.Test from file:/Users/weipeng2k/Documents/arena/jarviewer/target/classes/]
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home/jre/lib/rt.jar]

       这三种提前加载,都是由于Java编译器在进行规则检查时进行了提前加载所致。

相关文章

网友评论

    本文标题:Java类型检测与类加载

    本文链接:https://www.haomeiwen.com/subject/jqhqiftx.html