内部类分类
内部类分为四种:
1:实例内部类:定义在类的内部的一个类
2:静态内部类:定义在类的内部的一个类,但是由static来修饰的
3:匿名内部类
4:本地内部类:方法里面定义的类,没有意义,可以不看
实例内部类
如何实例化内部类对象
方式:
OuterClass.InnerClass innerClass2 = out.new InnerClass();
外部类名.内部类名 变量 = 外部类对象的引用.new 内部类();
代码示例
//实例内部类
class OuterClass {
public int data1 = 3;
public static final int data4 = 4;
//InnerClass就是我们的实例内部类
class InnerClass {
public int data3;
//实例内部类可以书写构造方法
public InnerClass() {
}
/*注意实例内部类内部不能定义静态的成员变量
例如public static int data = 9;这种就不能定义
*/
//如果非要定义静态的成员变量,要加上final
public static final int data5 = 9;
public void test() {
System.out.println("InnerClass::test()");
System.out.println(data3);
System.out.println(this.data3);
System.out.println(OuterClass.this.data1);
}
}
}
public class TestMain {
public static void main(String[] args) {
//实例内部类实例化对象的方式
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
}
}
注意事项:
1、只要是内部类,那么生成的字节码文件格式:外部类$内部类.class
2、在实例内部类当中,不能定义静态的成员变量
!!
如果非要定义,那么一定要是在编译时期确定的值,即常量
其定义方式为public static final
3、先来看一段代码:思考我们的data1最后的输出结果是多少?
class OuterClass {
public int data1 = 3;
class InnerClass {
public int data1 = 10;
public void test() {
//最后输出的data1的值为10
System.out.println(data1);
}
}
}
public class TestMain {
public static void main(String[] args) {
//实例内部类实例化对象的方式
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
//结果为10
innerClass.test();
}
}
可以看到最后的输出结果为10,所以说当一个类和其内部类声明了相同的一个成员变量的时候,最后输出的成员变量的值一定是这个内部类的这个成员变量的值
但是注意了:此时我们就想用外部类的data1的值,不想用内部类的该怎么办呢?,来看代码:
class OuterClass {
public int data1 = 3;
public static final int data2 = 4;
class InnerClass {
public int data1 = 10;
public static final int data4 = 9;
public InnerClass() {
}
public void test() {
//最后输出的data1的值为3,注意书写方式
System.out.println(OuterClass.this.data1);
}
}
}
public class TestMain {
public static void main(String[] args) {
//实例内部类实例化对象的方式
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
//结果为3
innerClass.test();
}
}
总结
格式:System.out.println(OuterClass.this.data1);
可以看到使用外部类名.this.变量名就可以获取到对应的值了
这里就说明一个问题:this实际上也是一个静态的成员
同时也说明实例内部类拥有两个this,一个是实例内部类自己的,一个是外部类的
:来看代码:
class OuterClass {
public int data1 = 3;
class InnerClass {
public int data1 = 10;
public InnerClass() {
}
public void test() {
//此处输出的data1的值为10
System.out.print(this.data1);
//最后输出的data1的值为3
System.out.println(OuterClass.this.data1);
}
}
}
public class TestMain {
public static void main(String[] args) {
//实例内部类实例化对象的方式
OuterClass outer = new OuterClass();
OuterClass.InnerClass innerClass = outer.new InnerClass();
//结果为10,3
innerClass.test();
}
}
可以看到我们可以使用this获取到内部类的data1,可以使用外部类名.this获取到外部类中的data1.
所以这里有个面试题
:同学,实例内部类,是否有额外的内存开销??
答:当然有,实例内部类拥有两个this,一个是实例内部类自己的,一个是外部类的
静态内部类
概念
定义在类的内部的一个类。但是由static来修饰的.
如何实例化对象
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
= new 外部类.静态内部类();
下面来看代码:
class OuterClass {
public int data1 = 3;
static class InnerClass {
public InnerClass() {
}
public void test() {
/*注意此时不能访问外部类中的非静态数据成员
System.out.print(data1);
*/
}
}
}
public class TestMain {
public static void main(String[] args) {
//静态内部类实例化对象的方式
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
//结果为10,3
innerClass.test();
}
}
总结:
1:静态内部类的实例化方式我已经写在了代码中
2:只要是内部类,此处尽管是静态内部类,那么生成的字节码文件格式仍为:外部类$内部类.class
3:静态内部类当中,是不可以访问外部类的非静态数据成员的!!!!
因为,外部类的非静态数据成员 是依赖于外部类对象的
那么假如面试官非要我们访问的话,该怎么办呢
?
思路:给个外部类对象的引用就好了:来看代码:
class OuterClass {
public int data1 = 3;
static class InnerClass {
public OuterClass out;
//构建一个有参的构造函数
public InnerClass(OuterClass out) {
this.out = out;
}
public void test() {
System.out.println(out.data1);
}
}
}
public class TestMain {
public static void main(String[] args) {
OuterClass out = new OuterClass();
//传入一个out变量
OuterClass.InnerClass innerClass = new OuterClass.InnerClass(out);
//结果为3
innerClass.test();
}
}
匿名内部类
代码示例
/*
匿名内部类
*/
class OuterClass {
public void test() {
System.out.println("匿名内部类");
}
}
public class TestMain {
public static void main(String[] args) {
new OuterClass(){
}.test();
}
}
可以看到直接在主方法main的内部直接new一个类名,这样的写法就叫做匿名内部类,然后如果想要调用OuterClass内的方法,直接在后面.方法名
即可.
此时我们也可以重写OuterClass类中的test方法
/*
匿名内部类
*/
class OuterClass {
public void test() {
System.out.println("匿名内部类");
}
}
public class TestMain {
public static void main(String[] args) {
new OuterClass(){
@Override
public void test() {
System.out.println("重写我们的匿名内部类");
}
}.test();
//重写后的输出结果为:重写我们的匿名内部类
}
}
注意此处我们在匿名内部类重写了外部类中的test方法,最终的输出结果也一定是重写后的test方法当中的输出结果
匿名内部类的变量捕获
先来看一段代码:
class Test {
public void func() {
System.out.println("func()");
}
}
public class TestMain {
public static void main(String[] args) {
int a = 100;
new Test() {
@Override
public void func() {
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == " + a + " 我是一个常量,或者是一个没有改变过值的变量!");
}
};
}
}
可以看到我们在匿名内部类的外部有一个变量a,其值为100,这个变量是可以在匿名内部类中是可以被捕获到并且进行输出的,最终输出的值仍为100
假设此时我们想要对这个a重新在内部类中进行赋值输出的话,最后能够成功输出吗?来看代码:
/*
匿名内部类
*/
class Test {
public void func() {
System.out.println("func()");
}
}
public class TestMain {
public static void main(String[] args) {
int a = 100;
new Test() {
@Override
public void func() {
//重新赋值
a = 50;
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a == " + a + " 我是一个常量,或者是一个没有改变过值的变量!");
}
};
}
}
此时编译就直接报错啦
总结:
1:在上述代码当中的变量a就是捕获的变量。这个变量要么是被final修饰,是一个常量,不能被修改,要么就不是被final修饰的
2:如果不是被final修饰的你要保证在使用之前,没有修改。即如果上面的代码我要是在匿名内部类外面已经定义了一个变量a的话,在匿名内部类中是不能对这个变量a进行修改的.否则会编译出错.