在Java中,可以将一个类定义在另一个类里面或者方法里面,这样的类称之为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类以及静态内部类,下面先来了解一下这四种内部类的用法。

1.成员内部类

成员内部类是最普通的内部类,它的定义位于另一个类的内部,形如下面的形式:

class C{
	class D{
	}
}

因为类C相对于类D在外面,我们且称类C为外部类。
成员内部类可以无条件访问外部类的所有属性和方法。但是外部类想要访问内部类属性或方法时,必须要创建一个内部类对象,然后通过该对象访问内部类的属性或方法。

成员内部类访问外部类

class C{
	private String name="外部类";
	public void run(){
		System.out.println("外部类奔跑");
	}
	class D{
		public void say(){
			System.out.println(name);
			run();
		}
	}
}

成员外部类访问内部类

class C{
	private String name="外部类";
	public void run(){
		System.out.println("外部类奔跑");
	}
	public void eat(){
		D d=new D();
		System.out.println(d.value);
		d.say();
	}
	class D{
		private String value="DDD";
		public void say(){
			System.out.println(name);
			run();
		}
	}
}

外部类属性或方法隐藏
如果成员内部类的属性或方法与外部类的同名,将导致外部类的这些属性或方法在内部类被隐藏,也可以使用以下格式调用:

外部类.this.属性/方法
class C{
	private String name="外部类";
	public void run(){
		System.out.println("外部类奔跑");
	}
	public void eat(){
		D d=new D();
		System.out.println(d.value);
		d.say();
	}
	class D{
		private String value="DDD";
		private String name="内部类";
		public void say(){
			System.out.println(C.this.name);
			System.out.println(name);
			run();
		}
	}
}

创建内部类对象
创建内部类有两种方式:

package interclass;

import interclass.C.D;

public class Test10{
	public static void main(String[] args){
		C c=new C();//以下为创建方式1
		C.D d=c.new D();
		C.D d1=c.getClassD();//此为创建方式2
		c.run();
		c.eat();
	}
}
class C{
	private String name="外部类";
	public void run(){
		System.out.println("外部类奔跑");
	}
	public D getClassD() {
		// TODO Auto-generated method stub
		return new D();
	}
	public void eat(){
		D d=new D();
		System.out.println(d.value);
		d.say();
	}
	class D{
		private String value="DDD";
		private String name="内部类";
		public void say(){
			System.out.println(C.this.name);
			System.out.println(name);
			run();
		}
	}
}

输出为:

外部类奔跑
DDD
外部类
内部类
外部类奔跑

成员内部类的访问权限:
成员内部类前可以加上四种访问修饰符:
private:仅外部类可访问
protected:同包下或继承下可访问
default:同包下可访问
public:所有类都可以访问

2.局部内部类

局部内部类存在于方法中。
他和成员内部类的区别在于局部内部类的访问权限仅限于方法或作用域内。

class K{
	public void say(){
		class J{
		}
	}
}

3.匿名内部类

匿名内部类就是没有名字的内部类,也正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有一个前提条件:必须继承一个父类或者实现一个接口。
实例1:不使用匿名内部类来实现抽象方法

package interclass;
abstract class Person{
	public abstract void eat();
}
class Child extends Person{
	public void eat(){
		System.out.println("eat something");
	}
}
public class Demo {
	public static void main(String[] args){
		Person p=new Child();//抽象类不能被实例化,只能使用其继承子类的实例化并向上转型为抽象类才可以调用抽象类中的抽象方法
		p.eat();
	}
}

运行结果:

eat something

可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只是用一次,那么将其编写为独立的一个类是很麻烦的。这个时候我们就可以引入匿名内部类。
实例2:匿名内部类的基本实现

package interclass;
abstract class Person{
	public abstract void eat();
}
public class Demo {
	public static void main(String[] args){
		Person p=new Person(){//匿名内部类-代表着抽象类子类
			public void eat(){
				System.out.println("eat something");
			}
		};		
		p.eat();
	}
}

运行结果:

eat something

可以看到,我们直接将抽象类Person中的方法在打括号中实现了,这样便可以省略一个类的书写。并且匿名内部类还可以应用于接口之上:
实例3:在接口上使用匿名内部类

package interclass;
interface Person{
	public void eat();
}
public class Demo {
	public static void main(String[] args){
		Person p=new Person(){//匿名内部类-代表着接口子类
			public void eat(){
				System.out.println("eat something");
			}
		};		
		p.eat();
	}

}

由上面的例子可以看出,只要一个类是抽象的或者是一个接口,那么其子类中的方法都可以使用匿名内部类实现。

4.静态内部类

静态内部类和成员内部类相比多了一个static修饰符。它与类的静态变量一样,是不依赖于外部类的。同时,静态内部类也有其特殊性。静态内部类不能使用外部类的非静态变量和方法。同时,我们也可以直到,内部类里面是不能含静态属性或者方法的。

class U{
	static class I{
	}
}

5.内部类的好处

1.完善了Java多继承机制,由于每一个内部类都可以独立地继承接口或者类,所以无论外部类是否继承或者实现了一个接口,对于内部类都没有影响。
2.方便写事件的驱动程序。