package com.test.hello;
class Outter
{
public static String name = "";
}
class Inner
{
private Outter 隐式实例 = new Outter();
}
1.为什么要有Static内部类?
答:通过理解下面这段话来找出答案:
静态内部类可以在生成对象的时候,不需要外部类对象,它的目的可能是为了把一个类隐藏在另一个类中或者是为了防止在一个大项目中多个类的重名
简单的说,声明为静态的内部类和一个普通类的功能是一样的,就可以把它当作一个普通的类一样使用
当然这样的话,它就不能访问其外部类中的非静态成员了。
2.隐式:解释成“默认”、偷偷地、不漏痕迹地。
结合有疑问的语句理解:
Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。
翻译成:Java编译器在创建内部类对象时,偷偷地的把其外部类对象的引用也传了进去并一直保存着。
3.初始化块解释:(什么是初始化块:就是和成员变量平级的一个“{}”块,可以结合什么是成员变量来理解)
在Java中,有两种初始化块:静态初始化块和非静态初始化块.
静态初始化块:使用static定义,当类装载到系统时执行一次.若在静态初始化块中想初始化变量,那仅能初始化类变量,即static修饰的数据成员.
非静态初始化块:在每个对象生成时都会被执行一次,可以初始化类的实例变量.
非静态初始化块会在构造函数执行时,且在构造函数主体代码执行之前被运行.
括号里的是初始化块,这里面的代码在创建java对象时执行,而且在构造器之前执行!
其实初始化块就是构造器的补充,初始化块是不能接收任何参数的,定义的一些所有对象共有的属性、方法等内容时就可以用初始化块了初始化!!
好处是可以提高初始化块的复用,提高整个应用的可维护性。--《疯狂java讲义》
4.静态初始化块的加载时间及顺序
加载时间:静态初始化块和变量都是在类加载的时候执行(把加载换成了执行,什么是类加载,java要执行代码,首先都得把类什么 的放到JVM里面,把类放到JVM你们就是类加载)
顺序:非Static成员变量、非Static初始化块、Static成员变量、Static初始化块、构造函数
Static的成员变量的初始化和 初始化块的执行都是在类加载的时候执行了,所以他们总是先于非Static的成员变量的初始化和非Static初始化块执行;
而Static成员变量和Static初始化块的执行顺序是按照代码的先后顺序排列的(谁放前面谁先执行),
非Static成员变量和非Static初始化块的执行顺序也是谁放前面谁先执行;
而构造函数总是在非Static成员变量初始化、非Static初始化块执行、Static成员变量初始化、Static初始化块执行完成后才执行;
5.Outter outter = new Outter()和Class.forName("com.test.hello.Outter")的区别
Class.forName("com.test.hello.Outter"):调用类加载器加载,结合初始化顺序理解:此时执行了类中Static的成员变量的初始化和初始化块;
Outter outter = new Outter():执行了Static的成员变量的初始化和初始化块(假如先前没执行过的话),然后执行非Static的成员变量的初始化和初始化块,
然后执行构造函数
6.当时还有个疑问,就是刘亮想直接通过静态内部类中来访问外部类的静态变量
如下代码:
package com.test.hello;
class Outter
{
public static String name = "";
public static class Inner
{
}
}
public class Test extends Object
{
public static void main(String[] args)
{
System.out.println(Outter.Inner.name);
}
}
这怎么理解呢,
1.内部类只是编译时的一个概念,实际上他们是两个不同的类
2.Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。
那么问题想象就变成了下面的代码:
package com.test.hello;
class Outter
{
public static String name = "";
}
class Inner
{
private Outter 隐式实例 = new Outter();
}
而问题转化成了:通过Inner类来直接访问(Inner.name)Outter类的变量为什么不行?(上面的 代码已经解释了)。