1:常规内部类。
常规内部类的规格是如下图:
01:要求声明在外部类 的内部 ,作为跟 外部类 的 实例数据域 和 实例方法 同一级别的成员,而 不可以是其他地方。
02:因为是跟外部类的 实例数据域 和 实例变量是同一级别的 所以说 可以将他视为 一个实例变 量 , 或者实例方法(注意这里暂且不讨论 静态内部类的情况)。
03:所以这个类的 修饰符 跟 同一级别的 实例变量 和 实例数据域 的修饰符是一样的,public private , protected , 默认 ,abstract , final ,也可以是 static(后面讨论).
04:常规内部类的数据域 不可以有 静态数据域 和 静态方法 , 因为 在加载外部类的时候,并不会加载这个常规内部类,所以这里弄一个静态的东西是不合理的,也是不合法的。
05:访问常规内部类的成员 的 唯一方法是 方法必须通过外部类的一个活实例!也就是说,在运行时必须 有一个 与 这个 内部类实例对象 相关的 外部类实例对象。
06:我们 在内部类中 访问这个 外部类的 任意的【修饰符 为 private 、默认、protected、public】 实例数据域 也可以 使用外部类的类名的形式去访问外部类的静态数据域。 以及访问外部类的 实例方法 和 静态方法, 此时我们将这个常规内部类看作一个常规的方法就可以了。
—>反过来说也是成立的: 我们也可以在外部类 中new一个 内部类对象, 通过这个内部类对象来访问内部类的 任意的【修饰符 为 private 、默认、protected、public】 实例数据域
06:实例化内部类的时候 , 必须有一个 与这个内部类相关联的外部类的实例对象,才可以在这个外部类对象的基础上 创造 这个内部类实例对象。
01:在 外部类的 实例方法中 实例化 内部类对象的写法:
这么写的原因是:外部类实例方法 代码正在进行初始化, 换句话说,已经有一个外部类 实例了,此时已经 外部类的实例对象已经被创建出来了,我们才可以这么写。
02:在外部类的 静态方法中 实例化 内部类对象的写法:
//因为外部类的 静态方法,在外部类 被加载到虚拟机的时候已经被激活,此时并没有 这个实例化的外部类对象,所以我们需要先 实例化外部类对象, 在外部类对象的基础上在实例化这个内部类对象。 之后才可以访问这个内部类对象上面的方法。
03:在不相关的另一个类中访问 外部类对象的写法:
//在另一个不相干 的类Variable 的main方法 中 访问 另一个不相干的外部类的内部类的写法如上图:
因为:要访问一个外部类的内部类的时候,必须有一个 外部类实例对象,我们需要在这个 外部类实例对象 上面才可以 创造一个内部类, 之后才可以访问这个内部类中的数据和方法。
要点提示:
Points :在一个外部类 的 外面的某个类(例如上边的 不相干的类 Variable类),加入要访问 当前的外部类的内部类, 一定要考虑一下几点:
A:在脑子 将外部类 和内部类 想想成一个 外边的大盒子 大盒子里面 嵌套个小盒子。
B:访问 大盒子的 任何内容自不用说了, 当访问 小盒子的内容的时候 ,我们的理解思路是:首先 可以访问到 外部类这个大盒子 , 然后可以访问到 里面的 小盒子。【注:如果小盒子 都访问不到 那就无从谈起 new一个 内部类对象 ===> 也无法访问到内部类 中的任何数据域和方法了】
C: 在B的基础上,我们假设可以 访问到了内部类 ,那么 首先我们 可以对这个内部类 做一个提升, 提升到 外部类的档次, 这个是假设的提升,实际也是这么回事,这是其中的一个理解方法。这仅仅是 一中理解方式 。
D:或者考虑这种理解方式:当 访问内部类 里面的 数据域或者是方法的时候 ,要考虑到可见性。
如果是 private : 则不可以被 外部类的外部的某一个类 访问到。【符合 规范】
如果是 默认 修饰符 : 则要比较 外部类的外部的某一个类 所处的包 和 当前内部 类所处的包【借用 外部类的 包】 是否在同一个包。
如果是protected : 不仅要考虑 是否是 同一个包【同上】 , 还要考虑 继承性。
如果是public: 都可以被访问到。
07:一定要记住 常规内部类的实例对象 是依附于 外部类实例对象而存在的, 总是向 内部类 实例对象 传递 一个对外部类对象的隐含引用。
因此 就可以理解 为什么 在外部类的实例方法 那么写 , 在外部类的静态方法有那样写,在不相干的类中有那样写, 以及在不相干的外部类的静态方法中也需要遵循一点 必须先有外部类实例对象才能更有内部类实例对象。
—:至此记住几点:
a:常规内部类中部 不可以 有静态的成员,因为java虚拟机无法在外部类初始化的时候,进行初始化加载,不合理,也不合法。
b:常规内部类 在 外部类中的位置, 是跟 外部类的 方法和 数据域是平级的 .
c: 访问常规内部类的时候 , 必须先有外部类的实例对象 ,然后在这个外部类对象的基础上创建内部类。 他是分析各种写法的原因所在。
d:常规内部类 可以访问 外部类的 实例变量 和 静态变量,访问静态变量的时候推荐使用外部类名字的形式,访问外部类的实例变量的时候 推荐使用 外部类名字.this.外部类变量名子 的形式。
解释常规内部了可以访问外部类的实例变量的原因:
01:可以将常规内部类当作是一个实例方法,此时实例方法为什么不可以访问 自己对象的实例变量呢?
02:常规内部类 是依附于 外部类对象 而存在的(而不是说:常规内部类 依附于 外部类而存在!)。也就是说 外部类对象一旦创建 ,此时这个外部类对象 就自身携带了这个内部类了,为什么这个 内部类不可以访问 外部类的实例变量呢?
09:常规内部类 可以看作是一个外部类的一个 成员, 常规内部类 可以继承一个自己的父类,这个父类可以是正常的父类,也可以是抽象的父类, 也可以implements一个接口, 但是我们必须在这个常规内部类 中实现抽象的方法,它的一切行为,跟其他的继承,封装 都一模一样。
内部类 也可以具备 构造方法 , 在构造内部类对象的时候,我们同样也是沿着构造方法链进行的。
但是内部类就是不可以有静态的成员。
08:在常规内部类的实例方法中访问,访问 内部类的数据和访问外部类的数据 的引用形式。
a:要从内部类 代码中 引用 内部类自身的实例 , 使用this。
b:要从内部类 代码内部 引用 外部类的this (外部类的实例) , 要使用 外部类名字.this 的形式。
比如:
内部类与外部类之间的成员互相访问
01:内部类 可以访问 外部类 的 任何成员,包括private成员。
02:外部类 访问 内部类 的成员 需要 创建 内部类的 对象,之后 可以 访问 内部类 的 任何 成员,包 括private成员,需要注意的是成员内部类不可以有静态成员。
03:当外部类 的成员 和 内部类的 成员重名时单单用this是区分不了的。在内部类中访问外部类的成员 时可以用如下语法区分 :
<外部类类名>.this.<外部类中需要被访问的成员名>;
04:解释 外部类 为什么可以直接访问 内部类的 所有的变量【public 、默认修饰符、protected、private】
Java语言规范里只说了外部类可以访问内部类的 private/protected/默认/public成员,内部类也可以访问外部类的private/protected/默认/public 成员,但是没有规定死要如何实现这种访问。
JVM规范则在大多数时候把每个类都看作等价于top-level的,也就是说JVM不关心外部类和内部类之间的嵌套关系。
对JVM来说,enclosing class和inner class在大部分情况下都是“不相关的两个类”,视为一个包中的两个类,所以它们之间相互是不能访问对方的private/protected/默认/public成员的。
但是在实现中,衔接Java语言规范与JVM规范的就是Java源码级编译器(例如javac、ECJ等)。简单来说就是在外部类/内部类之间要访问对方的 private/protected/默认/public 成员时,Java源码级编译器**会生成合适的“access method”**来提供合适的可访问性,这样就绕开了原本的成员的可访问性不足的问题。
—>参考:https://blog.csdn.net/dnntjc/article/details/91659087
综上,内部类private变量[推广:所有的修饰符修饰的 变量和方法]可被外部类直接访问,这由Java源码级编译器在编译过程中实现。
---->以上针对的是 常规内部类 和 静态内部类 都可以 实现 外部类和内部类 之间 所有修饰符 变量以及方法的 相互访问。
在同一个外部类中 多个内部类之间的 访问:
Require/demand tips:
One: 在同一个外部类中 , 一个内部类 访问 另一个内部类 的时候 需要 new 被访问的那个内部类 的对 象。
Two: 此时 在同一个 外部类中 使用 new 关键字 一个内部类 访问 另一个内部类 的时候,我们不需要 考虑被访问的那个内部类 的可见性【public / 默认 / protected / private】 都可以被另一个 内部类访问到。
Three: new出来 被访问的内部类对象之后, 要访问 这个被new 出来的 内部类对象中的 任何元素 都不需要考虑可见性【public /默认 / protected / private】 都可以被访问到。
------备注:这是经过实验 出来的 , 没有经过官方文档的查询, 我并不知道 内部是如何实现的!!!特别想知道 java是如何做到的,但是不得而知。
请关注公众号:计算机软件技术