1. 成员内部类
2. 静态成员内部类
3. 局部内部类
4. 匿名内部类
内部类最吸引人的:每个内部类都能独自继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没影响。也就从侧面实现了除接口外的多重继承。
它使得程序的逻辑更加紧凑和自洽!
成员内部类
成员内部类的含义是像成员变量那样,所以自然也就可以有权限修饰符。
成员内部类可以拥有 private、protected、public及包的访问权限:
如果成员内部类分别用以下权限修饰符修饰,结果如下:
(1) private,则只能在外部类的内部访问;
(2) public,任何地方都能访问;
(3) protected,则只能在同一个包下或者继承外部类的情况下访问;
(4) 默认,只能在同一个包下访问。
这一点和外部类有一点不一样,外部类只能被public和protected两种权限修饰符进行修饰。
1. 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
2. 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。
3. 如果要访问外部类的同名成员,需要以特定的形式进行访问
1-3示例如下:
public class InnerClass1 {
private String outer1 = "outer1";
private static String outer2 = "outer2";
public String common3 = "outer.common3";
/*
* 这样看起来,类InnerClass像是类InnerClass1的一个成员。
*/
class InnerClass {
public String common3 = "inner.common3";
void fun() {
// 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
System.out.println(outer1);
System.out.println(outer2);
// 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。
System.out.println(common3);
// 如果要访问外部类的同名成员,需要以下面的形式进行访问
System.out.println(InnerClass1.this.common3);
}
}
// 而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
InnerClass getInnerInstance() {
return new InnerClass();
}
// 成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
public static void main(String[] args) {
// 第一种方式:
InnerClass1 outter = new InnerClass1();
InnerClass inner = outter.new InnerClass(); // 必须通过Outter对象来创建
// 第二种方式:
InnerClass inner1 = outter.getInnerInstance();
}
}静态成员内部类
既然也是成员,那么自然也可以用权限修饰符修饰。
静态成员内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似。
不能使用外部类的非static成员变量或者方法,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
当内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是内部类的成员。
public class InnerClass4 {
private String outer1 = "outer1";
private static String outer2 = "outer2";
public static String common3 = "common3";
static class InnerClass {
public static String common3 = "common3";
void fun() {
// 不能使用外部类的非static成员变量或者方法:
// 因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
// System.out.println(outer1);
System.out.println(outer2);
// 当内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是内部类的成员。
System.out.println(common3);
}
}
}局部内部类
局部内部类的含义是像方法里的局部变量一样,所以自然不能有权限修饰符。
是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
public class InnerClass2 {
void fun() {
class InnerClass {
int inner = 1;
}
System.out.println(new InnerClass().inner);
}
}匿名内部类
匿名比较常用,不但方便而且使代码更加容易维护。
匿名内部类不能有访问权限修饰符和static修饰符的。
匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。
匿名内部类在编译的时候由系统自动起名为 Outter$1.class。
一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
public class InnerClass3 {
public static void main(String[] args) {
Runnable myRunner = new Runnable() {
@Override
public void run() {
// do sth
}
};
}
}