父类、子类、嵌套类


全都是基于java 9 的 不同版本有没有差异,我也不太清楚,有知道的大佬给补充以下。

嵌套类加载顺序

new一个对象时,代码的执行顺序:

  1. 加载外部类静态代码块、静态变量
  2. 加载内部类静态代码块、静态变量
    内部类如果需要有静态代码块,静态变量,就必须是静态内部类
  3. 加载外部类非静态代码块
  4. 加载内部类非静态代码块
  5. 执行外部类的构造方法
  6. 执行外部类的构造方法
  7. 加载外部类的非静态变量
  8. 加载内部类的变量
    如果内部类是非静态的,这个时候才加载,如果内部类的静态的,即使变量非静态,代码也会在第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
太有趣了
?

加载顺序

  1. 先加载外部类中的静态变量,静态代码块(因为静态变量写在上面,所以静态代码块可以引用)
  2. 之后加载内部类,由于是静态内部类,所以会全部加载,又因为外部类静态代码块,静态变量已经加载,内部类可以方位外部类的所有属性和方法,所以能够引用str,但是静态代码块无法引用内部类的非静态变量
  3. 因为内部类是静态的,所以会先执行内部类的非静态代码块,输出“太有趣了”
  4. 然后再输出内部类的成员变量 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();
    }


}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值