java中的内部类

简介: 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进行修改的.否则会编译出错.


相关文章
|
2月前
|
Java
【Java基础面试二】、个Java文件里可以有多个类吗(不含内部类)?
这篇文章讨论了Java文件中类的定义规则,指出一个Java文件可以包含多个类(不包含内部类),但其中最多只能有一个public类,且如果有public类,它的名称必须与文件名一致。
|
2月前
|
算法 Java
12 Java常用类(一)(内部类+object类+包装类)
12 Java常用类(一)(内部类+object类+包装类)
29 5
|
3月前
|
Java
Java进阶之内部类
【7月更文挑战第13天】Java内部类增进代码组织与封装,允许直接访问外部类成员,包括私有成员。主要有四种类型:成员、静态、局部和匿名内部类。匿名内部类常用于一次性实现接口或扩展类。内部类可隐藏实现细节,减少命名冲突,并在特定上下文中定义辅助类。示例展示了静态和非静态内部类如何在Shape类中封装Circle和Rectangle。使用内部类能提升代码可读性,但可能增加复杂性。
34 6
|
2月前
|
Java
【Java】内部类、枚举、泛型
【Java】内部类、枚举、泛型
|
4月前
|
Java
一篇文章讲明白Java中内部类详解—匿名内部类
一篇文章讲明白Java中内部类详解—匿名内部类
52 2
|
4月前
|
设计模式 Java 编译器
Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)
Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)
|
4月前
|
Java 编译器
24. 【Java教程】内部类
24. 【Java教程】内部类
24 2
|
5月前
|
Java 程序员
Java的内部类与匿名类的技术性文章
Java的内部类与匿名类的技术性文章
37 1
|
4月前
|
Java
Java内部类相关内容总结和解读
Java内部类相关内容总结和解读
28 0
|
4月前
|
存储 Java
Java 五种内部类演示及底层原理详解
Java 五种内部类演示及底层原理详解
27 0
下一篇
无影云桌面