一.内部类的概念
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中, 可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。
剧透一下,内部类会在数据结构中用到,比如二叉树类的内部类就是结点类,专门用来服务二叉树
内部类和外部类在同一个.java文件里,但是会生成不同的字节码文件
public class Outer {
class Inner {
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/a31971e3a610657d6094d5323eea63b3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/98b8c3ded21b224979b1e23c824c15c8.png)
二.实例内部类
定义在类的内部,方法外面的,未被static修饰的内部类称为实例内部类
2.1 实例内部类的实例化
举例如下
public class Outer {
public int data1=10;
private int data2=20;
public static int data3=30;
class Inner {
//定义内部类的成员变量
public int data4=40;
private int data6=60;
//定义内部类的成员方法
public void testInner() {
System. out.println(data1);
}
}
}
要访问实例内部类,就要先实例化一个内部类的对象,语法格式如下
Outer outer=new Outer();//创建外部类对象
Outer.Inner inner=outer.new Inner();//使用外部类对象的引用调用内部类的构造方法
因为内部类也是外部类对象的成员,所以构造内部类对象前要先构造外部类,然后使用外部类对象的引用才能调用内部类的构造方法
内部类的创建还有一个简化版
Outer.Inner inner2=new Outer().new Inner();
上面的代码先创建了一个外部类对象,然后用这个外部类对象的引用调用了内部类的构造方法
2.2 实例内部类的特性
1.实例内部类可以访问外部类的任何成员
public class Outer {
public int data1=10;
private int data2=20;
public static int data3=30;
class Inner {
public int data4=40;
private int data6=60;
public void testInner() {
System.out.println(data1);//访问public成员变量
System.out.println(data2);//访问private成员变量
System.out.println(data3);//访问静态成员变量
}
}
}
class test {
public static void main(String[] args) {
Outer.Inner inner=new Outer().new Inner();//实例化实例内部类
inner.testInner();
}
}
下图为运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/bf69f71cf6a14d67a16fa1cf5f7e839a.png)
2.实例内部类里面不能有静态成员变量,除非被final修饰;不可以有静态成员方法
![](https://i-blog.csdnimg.cn/blog_migrate/85badcad3b03505d5c3c34ddc62f7a40.png)
因为实例内部类是依赖外部类对象存在的,而静态成员不需要依赖对象存在,二者发生了冲突,所以语法上不允许这样做。但是静态成员变量经过final修饰后会被编译器看作是常量,可以存在于内部类中。
3.实例内部类和外部类有同名变量时,优先访问自己的变量
public class Outer {
public int data1=10;
private int data2=20;
class Inner {
public int data1=30;
public void test() {
System. out.println("data1="+data1);
}
}
}
执行test方法
class test {
public static void main(String[] args) {
new Outer().new Inner().test();
}
}
//运行结果
data1=30
如果要访问外部类的同名变量,需要使用外部类名.this.变量名
public void test() {
System. out.println("data1="+Outer.this.data1);
}
//输出结果
data1=10
根据这个结果可以推测出实例内部类包含了外部类的引用this
4.实例内部类和外部类的地位相同,其成员也可以被各种限定符修饰
5.外部类不能直接访问内部类的成员(static final修饰的成员变量除外,可以通过类名访问),除非先创建内部类对象
三.静态内部类
被定义在类的内部,方法外面,被static修饰的类
3.1 静态内部类的实例化
静态内部类是外部类的静态成员。所以不依赖外部类的对象
实例化格式如下
Outer.Inner inner=new Outer.Inner();
其中Outer是外部类类名,Inner是内部类类名,Outer.Inner是引用变量inner的指向的对象类型
3.2 静态内部类的特性
1.静态内部类不存在外部类的this引用,不能访问外部类的非静态成员
public class Outer {
public int data1=10;
private int data2=20;
public static int data3=30;
static class Inner {
public void test() {
System.out.println(data1);//报错
System.out.println(data3);//输出30
}
}
}
如何在test方法中访问data1?创建外部类对象
static class Inner {
public void test() {
Outer outer=new Outer();
System.out.println(outer.data1);
}
}
2.静态内部类不依赖外部类的对象,可通过类名直接访问
public class Outer {
static class Inner {
static void test2() {//定义内部类的静态成员方法
System.out.println("Inner内部的test2()方法");
}
}
}
class test {
public static void main(String[] args) {
Outer.Inner.test2();//直接通过类名访问test2()方法
}
}
四.局部内部类
局部内部类是被定义在方法内,只能在该方法中实例化,一般不使用
举例
public static void test() {
int a=10;
class Inner {//Inner类被定义在test方法中
int data1=10;
double data2=2;
void test() {
a=20;//error
System.out.println(a);
System.out.println(data1);
}
}
new Inner().test();//在方法内实例化Inner类
}
1.局部内部类可以访问外部类的成员,但是不能对其更改
2.局部内部类不能被访问限定符,static限制
3.局部内部类只能在方法内部访问
五.匿名内部类
被定义在方法中,在定义的时候通过接口实例化
举例如下
//定义学生类
class Student {
int age;
public Student(int age) {
this.age = age;
}
}
class test {
public static void test() {
Student st1=new Student(10);//创建学生对象1
Student st2=new Student(12);//创建学生对象2
int ret=new Comparator<Student>(){//通过接口Comparator创建匿名内部类并实例化
@Override
public int compare(Student o1, Student o2) {//匿名内部类内部实现COmparator接口方法compare
return o1.age-o2.age;
}
}.compare(st1,st2);//用刚才创造的对象引用调用compare方法
System.out.println(ret);//输出compare方法的返回值
}
public static void main(String[] args) {
test();
}
}
//输出结果
-2
和局部内部类一样,匿名内部类可以访问方法内的变量,但是不能更改变量的值