(二十)内部类详解(转)
转自:http://www.cnblogs.com/dolphin0520/p/3811445.html
一.内部类基础
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下面就先来了解一下这四种内部类的用法。
- 成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Circle { double radius = 0 ; public Circle( double radius) { this .radius = radius; } class Draw { //内部类 public void drawSahpe() { System.out.println( "drawshape" ); } } } |
这样看起来,类Draw像是类Circle的一个成员,Circle称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
package 封装类; public class Outer { private String name; //外围类成员属性 Outer(String name){ //构造器 this.name=name; } public void aaa(){ //外围类成员方法 System.out.println("im outer method"); } public Outer getOuter(){ System.out.println("getouter()"); return Outer.this; //外部类名+“.”+this 相当于外部类的对象引用 } class Inner{ //内部类 Inner(){ System.out.println(name); //内部类可以调用外部类的任何权限的成员 包括private } } public static void main(String[] args) { Outer out=new Outer("xiaoming"); Outer.Inner in=out.new Inner(); // .new 可以创建内部类的对象 out=out.getOuter(); } }
结果:
xiaoming
getouter()
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
1
2
|
外部类. this .成员变量 外部类. this .成员方法 |
public class Outer { String name="zhangsan"; public void aaa(){ System.out.println("im outer aaa()"); } class Inner{ String name="lisi"; public void aaa(){ System.out.println(name); System.out.println(Outer.this.name); } } public static void main(String[] args) { Outer out=new Outer(); Outer.Inner in=out.new Inner(); in.aaa(); } }
结果:
lisi
zhangsan
- 虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
public class Outer { String name="zhangsan"; public void aaa(){ Inner in=new Inner(); System.out.println(in.name); in.aaa(); } class Inner{ //内部类 String name="lisi"; public void aaa(){ System.out.println("im inner method"); } } public static void main(String[] args) { Outer out=new Outer(); out.aaa(); } }
结果:
lisi
im inner method
- 成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
public class Outer { private String name="out"; Inner getInner(){ return new Inner(); } public class Inner{ String name="inner"; } public static void main(String[] args) { //第一种,用 .new 关键字创建内部类对象 Outer out=new Outer(); Outer.Inner in=out.new Inner(); System.out.println(in.name); //第二种,用方法创建 Outer.Inner in1=out.getInner(); System.out.println(in1.name); } }
结果:
inner
inner
解析: 可见,无论是哪一种都必须先创建外部类的对象。
- 内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。
public class Outer {
private String name="out";
Inner getInner(){
return new Inner();
}
private class Inner{
String name="inner";
}
}
class text{
public static void main(String[] args) {
Outer out=new Outer();
Outer.Inner in=out.new Inner(); //这行报错,显示:The type Outer.Inner is not visible
}
}
2.局部内部类
- 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
class Person{} public class Outer { Person getPerson(){ class Inner extends Person{ int age=0; } return new Inner(); } }
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
3.匿名内部类
class Person{void aaa(){System.out.println("outer method");} } public class Outer { public static void main(String[] args){ Person p=new Person(){ protected String name="innerName"; //父类Person没有所以p无法访问name成员属性 public void aaa(){ System.out.println("inner method"); //覆盖Person类的aaa() } }; p.aaa(); } }
结果:
inner method
解析: Person p=new Person(){}; 意义是:创建一个继承自Person类的匿名类的对象。
- 匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
- 如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求这个参数是final类型的。
4.静态内部类
- 静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Outer {
public static void main(String[] args) {
Outer.Inner in=new Outer.Inner();
System.out.println(in.name);
in.aaa();
}
static class Inner{
String name="innerName";
public void aaa(){
System.out.println("inner method");
}
}
}
解析: 本来创建内部类对象时一定要用外部类对象来创建,但是此时内部类的是static,并不依赖于外部类,但是此时static内部类无法访问外部类中的非static成员。
- 一个外部类继承另一个外部类,其中的内部类无法被覆盖
public class Outer extends Text{ class A{ A(){ System.out.println("im outer A"); } } public static void main(String[] args) { new Outer(); } } class Text { class A{ A(){ System.out.println("Im text A"); }} Text(){ new A(); } }
结果:
Im text A
解析: Outer和Text 均有内部类A ,new Outer(); 我们希望Outer中的A 把父类Text的A类覆盖掉,可事实是不行。
- 一个内部类继承另一个内部类,子类的方法会覆盖父类的方法。
public class Outer extends Text{ class A extends Text.A{ void aaa(){ System.out.println("im outer A"); } } public static void main(String[] args) { new Outer(); } } class Text { class A{ void aaa(){ System.out.println("Im text A"); } } Text(){ new A().aaa(); } }
结果:
Im text A
解析: 结果是不能覆盖,这是因为加红色部分 new A().aaa(); 中 Text的A不能覆盖Outer中的A ,所以aaa()只能取Text类中的内部类A的方法。