首先先说明下基本概念,
- 静态解析:符号引用在类加载阶段就转为直接引用,编译期可知,运行期不可变。
- 动态连接:符号引用在运行期间转化为直接引用。
下面,看下这段代码的输出结果,代码一
public class Animal {
static {
System.out.println("static Animal");
}
public static int value = 1;
public Animal() {
System.out.println("构造方法 Animal");
}
public static void main(String[] args) {
int value = Dog.value;
}
public class Dog extends Animal {
static {
System.out.println("static Dog");
}
public Dog() {
System.out.println("构造方法 Dog");
}
}
输出结果:
static Animal
原因分析,对于静态字段,只有直接定义这个字段的类才会被初始化,类初始化阶段是执行类构造器clinit()方法的过程,clinit()是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的。
没有回答对的,要认真看下面的内容啦,思考下这段代码的输出结果,
public class Animal {
public Animal() {
System.out.println("构造方法 Animal");
}
public static void sleep() {
System.out.println("animal sleep");
}
private void hit() {
System.out.println("animal hit");
}
public final void hello() {
System.out.println("animal hello");
}
public static void main(String[] args) {
Animal animal = new Dog();
animal.sleep();
animal.hit();
animal.hello();
}
public class Dog extends Animal {
public Dog() {
System.out.println("构造方法 Dog");
}
public static void sleep() {
System.out.println("dog sleep");
}
private void hit() {
System.out.println("dog hit");
}
public final void hello() {
System.out.println("dog hello");
}
}
先想下这段代码可以正常执行吗,这段代码是不能正常执行的,在子类被final修饰的hello()会有编译错误的问题,这里又可以引申一个新的概念了,父类中被final修饰的方法是不能被重写的。
public final void hello() {
System.out.println("dog hello");
}
我们把这个编译错误的代码注释掉,思考下这个时候的输出结果,结果见下,
构造方法 Animal
构造方法 Dog
animal sleep
animal hit
sleep和hit方法全部调用的都是父类的。为什么呢?
sleep方法是静态方法,hit方法是私有方法,这两种方法各自的特点决定了他们都不可能通过继承或别的方式重写其他版本,因此他们在类加载中的解析阶段就有了可确定的调用版本,在运行期是不可变的。
- 静态方法与类型直接关联
- 私有方法在外部不可被访问
从JVM的角度来说,只要能被invokestatic和invokespecial指令调用的方法,都可以在解析阶段确定唯一的调用版本。
总结,以下方法可以在解析阶段确定调用版本:
- 静态方法
- 私有方法
- 实例构造器
- final修饰的方法,无法被覆盖
版权声明:本文为kl_Dreaming原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。