目录
内部类是指当前的类定义在类的内部,或者方法的内部。内部类分为实例内部类,静态内部类,匿名内部类、普通内部类(基本不使用)
实例内部类
class OuterClass {
public int data1 = 1;
private int data2 = 2;
public static int data3 = 3;
//实例内部类
class Innerclass {
}
}
你也可以在实例内部类中定义普通成员变量和普通成员方法
class Innerclass {
public int data4 = 4;
private int data5 = 5;
public void test() {
System.out.println(data4);
System.out.println(data5);
System.out.println("内部类test方法");
}
}
在普通类中也可以有和内部类同名的test方法
class OuterClass {
public int data1 = 1;
private int data2 = 2;
public static int data3 = 3;
//实例内部类
class Innerclass {
……
}
public void test() {
System.out.println("外部类test方法");
}
}
定义好了我们应该如何使用呢? 第一个问题是:如何获得一个实例内部类对象。如果我们按照原来的方法实例化我们发现是行不通的
我们可以类比这来学习,如果你要访问OuterClass中的data1应该如何访问呢?
OuterClass outerClass = new OuterClass();
System.out.println(outerClass.data1);
同样我们也用 . 来获得实例内部类对象
OuterClass outerClass = new OuterClass();
OuterClass.Innerclass innerclass = outerClass.new Innerclass();
可以把这两句代码合并成一句
OuterClass.Innerclass innerclass = new OuterClass().new Innerclass();
获取实例内部类对象依赖于外部类对象。拿到实例内部类对象,就可以调用实例内部类方法了。
innerclass.test();
但是如果我们在实例内部类中定义静态成员变量,程序会报错
但是如果我们加上关键字final,就不会报错了
所以如果你想要在实例内部类中定义一个静态成员变量就必须加上一个final关键字来修饰。
原因是什么呢?如果不加final,static修饰的成员会被最早执行且不依赖对象,但是内部类依赖于外部类对象,非静态内部类在外部类加载时并不会加载,必须先实例化外部类对象然后再实例化成员内部类。静态的属性和方法在类加载的时候就会存在于内存中,而成员内部类需要外部类的实例才能存在,这与静态成员不需要实例化的特性相矛盾。那为什么加上final修饰就可以了呢?因为被final修饰的变量就相当于一个常量,是不需要类加载的。
如果我们在实例内部类定义了一个和外部类同名的变量data1,然后我们在内部类的test方法中输出data1,请问输出的值是多少呢?
class Innerclass {
……
public int data1 = 111;
public void test() {
System.out.println(data1);
System.out.println("内部类test方法");
}
}
输出结果:
原因是:内部类test方法会优先访问自己类中的data1,如果自己类中没有才会去外部类中找。那么我们应该如何在内部类方法中访问外部类变量呢?注意:现在不是继承,所以我们不能用super。我们需要通过外部类类名.this来访问:
System.out.println(OuterClass.this.data1);
实例内部类和成员变量一样受访问限定符的约束。实例内部类可以直接访问外部类的成员,如果实例内部类与外部类有同名成员变量,要想访问外部类的同名变量要通过外部类类名.this来访问。在外部类中不能直接访问实例内部类的成员变量,要想访问必须先创建内部类对象。
实例内部类的麻烦点在于,当你每次去获取实例内部类对象时都必须先获取一遍外部类对象,静态内部类就很好的解决了这个麻烦。
静态内部类
class OuterClass {
public int data1 = 1;
private int data2 = 2;
public static int data3 = 3;
//静态内部类
static class InnerClass {
public int data4 = 4;
private int data5 = 5;
public static int data6 = 6;
public void test() {
System.out.println("内部类的test方法");
}
}
public void test() {
System.out.println("外部类的test方法");
}
}
那么这个静态内部类对象怎么构造呢?等号左边语法不变,因为现在不依赖外部类,所以右边就可以直接new了,静态内部类是需要外部类类名.来调用的
public static void main(String[] args) {
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
}
现在就可以调用静态内部类的test方法了
innerClass.test();
我们可以直接在静态内部类中访问外部类的静态成员data3
public void test() {
System.out.println(data3);
System.out.println("内部类的test方法");
}
但如果我们想在静态内部类的test方法中访问外部类的非静态成员data1又该如何访问呢?我们只需要在静态内部类的test方法中实例化一个外部类对象,通过这个对象来访问data1即可
public void test() {
OuterClass outerClass = new OuterClass();
System.out.println(outerClass.data1);
System.out.println("内部类的test方法");
}
匿名内部类
interface A {
void testA();
}
public class Test10_6 {
public static void main(String[] args) {
//以下代码可以认为:有一个类 实现了A接口并且重写了A接口中的方法
new A() {
@Override
public void testA() {
System.out.println("哈哈");
}
}.testA();//调用testA()方法//匿名内部类:这个类没有名字
}
}
输出结果:
也可以这样调用:
A a = new A() {
@Override
public void testA() {
System.out.println("哈哈");
}
};//匿名内部类
a.testA();
现在我们在匿名内部类中定义一个整型变量x,并通过testA方法输出
public static void main(String[] args) {
int x = 10;
A a = new A(){
@Override
public void testA() {
System.out.println(x);
}
};
a.testA();
}
现在我们给x赋值为100,你会发现代码报错了
在匿名内部类中,能够访问的是没有被修改过的值。---变量的捕获。实际上在这里能被访问的是被final修饰的。
局部内部类
public class Test10_3 {
public void method() {
int data1 = 1;
//局部内部类
class Inner {
public int data2 = 2;
}
Inner inner = new Inner();
System.out.println(inner.data2);
}
public static void main(String[] args) {
Test10_3 test10_3 = new Test10_3();
test10_3.method();
}
}
只能在当前方法中使用局部内部类且不能被public、static等访问限定符修饰。几乎不会使用局部内部类。每一个类都会生成一个字节码文件,局部内部类的命名格式是:外部类名字$数字内部类名字.class
使用最多的是匿名内部类和静态内部类,其次是实例内部类,局部内部类基本不使用。