接口的初始化
*当一个接口在初始化时,并不是要求其父接口都完成了初始化。(但是实际中根本就没有加载类,哪来的舒适化...)
*当有在真正使用到父类接口时候(如使用了父类中的常量),才会被初始化。
接口中默认的属性就是public static final
这里了解下深度内存解析Java关键字:Static与Final
调用继承父接口的子接口并且其中的常量时编译时确定的
上代码:
public class Test2 {
public static void main(String[] args){
System.out.println(Child2.a);
}
}
interface Parent2{
int a = 5;
}
interface Child2 extends Parent2{
int b = 6;
}
截取部分以上类加载信息:
这里值加载了Test2,并没有加载两个接口。
调用继承父接口的子接口并且其中的常量是运行时确定的
import java.util.Random;
import static staticpackage.PrintHelper.*;
public class Test2 {
public static void main(String[] args){
println(Child2.b);
}
}
interface Parent2{
int a = 6;
}
interface Child2 extends Parent2{
int b = new Random().nextInt();
}
调用继承父接口的类
public class Test2 {
public static void main(String[] args){
System.out.println(Child2.b);
}
}
interface Parent2{
int a = 6;
}
class Child2 implements Parent2{
static int b = 5;
}
被基础的子类有final修饰的数据其值编译时确定
public class Test2 {
public static void main(String[] args){
System.out.println(Child2.b);
}
}
interface Parent2{
int a = 6;
}
class Child2 implements Parent2{
static final int b = 5;
}
被基础的子类有final修饰的数据其值运行时确定
import java.util.Random;
public class Test2 {
public static void main(String[] args){
System.out.println(Child2.b);
}
}
interface Parent2{
int a = 6;
}
class Child2 implements Parent2{
static final int b = new Random().nextInt();
}
public class Test3 {
//编译期常量指的就是程序在编译时就能确定这个常量的具体值
//非编译期常量就是程序在运行时才能确定常量的值,因此也称为运行时常量
//定义上来说,声明为final类型的基本类型或String类型并直接赋值(非运算)的变量就是编译期常量,即:
public static void main(String[] args){
System.out.println(Parent3.c);
}
}
class Parent3{
// 编译期常量
final static int a = 3;
final int b =3 ;
// 运行期常量
static int c = 3;
int d = 3;
// 运行期常量
final static int f = new Integer(3);
final int g = new Integer(3);
// 运行期常量
static int h = new Integer(3);
int i = new Integer(3);
}
编译编译器常量:
Compiled from "Test3.java"
public class Test3 {
public Test3();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_3 //由此可见该常量直接在Test3类的常量池中,与Paren3无关
4: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
7: return
运行期间常量
Compiled from "Test3.java"
public class Test3 {
public Test3();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field Parent3.c:I //与Parent3有关
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: return
}
小结:
1.被final修饰的且其值编译时候就确定了的情况下,该类不会被加载。
2.被final修饰的且其值运时候就确定了的情况下,该类及其父类都会被加载,被加载并不等于初始化。
因此,一个父接口并不会因为他的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态变量时,才会导致接口的初始化。
参考两篇文章:JVM常量池浅析