1 内部类的定义
内部类是定义在另一个类中的类。一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。以下范例代码中默认省略getter和setter。
内部类可以访问自身的数据域,也可以访问所在外围类的数据域。内部类对象有一个隐式引用,指向创建它的外部类对象。
public class OuterClass {
private String name ;
private int age;
class InnerClass{
public InnerClass(){
name = "chenssy";
age = 23;
}
public OuterClass getOuterClass(){
return OuterClass.this;
}
// 编译器生成的默认构造器,实际不显示
public InnerClass(OuterClass outerClass){
outer = outerClass;
}
}
}
创建内部类的方式
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.display();
}
如果我们需要生成内部类对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了
public OuterClass getOuterClass(){
return OuterClass.this;
}
2 内部类的分类
在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。
2.1 成员内部类
成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
public class OuterClass {
private String str;
public void outerDisplay(){
System.out.println("outerClass...");
}
public class InnerClass{
public void innerDisplay(){
//使用外围内的属性
str = "chenssy...";
System.out.println(str);
//使用外围内的方法
outerDisplay();
}
}
/*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
2.2 局部内部类(方法内部类)*
有这样一种内部类,它是嵌套在方法内的,这个类的使用主要是在解决比较复杂的问题时,想创建一个类来辅助我们的解决方案,但又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员内部类一样被编译,但它只能在该方法和属性中被使用,出了该方法就会失效。
public class Parcel5 {
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}
2.3 匿名内部类
匿名内部类是没有名字的内部类,格式如下:
new SuperType(parameter p){
//重写方法
}
上述类的父类是SuperType,说它没有名字,实际上是指未定义子类的名字。
SuperType可以是接口,于是内部类就要实现这个接口。它也可以是基类,此时内部类中的重写方法对其扩展。注意SuperType是接口或者基类,不是内部类的名字。内部类没有名字,由于构造器的名字必须与类名相同,因此匿名内部类不能有构造器。
下面是一个老虎类的匿名内部类的实现方式
public class InnerClassTest {
public static void main(String[] args) {
new Animal(){
public void eat(){
System.out.println("老虎吃肉");
}
}.eat();
}
}
class Animal{
public void eat(){
System.out.println("动物吃东西");
}
}
匿名内部类常常用在接口的实现类中,在需要特定接口类型参数的地方,传一个匿名内部类,真的很方便。比如在对集合List进行排序时,传入一个Comparator类型的匿名内部类是常用方式。
Collections.sort(new ArrayList<Integer>(), new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
});
2.4 静态内部类
关键字static中提到Static可以修饰成员变量、方法、代码块,它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类。有时,使用内部类知识为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。静态内部类与非静态内部类之间存在较大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:
1、 它的创建是不需要依赖于外围类的。
2、 它不能使用任何外围类的非static成员变量和方法。
public class OuterClass {
Integer age = 30;
static String name = "土皮";
public void display(){
System.out.println("OuterClass...");
}
/*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
}
public class InnerClass{
public OuterClass getOuterClass(){
return OuterClass.this;
}
public void display(){
System.out.println("innerClass...");
}
}
public static class StaticInnerClass{
/*
\* 静态内部类只能访问外围类的静态成员变量和方法,比如name
\* 不能访问外围类的非静态成员变量和方法
*/
public void display(){
System.out.println(name);
System.out.println("staticInnerClass...");
}
}
}
3 内部类的用途
根据我这只菜鸡为数不多的代码阅读,我发现内部类也就匿名内部类在一些需要接口实现类的地方用的相对多点,比如Runnable、Comparator接口。
待更新