局部内部类、成员内部类、匿名内部类、静态内部类。
局部内部类:是指内部类定义在方法或代码块内的类。
1.1 与局部变量一样,不能用public, protected, private和static修饰。
1.2 只能访问外部类的方法或代码块中定义为final类型的局部变量。
1.3 只能在方法或代码块中使用,即只能在方法或代码块当中生成局部内部类的实例并且调用其方法,并不对外界透明。
例子:
package com.learnjava.innerclass;
class LocalInner
{
int a = 1;
public void doSomething()
{
int b = 2;
final int c = 3;
// 定义一个局部内部类
class Inner3
{
public void test()
{
System.out.println("Hello World");
System.out.println(a);
// 不可以访问非final的局部变量
// error: Cannot refer to a non-final variable b inside an inner
// class defined in a different method
// System.out.println(b);
// 可以访问final变量
System.out.println(c);
}
}
// 创建局部内部类的实例并调用方法
new Inner3().test();
}
}
public class LocalInnerClassTest
{
public static void main(String[] args)
{
// 创建外部类对象
LocalInner inner = new LocalInner();
// 调用外部类的方法
inner.doSomething();
}
}
成员内部类:定义在外部类方法之外的类,即外部类的成员。
2.1 可以直接使用外部类的所有成员和方法,不论是静态的,还是非静态的,即使是private的也可以访问。
可直接使用Outer.this表示外部类对象。
2.2 外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取,而不能通过inner.this。例如:
public class Outer {
// private Inner inner = new Inner();
// private String a = inner.b;
// private String a = inner.getB();
private String a = new Inner().b;
private class Inner {
private String b = "11";
public String getB() {
return b + "22";
}
}
public String getA() {
return a;
}
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.getA());
}
}
2.3 其他类要直接创建内部类,必须首先创建外部类,且受访问级别的限制。
Inner inner = (new Outer()).new Inner()
2.4 成员内部类不能含有static的变量和方法(除非定义为static final)。因为成员内部类需要先创建了外部类,才能创建它自己的,了解这一点,就可以明白更多事情,在此省略更多的细节了。
例子:
package com.learnjava.innerclass;
class MemberInner
{
private int d = 1;
private int a = 2;
// 定义一个成员内部类
public class Inner2
{
private int a = 8;
public void doSomething()
{
// 直接访问外部类对象
System.out.println(d);
System.out.println(a);// 直接访问a,则访问的是内部类里的a
// 如何访问到外部类里的a呢?
System.out.println(MemberInner.this.a);
}
}
}
public class MemberInnerClassTest
{
public static void main(String[] args)
{
// 创建成员内部类的对象
// 需要先创建外部类的实例
MemberInner.Inner2 inner = new MemberInner().new Inner2();
inner.doSomething();
}
}
3.1 就是没有名字的局部内部类。
3.2 与局部内部类不同的是,匿名内部类的类必须是预先定义好的已存在的类或接口。
3.3 匿名内部类隐式地继承了一个父类或者实现了一个接口。
3.4 因为没名字,因而默认只有无参数的构造函数,如果需要参数的,则需要该类有带参数的构造函数。例如:
public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city) {
// 注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final。
return new Inner(name, city) {
private String nameStr = name;
public String getName() {
return nameStr;
}
};
}
}
abstract class Inner {
Inner(String name, String city) {
System.out.println(city);
}
abstract String getName();
}
例子:
package com.learnjava.innerclass;
import java.util.Date;
public class AnonymouseInnerClass
{
@SuppressWarnings("deprecation")
public String getDate(Date date)
{
return date.toLocaleString();
}
public static void main(String[] args)
{
AnonymouseInnerClass test = new AnonymouseInnerClass();
// 打印日期:
String str = test.getDate(new Date());
System.out.println(str);
System.out.println("----------------");
// 使用匿名内部类
String str2 = test.getDate(new Date()
{
});// 使用了花括号,但是不填入内容,执行结果和上面的完全一致
// 生成了一个继承了Date类的子类的对象
System.out.println(str2);
System.out.println("----------------");
// 使用匿名内部类,并且重写父类中的方法
String str3 = test.getDate(new Date()
{
// 重写父类中的方法
@Override
@Deprecated
public String toLocaleString()
{
return "Hello: " + super.toLocaleString();
}
});
System.out.println(str3);
}
}
4.1 就是静态的成员内部类。定义时加上static。
4.2 不能和外部类有相同的名字。
4.3 只可以访问外部类的静态成员和静态方法,包括私有的。
4.4 可以直接引用Outer.Inner,即不需要创建外部类。
Outer.Inner inner = new Outer.Inner();
package com.learnjava.innerclass;
class StaticInner
{
private static int a = 4;
// 静态内部类
public static class Inner
{
public void test()
{
// 静态内部类可以访问外部类的静态成员
// 并且它只能访问静态的
System.out.println(a);
}
}
}
public class StaticInnerClassTest
{
public static void main(String[] args)
{
StaticInner.Inner inner = new StaticInner.Inner();
inner.test();
}
}