定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类提供更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中其他类访问。内部类可以声明public、protected、private等访问限制,可以声明为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。static的内部类行为上象一个独立的类,非static在行为上类似类的属性或方法且禁止声明static的方法。内部类可以访问外部类的所有方法与属性,内部类被单成其外部类的成员,同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节,如内部类的属性。static的内部类只能访问外部类的静态属性与方法。匿名内部类适合用于创建那些仅需要一次使用的类。
内部类被作为成员内部类定义,而且不是局部内部类。成员内部类是一种与属性、方法、构造器和初始化块相似的类成员;局部内部类和匿名内部类则不是类成员。成员内部类分为两种:静态内部类(使用static修饰)和非静态内部类,
当在非静态内部类的方法访问某个变量时,系统优先在该方法内查找是否在该名字的局部变量,如果存在改名字的局部变量,就是用改变量;如果不存在则到内部类所在的外部类中查找是否存在改名字的属性,如果存在就是用。如果不存在编译错误。
如外部类属性、内部类属性与内部类里方法的局部变量通明,则通过使用this,外部类类名.this作为限制类区分。
public class DiscernVariable
{
private String prop = "外部类属性";
private class InClass
{
private String prop = "内部类属性";
public void info()
{
String prop = "局部变量";
//通过 外部类类名.this.varName 访问外部类实例属性
System.out.println("外部类的属性值:" + DiscernVariable.this.prop);
//通过 this.varName 访问外内部类实例的属性
System.out.println("内部类的属性值:" + this.prop);
//直接访问局部变量
System.out.println("局部变量的属性值:" + prop);
}
}
public void test()
{
InClass in = new InClass();
in.info();
}
public static void main(String[] args)
{
new DiscernVariable().test();
}
}
非静态内部类的成员可以访问外部类的private成员,但反过来不可以。非静态内部类成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类成员,则必须相示创建非静态内部类对象来调用访问其实例成员。根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量,创建实例等。总之,不允许在外部类的静态成员中直接使用非静态内部类。
public class Outer
{
private int outProp = 9;
class Inner
{
private int inProp = 5;
public void acessOuterProp()
{
//内部类可以直接访问外部类的成员
System.out.println("外部类的outProp属性值:" + outProp);
}
}
public void accessInnerProp()
{
//外部类不能直接访问内部类属性,下面代码出现编译错误
//System.out.println("内部类的inProp属性值:" + inProp);
//如需访问内部类成员,必须显式创建内部类对象
System.out.println("内部类的inProp属性值:" + new Inner().inProp);
}
public static void main(String[] args)
{
//执行下面代码,只创建了外部类对象,还未创建内部类对象
Outer out = new Outer();
}
}
public class TestStatic
{
//定义一个非静态的内部类,是一个空类
private class In{}
//外部类的静态方法
public static void main(String[] args)
{
//下面代码引发编译异常,因为静态成员(main方法)无法访问非静态成员(In类)
new In();
}
}
不允许在非静态内部类立定义静态成员
public class InnerNoStatic
{
private class InnerClass
{
/*
下面三个静态声明都将引发如下编译错误:
非静态内部类不能有静态声明
*/
static
{
System.out.println("==========");
}
private static int inProp;
private static void test(){};
}
}
非静态内部类里不能有静态方法、静态属性、静态初始化块。
静态内部类可以包含静态成员,也可以包含非静成员。静态成员不能访问非静态成员的规则,所以静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
public class TestStaticInnerClass
{
private int prop1 = 5;
private static int prop2 = 9;
static class StaticInnerClass
{
private static int age;
public void accessOuterProp()
{
//下面代码出现错误:静态内部类无法访问外部类的实例成员
System.out.println(prop1);
//下面代码正常
System.out.println(prop2);
}
}
}
外部类不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者类访问静态内部类的类成员,也可使用静态内部类的对象作为调用者来访问静态内部类的实例成员。
public class AccessStaticInnerClass
{
static class StaticInnerClass
{
private static int prop1 = 5;
private int prop2 = 9;
}
public void accessInnerProp()
{
//System.out.println(prop1);
//上面代码出现错误,应改为如下形式:通过类名访问静态内部类的类成员
System.out.println(StaticInnerClass.prop1);
//System.out.println(prop2);
//上面代码出现错误,应改为如下形式:通过实例访问静态内部类的实例成员
System.out.println(new StaticInnerClass().prop2);
}
}
java还允许在接口立定义内部类,接口立定义的内部类默认使用public static修饰。
外部类按常规的类访问方式使用内部类,唯一的差别是外部类可以访问内部类的所有方法与属性,包括私有方法与属性。如:
pinner p = new pinner();
p.index = 20;
p.Print();
---- 这种方式适合外部类的非static方法;
pouter po = new pouter();
pinner pi = po.new pinner();
pi.index = 40;
pi.Print();
---- 这种方式适合外部类的static方法;
内部类类似外部类的属性,因此访问内部类对象时总是需要一个创建好的外部类对象。内部类对象通过‘外部类名.this.xxx’的形式访问外部类的属性与方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);
如果需要在其他类中访问内部类,可以使用:
(1)外部类提供创建内部类的方法供其他类使用。如:
// 外部类
pinner getInner()
{
return new pinner();
}
// 其他类
pouter.pinner pi = po.getInner();
pi.Print();
(2)直接创建内部类的对象。如:
pouter po = new pouter();
pouter.pinner pi = po.new pinner();
pi.Print();
内部类可以声明在外部类的方法中或语句块中。如果内部类需要访问包含它的外部类方法或语句块的局部变量或参数,则该局部变量或参数必须是final的。外部类的其他方法、其他类无法访问声明在方法内部或块内部的内部类。
如果一个类继承内部类,则创建该类的对象时需提供一个外部类的对象作为构造方法的参数。如:
class Car
{
class Wheel
{
}
}
class SuperWheel extends Car.Wheel
{
SuperWheel(Car car)
{
car.super();
}
public static void main(String [] args)
{
Car car = new Car();
SuperWheel wl = new SuperWheel(car);
}
}
如果创建命名的内部类没有多少实际意义时,可以创建匿名的内部类。比如使用内部类实现接口的功能(如事件处理器、适配器等),而功能的差异较大,需要根据实际的情况创建相应的内部类时,可以使用匿名内部类。简单的示例如下:
interface WebView
{
void doGet();
}
class A
{
WebView ShowName()
{
return new WebView()
{
void doGet()
{
System.out.println("Name");
}
};
}
WebView ShowCode()
{
return new WebView()
{
void doGet()
{
System.out.println("Code");
}
};
}
}
最后,JAVA 内部类还有一个作用,那就是实现JAVA的多继承。JAVA本身是不允许多继承的,如果我们想一个类继承多个基类,就可以使用内部类。通过内部类分别继承一个基类,外部类创建内部类的对象,并使用内部类的方法,变相地实现了多继承。