在学习java内部类时,自己脑洞开了,想了几种情况并做了测试,结果如下:
一、静态内部类:
- 刚开始我在外部类中定义了一个静态内部类的引用类型的成员变量,想验证:
①外部类中是否可以直接创建其内部类对象? (可以。)
②外部类是否能访问到内部类的私有变量? (可以。)
③可以把引用声明为静态的吗? (事实上任何引用类型应该都可以,只不过我还没试过。)
- 初始代码如下:
class Outer
{
static StaticInner inner = new StaticInner();
//直接创建一个静态内部类成员变量
public static int a = 10;
public static void method()
{
System.out.println("In Inner Class Method! inner.a :" + inner.a);
//外部类可以通过引用访问静态内部类的私有变量a
}
static class StaticInner
{
private int a = 100;
public int geta()
{
return a;
}
public void innerMethod()
{
System.out.println("In Static Inner Class Method! Outer.a :" + Outer.a);
//内部类通过 类名.变量名 访问外部类同名变量
method();
}
}
}
public class InnerTest
{
public static void main(String args[])
{
Outer.StaticInner in = new Outer.StaticInner();
in.geta();
Outer.inner.innerMethod(); //访问静态成员变量inner 此时访问不到私有变量a
}
}
二、然后我又想:可以定义静态引用类型成员变量 是因为内部类是静态内部类吗?
在外部类中可以用常规方法,定义一个静态内部类的引用及对象:
StaticInner inner = new StaticInner();
在其他类中,想要定义一个静态内部类对象,可以把静态内部类看成一个嵌入在外部类中的静态成员,用类名.静态成员名访问:外部类.内部类 引用名 = new 外部类.内部类();
e.g: Outer.StaticInner inner = new Outer.StaticInner();
原声明和定义:static StaticInner inner = new StaticInner(); //正确!
然后我把静态内部类的static去掉了,自然就变成了成员内部类(成员内部类中不能定义静态的成员变量和方法,可以访问外部类中所有成员,包括静态和非静态的。 在成员内部类的方法中this指向此内部类的对象,用外部类.this访问外部类对象。)
原静态内部类变为成员内部类后,原声明和定义出现错误,错误如下:
No enclosing instance of type Outer is accessible. Must qualify the allocation with an enclosing instance of type Outer
(e.g. x.new A() where x is an instance of Outer).
- 然后我又猜想:难道是我当初的想法出错了吗,不是所有的类都可以声明为静态引用类型,我便也把原声明和定义中的static也给去掉了,然后错误消失,代码如下:
class Outer
{
StaticInner inner = new StaticInner();
public int a = 10;
public void method()
{
System.out.println("In Static Inner Class Method! Outer.a :" + inner.a);
//外部类可以访问到内部类中私有变量
}
class StaticInner
{
private int a = 100;
public void innerMethod()
{
System.out.println("In Static Inner Class Method! Outer.a :" + Outer.this.a);
//注意:这个访问外部类同名变量的方式 Outer.this.a
method();
}
}
}
三、成员内部类:然后我又注意到,成员内部类定义对象的方式和静态内部类有所不同:
①引用的声明与静态内部类相同: 外部类.内部类 引用名; e.g: Outer.MemberInner inner;
②创建对象方式有所不同: (总而言之,成员内部类对象的创建是基于一个已存在的外部类对象创建的)
方式一:先创建一个外部类对象,然后用此外部类对象创建内部类对象
e.g: Outer out = new Outer(); inner = out.new MemberInner();
方拾二:直接创建外部类对象的同时创建内部类对象
e.g: inner = new Outer().new MemberInner();
- 在此基础上,也就看明白报错问题中的提示e.g,然后我又百度了一下这个问题,看到了一个不错的解释,在如下链接:
按作者的解释,我的理解是:成员内部类是一种动态载入内存的,静态成员类是随着类的载入而载入内存的,这也就不难理解两种不同内部类在创建方式上为什么有如此不同。静态内部类与静态成员变量一样存在于静态存储区,只要外部类载入内存,便可以单独存在所以创建对象时,像访问静态成员一样可以直接用外部类名.内部类名来创建;而成员内部类是要在已分配空间的存在的外部类对象中动态开辟一块空间存放,所以在创建成员内部类对象时要首先创建一个外部类对象,才能继续在这块空间创建一个内部类对象,并且此内部类对象绑定在外部类的这个对象上。
- 理解了成员内部类对象的创建后,修改代码如下:
class Outer
{
static MemberInner inner;
//先创建一个成员内部类引用
private int a = 10;
public Outer()
{
inner = new MemberInner();
//这样便可以随着外部类对象创建同时创建一个成员内部类对象
}
public static void method()
{
System.out.println("In Inner Class Method! inner.a :" + inner.a);
//外部类可以通过引用访问内部类的私有变量a
}
class MemberInner
{
private int a = 100;
public int geta()
{
return a;
}
public void innerMethod()
{
System.out.println("In Static Inner Class Method! Outer.a :" + Outer.this.a);
method();
}
}
}
public class InnerTest
{
static Outer o = new Outer();
//普通类可以直接声明静态引用类型成员变量并直接创建对象。
public static void main(String args[])
{
o.inner.innerMethod();
}
}
说明:
- 我采用的是在外部类构造函数中创建成员内部类的对象,在创建外部类对象的同时创建一个内部类对象。
- 创建普通类的静态引用类型成员变量时可以直接创建对象,如上代码中InnerTest
四、既然都记录到这了,就把剩下两个内部类一起说了。
- 本地内部类:定义在方法内的内部类,同在方法中定义的变量一样,本地内部类只能在定义它的方法中使用;而且不能用访问限定符(public,private等)限定;不能定义静态的成员变量和方法;可以访问外部类所有成员。
- 示例如下:
public class Outer
{
int member = 10;
public void containInnerClass()
{
class LocalInner
{
public void print()
{
System.out.println(member);
}
}
LocalInner inner = new LocalInner();
}
//LocalInner inner = new LocalInner(); 错误:无法访问!
}
- 匿名内部类:没有名字的内部类,在建立对象时完成对类的定义。
- 在定义时,要么给出类的超类,要么给出类要实现的接口(只能有一个);对外部类的访问权限同本地内部类相同;常见的用途是在建立GUI应用程序时为组件添加事件监听器对象
- 三种示例:
//从一个有无参构造函数的超类创建匿名内部类及其对象
public abstract class Super1
{
public abstract void method();
}
Super1 s = new Super1(){
public void method()
{
System.out.println("Hello!");
}
};
//从一个有带参数构造函数的超类创建匿名内部类及其对象
public abstract class Super2
{
public Super2(int i)
{
}
public abstract void method();
}
Super2 s = new Super2( 10 ){
public void method()
{
System.out.println("Hello!");
}
};
//从一个接口创建匿名内部类及其对象
interface Super
{
public void method();
}
Super s = new Super(){
public void method()
{
System.out.println("Hello!");
}
};
四、小白总结:
- 现在发现这些问题好多都是对底层原理不清造成的,如果学习编程语言不从底层原理理解,会学的很难而且对问题理解的也不那么透彻。比如在外部类中,创建成员内部类的静态引用类型成员变量这件事。
- 静态内部类创建对象:Outer.StaticInner inner = new Outer.StaticInner();
- 成员内部类创建对象:Outer out = new Outer(); Outer.MemberInner inner = out.new MemberInner(); 或 Outer.MemberInner inner = new Outer().new MemberInner(); 访问外部类成员可用 Outer.this.成员名
- 本地内部类:定义在方法体内,也作用于在方法体内,不可用任何访问限定符修饰。
- 匿名内部类:借用超类或接口创建对象的同时定义的没有名字的类。
- 外部类可以通过引用访问内部类私有成员,所有类型均可声明为静态的。
- 具体这四种类的应用和作用还没有实践和体验过,以后在开发过程中再积累。
- 我还是个小白,有什么错误请批评指正,都是最浅层次的见解,没有翻阅相关权威书籍。
这里引用一篇我觉得解释的比较好的博客的链接:点击此处