在Java中,允许在一个类的内部定义类,这样的类称为“内部类”,这个内部类所在的类称为“外部类”。
根据内部类的位置、修饰符和定义方式的不同,内部类可以分为以下4种形式:
(1)成员内部类
创建内部类对象的具体语法格式:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名()
——————————————————————————————————————————————————————
//定义外部类Outer
class Outer{
int m = 0; //定义外部类的成员变量
void test1(){ //定义外部类的成员方法
System.out.println("外部类成员方法");
}
//定义成员内部类Inner
class Inner{
int n = 1;
void show1(){ //1.定义内部类方法,访问外部类成员变量和方法
System.out.println("外部类成员变量m = " + m);
test1();
}
void show2(){
System.out.println("内部类成员方法");
}
}
void test2(){ //2.定义外部类方法,访问内部类变量和方法
Inner inner = new Inner();
System.out.println("内部类成员变量n = " + inner.n);
inner.show2();
}
}
//定义测试类
public class Example{
public static void main(String[] args){
Outer outer = new Outer(); //创建外部类对象
Outer.Inner inner = outer.new Inner(); //创建内部类对象(通过外部类对象创建内部类对象)
//Outer.Inner inner = new Outer().new Inner(); //这一行跟上一行的效果是一样的(语法格式:外部类名.内部类名 变量名 = new 外部类名().new 内部类名())
inner.show1(); //测试在成员内部类中访问外部类成员变量和方法
outer.test2(); //测试在外部类中访问内部类成员变量和方法
}
}
——————————————————————————————————————————————————————
(2)局部内部类
也叫“方法内部类”,就是定义在某个局部范围中的类,它和局部变量一样,都是在方法中定义的,其有效范围只限于方法内部。
——————————————————————————————————————————————————————
//定义外部类Outer
class Outer{
int m = 0;
void test1(){
System.out.println("外部类成员方法");
}
void test2(){
//1.定义局部内部类Inner,在局部内部类中访问外部类变量和方法
class Inner{
int n = 1;
void show(){
System.out.println("外部类变量m = " + m);
test1();
}
}
//2.在创建局部内部类的方法中,调用局部内部类变量和方法
Inner inner = new Inner();
System.out.println("局部内部类变量n = " + inner.n);
inner.show();
}
}
//定义测试类
public class Example{
public static void main(String[] args){
Outer outer = new Outer();
outer.test2(); //通过外部类对象调用创建了局部内部类的方法
}
}
——————————————————————————————————————————————————————
(3)静态内部类
创建静态内部类对象的基本语法格式:
外部类名.静态内部类名 变量名 = new 外部类名().静态内部类名()
与【成员内部类】相比:
1.在形式上,静态内部类只是在内部类前增加了static关键字;
2.在功能上,静态内部类中只能访问外部类的静态成员,同时通过外部类访问静态内部类成员时,可以跳过外部类从而直接通过内部类访问静态内部类成员。
——————————————————————————————————————————————————————
//定义外部类Outer
class Outer {
static int m = 0; //定义外部类静态变量m
static class Inner{
void show(){
System.out.println("外部类静态变量m = " + m); //静态内部类访问外部类静态成员
}
}
}
//定义测试类
public class Example{
public static void main(String[] args){
Outer.Inner inner = new Outer.Inner(); //静态内部类可以直接通过外部类创建
inner.show();
}
}
——————————————————————————————————————————————————————
(4)匿名内部类(比较难懂)
创建匿名内部类的基本语法格式:
new 父接口(){
//匿名内部类实现部分
}
——————————————————————————————————————————————————————
//定义动物类接口
interface Animal{
void shout();
}
public class Example{
public static void main(String[] args){
String name = "小花";
//定义匿名内部类作为参数传递给animalShout()方法
animalShout(new Animal(){
public void shout(){ //实现shout()方法
System.out.println(name+"喵喵……"); //从Java8开始,局部内部类、匿名内部类可以访问非final的局部变量
}
});
}
//定义静态方法animalShout(),接收接口类型参数
public static void animalShout(Animal an){ //调用传入对象an的shout()方法
an.shout();
}
}
——————————————————————————————————————————————————————
需要注意的是:
程序中访问了局部变量name,而局部变量name并没有使用final修饰,程序也没有报错,这是JDK8开始有的特性,允许在局部内部类、匿名内部类中访问非final修饰的【局部变量】;而在JDK8之前,局部变量前必须加final修饰符,否则程序编译报错。
对于初学者而言,可能会觉得匿名内部类的写法较难理解,下面分两步介绍匿名内部类的编写:
(1)在调用animalShout()方法时,在方法的参数位置写上new Animal(){},这相当于创建了一个实例对象,并将对象作为参数传给animalShout()方法。在new Animal()后面有一对大括号{},表示创建的对象为Animal的子类实例,该子类是匿名的。具体代码如下:
animalShout(new Animal(){});
(2)在大括号{}中编写匿名子类的实现代码,具体代码如下:
animalShout(new Animal(){
public void shout(){
System.out.println(name+"喵喵……");
}
})