内部类,位于一个类内部的类,可以看出内部类依然是一个类,所有依旧能被编译成独立的.class文件。
但是内部类属于外部类的成员,依附于外部类而存在,所以编译成的.class文件前面冠以外部类的类名和"$"
具体说一说内部类有哪些特点吧。
一、特点
1.不能被public修饰
一个.java文件可以有很多个类,但是只有一个类可以被public修饰,并且这个类的类名必须与文件名相同。在这种情况下不允许有其他的类使用public进行修饰,所以内部类同样不允许使用public修饰。
2.内部类的声明方法比较特殊,由于内部类依附于外部类而存在,所以实例化时必须按照以下格式:
Outer.Inner inner = outer.new Inner();
3.内部类,类似于外部类的成员,可以随意调用外部类的成员变量。而外部类则不能调用内部类的成员变量,调用时必须实例化内部类的对象进行调用(内部类的成员对于外部类来讲意义相当于局部变量,所以是没办法用外部类的对象进行调用的,同理,内部类的成员是不能用访问修饰符进行修饰的,就像局部变量一样,只在局部起作用,不存在其他类调用的可能性)
二、类别
内部类总的来说可以分为2种(按位置不同),即成员内部类和局部内部类.然后成员内部类的一个特例 是静态内部类,局部内部类的一个特例是匿名内部类.下面详细区分这几种内部类.
1.成员内部类
成员内部类是最普通的内部类,成员内部类是定义在某个类的内部,作为类成员.他在编译时生成的.class文件的 格式为: 外部类名$成员内部类名.class.在创建成员内部类的对象前,需要先实例化一个外部类的对象.成员内部类可以调用外部类的所有成员.
public class OuterClass { class Inner{ //成员内部类 } }
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
2.静态内部类
一般情况下当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何条件。此外,内部类还拥有其外围类的所有元素的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。然后,在你访问此外围类的成员时,就是用那个引用来选择外围类的成员。而这些所有细节,都是编译器帮你处理了。
如果不需要内部类对象和其外部类对象之间有关系,那么可以将内部类声明为static,静态内部类不会隐式的持有一个外部类对象的引用。静态内部类与普通内部类还有一个区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含静态内部类,而静态内部类可以包含所有这些东西。
在没有创建外部类对象的i时候,可以直接创建静态内部类的对象,同时,静态内部类可以引用外部类的静态成员变量或静态方法,但是不能引用外部的普通成员.(就比如,正常的成员方法可以调用静态成员变量和方法,而静态方法不能调用普通的成员变量和方法一样。)并且静态内部类不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
静态内部类的使用:
1.在接口中直接实现接口的抽象方法,创建所有实现类需要的公共代码
正常情况下,不能在接口内部放置任何代码,但静态内部类可以作为接口的一部分。你放到接口中的任何类都会自动的是public和static。因为类是static的,只是将静态内部类置于接口的命名空间内,这并不违反接口的规则。你甚至可以在内部类中实现其外围接口,如果你想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共有,那么使用接口内部的静态类会显得非常方便。
public class OuterClass { class Inner{ //成员内部类 } private static class StaticInner{ //静态内部类 } }
3.局部内部类
局部内部类是定义在某的方法内部的类.只能在方法内中使用,一旦方法执行完毕,局部内部类就会从内存中是释放.他在编译时生成的.class文件的格式为: 外部类名$1内部类名.class,直接在方法内部创建局部内部类的对象.换句话说,局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
public class OuterClass { class Inner{ //成员内部类 } private static class StaticInner{ //静态内部类 } public void eat() { class JubuInner{ //局部内部类 int i = 0; } JubuInner a = new JubuInner(); System.out.println(a.i); } }
4.匿名内部类
匿名内部类就是没有名字的内部类。匿名内部类也是唯一一种没有构造器的类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口,形式如:new XXX(){};
同样的,匿名内部类也是不能有访问修饰符和static修饰符的。
Child c = new Child() {//匿名内部类
public void eat() {
System.out.println("i am not drinking");
}
};
c.eat();
}
有的时候,某一个方法只使用一次,为了调用方法而实例化一个对象十分浪费空间,我们就可以选择匿名内部类
三、内部类对象的实例化
public static void main(String[] args) { //外部类对象 OuterClass out = new OuterClass(); //实例化一个外部类对象 //成员内部类 OuterClass.InnerClass in = out.new InnerClass(); //实例化成员内部类对象 //静态内部类 Outer.StaticInner staticInner = new StaticInner(); //实例化静态内部类对象 //局部内部类 out.eat(); //由于局部内部类只需直接在声明完后就直接就在该方法内实例化对象,故可以直接调用 //匿名内部类 out.drink(); }
四、总结内部类的其他优点
1.内部类的存在使得Java的多继承机制变得更加完善
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏
五、全部代码展示
public class OuterClass { class Inner{ //成员内部类 } static class StaticInner{ //静态内部类 } public void eat() { class JubuInner{ //局部内部类 int i = 0; } JubuInner a = new JubuInner(); System.out.println(a.i); } public void drink() { Child c = new Child() {//匿名内部类 public void eat() { System.out.println("i am not drinking"); } }; c.eat(); } public static void main(String[] args) { OuterClass out = new OuterClass(); OuterClass.Inner in = out.new Inner(); OuterClass.StaticInner staticInner = new StaticInner(); out.eat(); out.drink(); } }