Java:内部类

发布于:2024-04-26 ⋅ 阅读:(12) ⋅ 点赞:(0)

1.内部类介绍

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,**可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。**内部类也是封装的一种体现。
注意事项
1.定义在class 类名{}花括号外部的,即使是在一个文件里,都不能称为内部类,举例如下

public class A{  
}
class B{ 
}
// A 和 B是两个独立的类,彼此之前没有关系

2.内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件。如下说示:

class OuterClass{
    public int data1=1;
    private int data2=2;
    class InnerClass{
        public int data1=100;
        public int data3=3;

    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        OuterClass.InnerClass innerClass=out.new InnerClass();
    }
}

编译后产生的字节码文件
在这里插入图片描述

2.实例内部类

代码形式

class OuterClass{
    public int data1=1;
    private int data2=2;
    class InnerClass{
        public int data1=100;
        public int data3=3;
    }
}

1.外部类中的任何成员都可以在实例内部类方法中直接访问

class OuterClass{
    public int data1=1;
    private int data2=2;
    public void test(){
        System.out.println("OuterClass::test()");
        System.out.println(data1);    
    }
    class InnerClass{
        public void test1(){
            System.out.println("InnerClass::test()");
            System.out.println(data1);
            System.out.println(data2);
            //直接调用外部类的data1和data2并打印
        }
    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        OuterClass.InnerClass innerClass=out.new InnerClass();
        innerClass.test1();
    }
}

运行结果
在这里插入图片描述

2.实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
在这里插入图片描述
使用private修饰后,下面实例化的时候就会报错,如下所示
在这里插入图片描述
被public修饰就不展示了
3.在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问

class OuterClass{
    public int data1=1;
    private int data2=2;
    public void test(){
        System.out.println("OuterClass::test()");
        System.out.println(data1);
    }
    class InnerClass{
        public int data1=100;//与外部类同名成员
        public void test1(){
            System.out.println("InnerClass::test()");
            System.out.println(this.data1);
            System.out.println(data2);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        OuterClass.InnerClass innerClass=out.new InnerClass();
        innerClass.test1();
    }
}

运行结果
在这里插入图片描述
如果要想访问到外部类的同名方法,修改如下

public void test1(){
            System.out.println("InnerClass::test()");
            System.out.println(OuterClass.this.data1);
            System.out.println(data2);
        }

运行结果
在这里插入图片描述

4.实例内部类对象必须在先有外部类对象前提下才能创建
下面提供两种实例化方式

public static void main(String[] args) {
// 要访问实例内部类中成员,必须要创建实例内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
        OuterClass out=new OuterClass();
        OuterClass.InnerClass innerClass=out.new InnerClass();
        OuterClass.InnerClass innerClass1=new OuterClass().new InnerClass();
    }

5.实例内部类的非静态方法中包含了一个指向外部类对象的引用

class OuterClass{
    public int data1=1;
    private int data2=2;
    public void test(){
        System.out.println("OuterClass::test()");
        System.out.println(data1);
    }
    class InnerClass{

        public void test1(){
            OuterClass out=new OuterClass();
  //在内部类方法中创建一个外部类对象,通过这个对象调用外部类成员方法
            out.test();
            System.out.println("=================");
            System.out.println("InnerClass::test()");
            System.out.println(data1);
            System.out.println(data2);
        }

    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        OuterClass.InnerClass innerClass=out.new InnerClass();
        innerClass.test1();
    }
}

运行结果
在这里插入图片描述

6.外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。

class OuterClass{
    public int data1=1;
    private int data2=2;
    public void test(){
        OuterClass.InnerClass innerClass=new InnerClass();
        //在外部类中实例化了一个内部类对象调用内部类成员
        innerClass.test1();
        System.out.println("===================");
        System.out.println("OuterClass::test()");
        System.out.println(data1);
    }
    class InnerClass{
        public void test1(){
            System.out.println("InnerClass::test()");
            System.out.println(data1);
            System.out.println(data2);
        }

    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        out.test();
    }
}

运行结果
在这里插入图片描述

3.静态内部类

1.在静态内部类中只能访问外部类中的静态成员

class OuterClass{
    public int data1=1;
    private int data2=2;
    static int data3=3;
    public void test(){
        System.out.println("OuterClass::test()");
        System.out.println(data1);
    }
    static class InnerClass{
        public void test1(){
            System.out.println("InnerClass::test()");
            System.out.println(data1);//非静态成员,会报错
            System.out.println(data2);//非静态成员,会报错
            System.out.println(data3);//静态成员正常访问
        }
    }
}

在这里插入图片描述
如果确实想访问,我们该如何做?
在内部类方法里实例化一个外部类方法

static class InnerClass{
        public void test1(){
            OuterClass out=new OuterClass();
            System.out.println("InnerClass::test()");
            System.out.println(out.data1);
            System.out.println(out.data2);
            System.out.println(data3);
        }

运行结果
在这里插入图片描述
2.创建静态内部类对象时,不需要先创建外部类对象

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass innerClass=new OuterClass.InnerClass();
        //直接通过外部类调用就可创建静态内部类的对象
        innerClass.test1();
    }
}

4.局部内部类

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般使用的非常少,此处简单了解下语法格式。
1.局部内部类只能在所定义的方法体内部使用

class OuterClass{
    public void method() {
        int data1=1;
        class InnerClass{
            void test1(){
                System.out.println("InnerClass::test1()");
                System.out.println(data1);
            }
        }
        //只能在方法体内部使用
        InnerClass innerClass=new InnerClass();
        innerClass.test1();
    }
}
public class Test {
    public static void main(String[] args) {
        OuterClass out=new OuterClass();
        out.method();
    }
}

运行结果
在这里插入图片描述
如果在方法题外部使用会出现报错
在这里插入图片描述

2.不能被public、static等修饰符修饰
报错结果如下
在这里插入图片描述
在这里插入图片描述

3.编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class
在这里插入图片描述
4.几乎不会使用

5.匿名内部类

匿名内部类可以用来实现一个接口并创建一个新的线程,举例如下

interface ITestable{
    void test();
}
public class Test {
    public static void main(String[] args) {
        new ITestable(){//直接实现这个接口
            @Override
            public void test() {
                System.out.println("hello zzuli");
            }
        };
    }
}

上面的代码相当于下面通过implments来实现一个接口

interface ITestable{
    void test();
}
class A implements ITestable{

    @Override
    public void test() {
        System.out.println("hello zzuli");
    }
}
public class Test {
    public static void main(String[] args) {
        A a=new A();
    }
    
}

我们通过匿名内部类来实现接口,那么我们应该怎么使用接口里的方法呢?
下面提供两种方法
方法一:直接通过.来调用,代码如下

interface ITestable{
    void test();
}
public class Test {
    public static void main(String[] args) {
        new ITestable(){
            @Override
            public void test() {
                System.out.println("hello zzuli");
            }
        }.test();//直接调用
    }
}

方法二:通过创建一个变量来调用(推荐使用)

interface ITestable{
    void test();
}
public class Test {
    public static void main(String[] args) {
        ITestable I=new ITestable(){
            @Override
            public void test() {
                System.out.println("hello zzuli");
            }
        };
        I.test();//通过变量名调用
    }
}