在一个类内部定义的类称为内部类
定义格式:
public class A
{
class B
{
//属性、方法定义
}
//属性、方法定义
}
上述内部类格式编译后会产生A.class和A$B.class,其中A称为外部类,B称为内部类
public class A
{
//属性、方法定义
}
class B
{
//属性、方法定义
}
而上述A和B类是正常的并列关系编译后只会产生A.class和B.class,他们是两个互不相同的类
内部类按区域可以分为成员内部类和局部内部类,其中成员内部类分为实例内部类和静态内部类,还有一种非常特殊的内部类匿名内部类。归纳起来内部类有4种类型:局部内部类、实例内部类、静态内部类、匿名内部类
局部内部类
局部内部类就像是局部变量一样,只能定义在方法中,可见范围是当前方法,不能用访问控制符(public、private、protected)及static修饰符来修饰,内部类具有以下特点
(1)局部内部类只能在当前方法中使用
class Outer
{
//Inner in=new Inner();//编译错误
public void method()
{
class Inner
{
int id;
String name;
}
Inner in=new Inner();//合法
}
}
(2)局部内部类不能包含静态成员
class Outer
{
public void method()
{
class Inner
{
//static int id;//编译错误
String name;//合法
}
}
}
(3)局部内部类里面定义的内部类也不能用访问控制符(public、private、protected)及static修饰符来修饰(4)局部内部类可以访问外部类所有成员,也可以访问所在方法内final类型的参数和变量
class Outer
{
int a=1;
public void method(final int d,int e)
{
int b=2;
final int c=3;
class Inner
{
int a1=a;//合法
// int b1=b;//编译错误
int c1=c;//合法
int d1=d;//合法
// int e1=e;//编译错误
}
}
}
匿名内部类
使用格式:
new <类或借口>()
{
//定义属性或方法
}
匿名内部类是一种特殊的内部类,它没有名字,常用于方法中,在GUI图像界面编程中常用于事件添加处理功能。因为其没有名字,因此需要在定义的同时使用,new关键字作为开始后面跟着匿名类需要继承的父类名或者是实现的接口,一般需要重写父类某些方法或者实现接口中所有方法。有以下几个特点
(1)匿名类本身没有构造函数,但会调用父类的构造方法
(2)匿名类尽管没有构造函数,但是可以在内部类中提供一段实例初始化代码
class Outer
{
Outer(int v)
{
System.out.println("Outer带参数构造函数");
}
Outer()
{
System.out.println("Outer构造函数");
}
public void method()
{
System.out.println("Outer的method方法");
}
}
public class InnerClassDemo1
{
public static void main(String[] args)
{
new Outer().method();
// (1)匿名类调用父类带参数的构造函数
Outer out = new Outer(5)
{
/* {//(2)实例初始化代码
System.out.println("实例初始化代码");
}*/
public void method()
{
System.out.println("小out的method方法");
}
};
out.method();
}
}
(3)内部类除了可以在外部类的方法中定义外,还可以在声明一个变量时定义匿名类
abstract class A
{
A a=new A()
{
void method()
{
System.out.println("A的method方法");
}
};
abstract void method();
}
(4)匿名类除了继承外还可以实现接口
class Sample
{
public static void main(String[] args)
{
Thread t=new Thread(new Runnable()
{
@Override
public void run()
{
for(int i=0;i<100;i++)
System.out.println(i);
}
});
t.start();
}
}
(5)匿名类和局部内部类一样可以访问外部类的所有成员
(6)匿名类与局部内部类一样在方法外是不可见的,因此可以起到封装作用
实例内部类
有些书又叫非静态内部类,是成员内部类的一种,没有static修饰,具有以下几个特点
(1)在创建实例内部类时,外部类的实例必须已经存在
(2)实例内部类的实例自动持有外部类实例的引用,即可以直接访问外部类所有成员,包括变量和成员方法,而外部类访问内部类必须通过内部类的实例去访问
(3)外部类实例与内部类实例间是一对多关系,一个内部类实例只会引用一个外部类实例看,而一个外部类实例对付零个或多个内部类实例
(4)在实例内部类中不能定义静态成员,而只能定义实例成员
(5)如果在实例内部类B与外部类A包含同名的成员,那么B中this.v表示类B的成员,A中this.v表示类A的成员
class A
{
int a1=5;
class B//B是A的内部类
{
private int b1=1;
public int b2=2;
//static int b3=3;//实例内部类中不能定义静态成员
class C{}//C是B的内部类
void testB()
{
test();//直接调用外部类的方法
int a2=a1;//直接调用外部类的变量
}
}
void test()//外部类A的方法
{
/* int v1=b1;//编译错误,不能直接访问内部类B的成员变量
int v2=b2;//编译错误,不能直接访问内部类B的成员变量
B.C c1=new C();//编译错误,不能直接访问内部类B的内部类C
*/
B b=new B();//合法
int v3=b.b1;//合法,可以通过内部类B的实例去访问b1
int v4=b.b2;//合法,可以通过内部类B的实例去访问b2
B.C c2=b.new C();//合法,可以通过内部类B的实例去访问内部类C
B.C c3=new B().new C();//合法,可以通过内部类B的实例去访问内部类C
}
}
静态内部类
用static修饰的内部类,有以下几个特点
(1)静态内部类的实例不会自动持有外部类的特定实例引用,在创建内部类实例时不必创建外部类实例
class A
{
static class B//B是A的静态内部类
{
int v=1;
}
}
class Tester
{
public void test()
{
A.B b=new A.B();
b.v=1;
}
}
上述客户类Tester创建类B实例时不必创建A的实例
(2)静态内部类不能直接访问所在外部类的实例成员,必须通过 外部类的实例去访问,但是可以直接访问外部类的静态成员
class A
{
private int a1;//实例变量
private static int a2;//静态变量
static class B//B是A的静态内部类
{
// int b1=a1;//编译错误,不能直接访问外部类A的实例变量
int b2=a2;//合法,可以直接访问外部类A的静态变量
int b3=new A().a1;//合法,可以通过类A的实例访问实例变量
}
}
(3)在静态内部类中可以定义静态成员和实例成员
class A
{
static class B//B是A的静态内部类
{
int a1;//实例变量
static int a2;//静态变量
}
}
(4)客户类可以通过完整的类名直接访问静态内部类的静态成员,但是不能这样访问实例成员
class A
{
public static class B// B是A的静态内部类
{
int v1;// 实例变量
static int v2;// 静态变量
public static class C// C是B的静态内部类
{
static int v3;// 静态变量
int v4;// 实例变量
}
}
}
class Tester
{
public void test()
{
A.B b = new A.B();
A.B.C c = new A.B.C();
b.v1 = 1;
b.v2 = 1;
// A.B.v1=1;//编译错误
A.B.v2 = 1;// 合法
A.B.C.v3 = 1;// 合法
}
}
内部类小结
主要优点:
(1)内部类对象能访问其所处类的私有属性和方法
(2)内部类能够隐藏起来,不被同一个包中的其他类访问(如果一个类只对某个类使用,可以将其定义为内部类)
(3)匿名内部类可以方便的用在回调方法中(图像编程的事件处理)
主要特征:
(1)内部类可以声明为抽象类,因此可以被其他的内部类继承,也可以声明为final的
(2)和外部类不同,内部类可以声明为private或protected,而外部类只能用public和default
(3)内部类可以声明为static的,但此时就不能再使用外层封装类的非static的成员变量
(4)非static的内部类中的成员不能声明为static的,只能在顶层类或static的内部类中才可以声明static成员
参考文献:
Java从入门到精通 高宏静
Java面向对象编程 孙卫琴