简单来说,内部类就是在类的内部定义的类,根据内部类定义的位置,我们可以将其分为成员内部类和局部内部类:
实例内部类即未被static修饰的成员内部类。使用时需要注意如下一些语法上的规定:
- 外部类中的任何成员都可以在实例内部类方法中直接访问。
- 实例内部类所处的位置与外部类成员位置相同,因此也受
public
、private等
访问限定符的约束。- 实例内部类中不可以定义static修饰的成员,但允许定义
final
修饰的static成员。- 在实例内部类方法中访问同名的成员时,优先访问自己的(
就近原则
),如果要访问外部类同名的成员,必须:外部类名称.this.同名成员
来访问。- 实例内部类对象
必须在先有外部类对象
前提下才能创建。- 实例内部类的非静态方法中包含了一个指向
外部类对象的引用
。- 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
实例展示:
class OuterClass {
private int data1=1;
int data2=2;
public static int data3=3;
public void func1() {
System.out.println("外部类func1");
}
//内部类可以被public、private等限定符修饰
public class InnerClass {
int data2=888;
//内部类可以定义被final修饰的静态成员变量
static final int SIZE = 999;
public void func2() {
System.out.println("内部类func2");
//默认就近访问同名成员
System.out.println(data2);
//使用类名访问外部类同名成员
System.out.println(OuterClass.this.data2);
//可直接访问外部类的成员
data1=111;
data3=333;
func1();
}
}
}
public class Test {
public static void main(String[] args) {
//两种创建内部类对象的方式:
//方式1:
//OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
//方式2:
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.func2();
}
}
运行结果:
被static
修饰的内部成员类称为静态内部类。使用静态内部类时同样要遵循一些语法规则:
- 在静态内部类中只能访问外部类中的静态成员,因为非静态成员需要使用引用来访问,如果非要访问则需要创建外部对象的引用。
- 同样外部类中不能直接访问静态内部类中的成员,如果要访问必须先要创建内部类的对象。
- 静态内部类所处的位置与外部类成员位置相同,也受
public
、private等
访问限定符的约束。- 在静态内部类方法中访问同名的静态成员时,优先访问自己的(
就近原则
),如果要访问外部类同名的成员,必须:外部类名称.同名成员
来访问。- 创建静态内部类对象时,不需要先创建外部类对象。
实例展示:
class OuterClass {
public int data1=1;
int data2=2;
public static int data3=3;
public void func1() {
System.out.println("外部类func1");
}
static class InnerClass {
public int data4=4;
public static int data5=5;
public void func2() {
System.out.println("内部类func2");
//只能直接访问外部类的静态成员。非静态成员需要对象的引用才能访问。
System.out.println(data3);
System.out.println(data4);
System.out.println(data5);
}
}
}
public class Test {
public static void main(String[] args) {
//静态内部类不依赖于外部类的对象,可直接如下创建:
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.func2();
}
}
运行结果:
定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用。根据是否具名将其分为方法内部类和匿名内部类,同时局部内部类还遵循如下语法规则:
- 局部内部类只能在所定义的方法体或
{}
内部使用。- 不能被
public
、static
等修饰符修饰。
下面分别讲解:
在方法中定义方法内部类相对来说是非常鸡肋的,这种方式开发中很少用到,大家目前了解语法即可。
实例展示:
class OuterClass {
public void func() {
class InnerClass {
private int a = 10;
public void test() {
System.out.println("方法内部类中的方法!");
}
}
//只能在方法体中使用方法内部类
InnerClass innerClass = new InnerClass();
innerClass.test();
}
}
public class Test {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.func();
}
}
匿名内部类是与new
关联的,在创建对象的时候定义类,new后面是父类或者父接口,然后是圆括号()
,里面可以是传递给父类构造方法的参数,最后是大括号{};
,里面是类的定义。
如果对象只会创建一次
,且不需要构造方法来接受参数,则可以使用匿名内部类,代码书写上更为简洁。匿名内部类在之后会频繁的使用,这里我们先来了解一下匿名内部类的语法:
new 父类(参数列表) {
//匿名内部类实现部分
};
或者
new 父接口() {
//匿名内部类实现部分
};
下面我们就以接口
为例,简单展示一下匿名内部类,我们先看两段代码:
代码1:
interface IA {
void test();
}
class AA implements IA {
@Override
public void test() {
System.out.println("类AA重写IA接口test方法");
}
}
代码2:
interface IA {
void test();
}
public class Test {
public static void main(String[] args) {
new IA() {
@Override
public void test() {
System.out.println("匿名内部类重写IA接口方法");
}
}.test();//这里调用了test()方法
}
}
分析: 上面的两段代码是对IA
接口的两种实现。代码1定义了一个类AA实现了IA接口并重写了IA接口的方法。代码2是采用了匿名内部类的实现方式,定义了一个没有名字的类实现了IA接口并重写了IA接口的方法,在只创建一次对象的情况下,这种代码2匿名的实现方式可以实现代码1相同的效果。