非静态内部类中能不能拥有静态方法或属性?

最近在重读 《Think in Java》的时候,发现了下面这段话:

普通内部类的字段和方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和方法,也不能包含嵌套类(也就是静态内部类)。但是嵌套类能够包含所有这些东西。

错误的答案

自己先想了下为什么普通内部类不能够包含静态属性和方法,想了半天也想不通,就到网上搜了下相关问题,结果大部分答案都是如下所示:


某种解释

但是上面这个答案是不正确的,类在以下几种情况下就会进行加载:

  1. 遇到newgetStaticputStaticinvokeStatic这四条字节码指令时,类如果没有执行过初始化,需要先触发初始化。生成这4条指令最常见得Java代码场景是:使用new关键字实例化对象的时候,读取和设置一个类的静态属性(被final修饰,已经在编译器放入常量池的除外),调用一个类的静态方法。
  2. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,需要对其进行初始化。
  3. 当初始化一个类的时候,如果其父类还没出进行过初始化,需要对这个父类进行初始化。
  4. 当虚拟机启动的时候,用户指定的那个要执行的类(包含main方法)需要先进行初始化。

也就是说,如果我们主类需要使用到内部类的静态方法的时候,会先初始化这个内部类,上面答案说的调用先于加载的情况就不会发生。

正确的答案

那为什么Java中不能在内部类中有静态变量和方法呢?
我觉得应该从静态内部类和非静态内部类的定义来说明。

首先我们来说说内部类的作用。
内部类是为了弥补Java中没有多继承的缺陷而产生的。所以静态内部类用于那些与外部类关系不是特别大,不需要调用外部类中的非静态属性和非静态方法。换句话说,静态内部类就相当于一个可以获取到其他类的静态私有属性和私有方法的类,除此之外和放在外面的类不没有什么区别。

public class Test {

    public static void main(String[] args) {
        A.a();
    }

    private static int aa = 1;

    static class A{
        private static void a(){
            System.out.println(aa);
        }
    }
}

静态内部类与静态方法

而非静态内部类则不一样了,非静态内部类比静态内部类更像多继承一些。其能够访问外部类的所有属性和方法。非静态内部类想要做到这一点需要持有一个外部类对象的引用。那么问题就来了,如果说我们允许非静态内部类中存在静态方法,那在调用重名方法的时候怎么知道调用的是哪个方法呢?
我们先看下外部类是如何处理这种情况的:


    public static void main(String[] args) {
        Outer.a();
        Outer.Inner.a();
    }
}

class Outer{

    static void a(){
        System.out.println("这是外部类的方法");
    }

    static class Inner{

        static void a(){
            System.out.println("这是内部类的方法");
        }
    }
}

输出结果为:

这是外部类的方法
这是内部类的方法

可以看出,我们可以通过Outer.aOuter.Inner.a来确定到底使用的是哪一个方法。

非静态内部类调用自身的非静态方法

但是如果是非静态内部类呢?因为非静态内部类中持有外部类对象的引用,我们如何确定想要使用的是哪个方法呢?
先看下非静态方法:

public class Test {
    public static void main(String[] args) {
        Outer.Testb test = new Outer().getTestb();
        test.b();
    }
}

class Outer{
    void b(){
        System.out.println("外部类的b方法");
    }
    class Testb{
        void b(){
            System.out.println("Testb的方法");
        }
    }

    Testb getTestb(){
        return new Testb();
    }
}

输出为:

Testb的方法

所以对于内部类与外部类存在方法名与参数列表都相同的方法时,我们能够准确地确定执行的是哪一个方法。对于内部类对象来说,执行的一定是自己内部的方法,而不是外部类的方法。

非静态内部类调用外部类的非静态方法

因为我们生成的是Testb对象,调用的是Testb类中的b方法,如果想要调用外部类中的方法,我们不能通过内部类对象直接调用,需要通过内部类方法调用。

public class Test {

    public static void main(String[] args) {
        Outer.Testb test = new Outer().getTestb();
        test.b();
    }
}

class Outer{
    void b(){
        System.out.println("外部类的b方法");
    }

    void c(){
        System.out.println("外部类的c方法");
    }
    class Testb{
        void b(){
          System.out.println("Testb的方法");
          System.out.println("通过Testb的方法调用外部类的方法");
          c();
        }
    }

    Testb getTestb(){
        return new Testb();
    }
}

输出:

Testb的方法
通过Testb的方法调用外部类的方法
外部类的c方法
真正的答案

到现在就很明显了,如果允许内部类中有静态方法,而外部类中又有一个相同名称和参数类型的静态方法,那我们就不知道如何确认调用的是哪一个方法了。而这才是为什么非静态内部类中不能拥有静态方法或者属性的原因。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,707评论 2 9
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,065评论 1 32
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,531评论 0 6
  • Advanced Language Features 知识点:一. static修饰符 static修饰符可以用来...
    风景凉阅读 422评论 0 0
  • 每年的四月份,都会带专业生来湖南师范大学参加术科考试,而我总是提前过来做准备工作,为的是学生过来就能吃到家里的味道...
    致远私人体脂管理阅读 265评论 2 1