java中的内部类

内部类分类

内部类分为四种:
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进行修改的.否则会编译出错.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值