一个类定义在另一个类的内部,这个类就叫做内部类。内部类一般可分为4种:成员内部类、局部内部类、匿名内部类、静态内部类。
成员内部类
成员内部类是最普通的内部类,它的定义为另一个类的内部,形式如下:
package com.review.innerClass; public class Outer { //内部类 class Inner { } }从定义形式上看,成员内部类相当于外部类的一个成员,它可以访问外部类的所有成员变量及方法。
package com.review.innerClass; public class Outer { private int i = 0; public int j = 10; private static int k=3; private final int m=2; public void m(){ } private void n(){ } class Inner { public void g(){ System.out.println(i);//外部类的私有变量 System.out.println(j);//外部类公共变量 System.out.println(k);//外部类静态变量 System.out.println(m);//外部类常量 m();//外部类公共方法 n();//外部类私有方法 } } }当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法在成员内部类中,当外部类想访问内部类的成员时,需先建立一个内部类的对象,再通过内部类对象的应用来访问。
package com.review.innerClass; public class Outer { public void m(){ int k=new inner().i; } class Inner { private int i=3; } }那么如何创建内部类的对象呢?成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
package com.review.innerClass; public class Outer { public static void main(String[] args) { //第一种方式 Outer outer=new Outer(); Inner inner=outer.new Inner(); //第二种方式 Inner inner1=new Outer().new Inner(); System.out.println(inner.i+""+inner1.i); } class Inner { private int i=3; } }内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限,而外部类只能被public和包访问两种权限修饰。
局部内部类
局部内部类是定义在一个类的一个方法或者一个作用域里面的类。
package com.review.innerClass; public class Outer2 { public void p(){ class Inner{ } } }局部内部类就像是方法里面的一个局部变量一样,它跟成员内部类一样,可以访问外部类的所有成员变量及方法,当局部内部类拥有和外部类同名的成员变量或者方法时,访问方式跟成员内部类一致,其访问仅限于方法内或者该作用域内,没有public、protected、private以及static修饰符。
匿名内部类
匿名内部类隐藏了内部类的类名称,在我们编写事件监听时常常用到匿名内部类,使用匿名内部类能够在实现父类或者接口中的方法情况下同时产生一个相应的对象,但是前提是这个父类或者接口必须先存在才能这样使用。我们常用的Comparator比较器匿名内部类使用如下:
package com.review.innerClass; public class Score { private int score; private String name; public int getScore() { return score; } public void setScore(int score) { this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.review.innerClass; import java.util.Collections; import java.util.Comparator; import java.util.List; public class Outer3 { public void g(List<Score> list){ Collections.sort(list, new Comparator<Score>() { @Override public int compare(Score o1, Score o2) { return o1.getScore()-o2.getScore(); } }); } }比较集合中Score对象按照score大小排序,其中
new Comparator<Score>() { @Override public int compare(Score o1, Score o2) { return o1.getScore()-o2.getScore(); } });就是一个匿名内部类。当然我们也可以直接写一个类实现Comparator接口,如下
package com.review.innerClass; import java.util.Comparator; public class ScoreComparator implements Comparator<Score> { @Override public int compare(Score o1, Score o2) { return o1.getScore() - o2.getScore(); } }虽然说这样也能实现同样的效果,但是既冗长又难以维护,匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。匿名内部类也是不能有访问修饰符和static修饰符。
静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
package com.review.innerClass; public class Outer4 { public static void main(String[] args) { Outer4.Inner inner=new Outer4.Inner(); } static class Inner{ } }总结
一:成员内部类[类的成员]:
成员内部类,就是作为外部类的成员。
特点:
(1)可以直接使用外部类的所有成员和方法,即使是private的。
内部类访问外部成员 outer.this.id
内部类访问外部方法 outer.this.getStr()
(2)内部类可以定义跟外部类相同的成员和方法。
(3)内部类的创建:
//第一种方式 Outer outer=new Outer(); Inner inner=outer.new Inner(); //第二种方式 Inner inner1=new Outer().new Inner();
(4)外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取(静态方法;非静态方法获取时可以直接Inner in=new Inner();)
(5)成员内部类不能含有static的变量跟方法,因为成员内部类需要先创建了外部类,才能创建它自己
二、局部内部类[方法里面的局部变量]:
在方法中定义的内部类称为局部内部类
特点:
(1)不可以定义静态变量
(2)可以访问外部内的局部变量,但是必须是final的
(3)访问局部内部类对象必须现有外部内对象
三、静态嵌套类:
定义在类中,任何方法外,用static修饰
特点:
(1)静态内部类可以定义静态或非静态成员
(2)静态内部类只能访问外部类的静态成员
(3)外部类访问静态内部类的成员(非静态成员需要实例静态内部类)
(4)静态内部类不可以用private来修饰
(5)生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别
四、匿名内部类
特殊的局部内部类,通过匿名实现接口
只要一个类是抽象的或者是一个接口,那么其子类中的方法都可以使用匿名内部类 来实现,常用在多线程实现上。
特点:
(1)匿名内部类是唯一一种无构造方法类
(2)隐藏不想别人知道的操作
为什么有内部类
(1)内部类提供了某种进入外围类的窗户。
(2)也是最吸引人的原因,每个内部类都能独立地继承一个接口,而无论外围类是否已经继承了某个接口。
因此,内部类使多重继承的解决方案变得更加完整。在项目中,需要多重继承,如果是两个接口,那么好办,接口支持多重继承。如果是两个类呢?这时只有使用内部类了。