全都是基于java 9 的 不同版本有没有差异,我也不太清楚,有知道的大佬给补充以下。
嵌套类加载顺序
new一个对象时,代码的执行顺序:
- 加载外部类静态代码块、静态变量
- 加载内部类静态代码块、静态变量
内部类如果需要有静态代码块,静态变量,就必须是静态内部类 - 加载外部类非静态代码块
- 加载内部类非静态代码块
- 执行外部类的构造方法
- 执行外部类的构造方法
- 加载外部类的非静态变量
- 加载内部类的变量
如果内部类是非静态的,这个时候才加载,如果内部类的静态的,即使变量非静态,代码也会在第2步加载完成,所有第2步和第8步不能共存的
总之,就是先外部,后内部,先static,后非static。先执行先写的,再执行后写的。
注意:
- 内部类的私有属性必须先创建一个内部类在进行引用
- 外部类的私有属性内部类可以直接引用
示例1(一定要看示例2)
以下代码执行后会有什么结果?会出现异常吗?
public class simple {
//静态内部类
static class in{
String s="?";//静态内部类的非静态变量
static{System.out.println(str);}//静态内部类的静态代码块
{System.out.println("太有趣了");}//静态内部类的非静态代码块
}
static String str="yh";//外部类的静态变量
static{System.out.println(str);}//外部类的静态代码块
{System.out.println((new in()).s);}//外部类的非静态代码块
public static void main(String[] args) {
simple simple=new simple();
}
}
输出结果:
yh
yh
太有趣了
?
加载顺序
- 先加载外部类中的静态变量,静态代码块(因为静态变量写在上面,所以静态代码块可以引用)
- 之后加载内部类,由于是静态内部类,所以会全部加载,又因为外部类静态代码块,静态变量已经加载,内部类可以方位外部类的所有属性和方法,所以能够引用str,但是静态代码块无法引用内部类的非静态变量
- 因为内部类是静态的,所以会先执行内部类的非静态代码块,输出“太有趣了”
- 然后再输出内部类的成员变量 s
看似合理?实际不对
首先结果是对的,但是理解的不太准确
示例2
public class simple {
static class in{
String s="内部类的变量";
static{System.out.println(str); }
{System.out.println("内部类的非静态代码块");}
public in(){
System.out.println("内部类的构造方法"); }
}
static String str="外部类的静态变量";
static{ System.out.println(str); }
public simple(){System.out.println("外部类的构造方法输出");}
{System.out.println("外部类的非静态代码块");}
public static void main(String[] args) {
simple simple=new simple();
}
}
输出什么呢?
外部类的静态变量
外部类的非静态代码块
外部类的构造方法输出
为什么?因为在主方法中没有调用内部类,虽然内部类是静态的,但是它没有被调用,所以是不会加载的。也就是示例1中,第二步执行的原因,是因为外部类的非静态代码块中使用了匿名内部类,才会先加载内部类,然后再引用内部类的变量。正常不会有人见了内部类然后不使用吧
示例3
如果你觉得没有问题了,那就来一段狗屁不通、没人会写的代码吧。
以下代码输出是个啥呢?
public class simple {
static class in{
String s="内部类的变量";
static{System.out.println(str); }
{System.out.println("内部类的非静态代码块");}
public in(){
simple s=new simple();
System.out.println(s.str1); }
}
static String str="外部类的静态变量";
String str1="外部类的非静态变量";
static{ System.out.println(str); }
public simple(){
//in in=new in();
System.out.println("外部类的构造方法输出");
}
{in in=new in();
System.out.println(in.s);}
public static void main(String[] args) {
simple simple=new simple();
}
输出:StackOverflowError 栈溢出错误
因为内部类、外部类互相引用了。在外部类的非静态代码块中使用了内部类的构造方法,而内部类的构造方法中又重新加载了外部类,会导致再次加载外部类的非静态代码块,造成死循环,所以就栈溢出了。
示例4
最后来一个卢老爷清明纪念版
以下代码输出什么?
public class simple {
static class in{
String s="卢本伟牛逼";
static{System.out.println(str); }
{System.out.println("十七张牌你能秒我?");}
public in(){System.out.println("代码就要笑着写");}
}
static String str="阿姨快一点啊";
static{ System.out.println(str); }
public simple(){
System.out.println("给阿姨倒一杯卡布奇诺");
}
{
in in=new in();
System.out.println(in.s);
System.out.println(new in().s);
}
public static void main(String[] args) {
simple simple=new simple();
}
/*
阿姨快一点啊
阿姨快一点啊
十七张牌你能秒我?
代码就要笑着写
卢本伟牛逼
十七张牌你能秒我?
代码就要笑着写
卢本伟牛逼
给阿姨倒一杯卡布奇诺
*/
}
需要注意的是,static代码块只会被加载一次,但是非静态代码块在new的时候是会重新加载的,所以"阿姨你快一点"输出一次,而"十七张牌你能秒我?"每创建一次,就执行一次
最后一个问题,如何在其他类中创建一个外部类中的非静态内部类?
outer out=new outer();//先创建一个外部类
outer.inner in=out.new inner();//使用外部类的new方法创建内部类
父子类
A a =new B() A为声明类,B为构造类
使用多态创建的时候,a的属性都是声明类的,无法使用子类的属性、变量的,方法则是构造类重写了就重写的优先,如果没有重写就使用声明类的
父子类在不同class下
可以看一下自己总结的这一片文章,里面有具体的父子类方法重写和调用,注意:
- static修饰的方法是不能被重写的,所以即使是多态(左父右子)的创建,使用static方法的时候,也是调用父类的static方法
- private修饰的方法是私有的,即使是继承父类,也不会将其private修饰的方法、变量进行继承的
- 在使用多态(左父右子)进行创建的时候,如果父类方法被子类重写,那么会被优先调用,如果没有被调用,是会调用父类本身的方法(如以上的static、private修饰的方法)
- 重写的方法是必须比父类方法的作用域更大的,如果更小,就不会视为重写,此时如果参数列表完全一致,会被认为方法同名,标红
父子类属于嵌套类
坏的很,一般都是这种情况进行判断的
但是,其实如果我们分别掌握了嵌套类的加载,以及父子类方法的调用,其实不会很难理解,但是需要注意:
- 内部类在调用的时候才会被加载,而父子类如果为嵌套类,那么使用多态创建时,一定都会被加载,顺序也遵从嵌套类的加载顺序,即使不使用多态,只创建子类,也会因为继承父类而调用父类静态代码块、非静态代码块、构造方法
- 嵌套类中,内部类是可以使用外部类的所有属性的,即使是private 私有的
- static方法还是不能被重写的,即调用的还是声明类的static
暂时想到这里,有了以后再补充,如果有错误,还请大佬指出。
贴一段代码测试使用
public class outer {
//外部类成员变量
public String outer_pub="outer_public";
protected String outer_pro="outer_pro";
String outer_def="outer_def";
private String outer_pri="outer_pri";
//外部类静态代码块
static{ System.out.println("outer静态代码块1"); }
static{ System.out.println("outer静态代码块2"); }
//外部类构造函数
public outer(){ System.out.println("outer构造函数执行"); }
//外部类静态方法
public static void test(){ System.out.println("outer static method"); }
//外部类成员方法
public void class_print(){ System.out.println("outer&inner print");}
public void pub_test(){System.out.println("outer pub test"); }
void def_test(){System.out.println("outer def test");}
protected void pro_test(){System.out.println("outer pro test");}
private void pri_test(){System.out.println("outer pri test");}
//非静态代码块
{
System.out.println("父类非静态代码块");
}
static class inner extends outer {
public String inner_pub="inner_public";
protected String inner_pro="inner_pro";
String inner_def="inner_def";
private String inner_pri="inner_pri";
//外部类静态代码块
static{ System.out.println("inner静态代码块1");}
//static{ System.out.println("inner静态代码块2"); }
public inner(){ System.out.println("inner构造函数"); }
public static void test(){ System.out.println(2); }
public void print(){ System.out.println("inner.print");}
public void pub_test(){System.out.println("inner pub test"); }
void def_test(){System.out.println("inner def test");}
protected void pro_test(){System.out.println("inner pro test");}
private void pri_test(){System.out.println("inner pri test");}
{
System.out.println("子类非静态代码块");
}
}
public static void main(String[] args) {
/*outer o=new inner();
o.pri_test();
o.test();*/
inner in=new inner();
in.pri_test();
in.test();
}
}