Java(十)——内部类

文章目录

内部类

Java内部类是一种特殊的类定义方式,它允许在一个类的内部定义另一个类。

内部类可以访问其所在外部类的成员变量和成员方法,这使得它非常适用于封装与外部类紧密相关的私有逻辑。

内部类是类的五大成员之一。【成员变量、成员方法、构造方法、代码块、内部类】

内部类有以下四种:

  1. 静态内部类
  2. 实例内部类
  3. 匿名内部类
  4. 局部内部类

内部类的优势:

  • 每个内部类都可以独立地继承一个接口的实现,无论外部类是否继承了接口的实现,这使多继承的方案得到进一步的完善
  • 内部类可以实现特殊的逻辑关系,并能对外隐藏
  • 内部类方便编写实现事件驱动程序
  • 内部类方便编写线程代码

内部类有一个单独的字节码文件,字节码文件格式:


静态内部类

Java的静态内部类是用static修饰的内部类

【特点】

  1. 静态内部类实例化对象不依赖于外部类,不需要先实例化外部类对象

    格式:

    外部类.静态内部类 变量名 = new 外部类.静态内部类();

  2. 可以使用publicprotecteddefault(默认权限)private修饰静态内部类

  3. 静态内部类中不能直接访问其外部类的非静态的成员,要依赖外部类的对象进行访问

  4. 静态内部类中可以定义静态成员变量和方法

  5. 静态内部类中可以有构造方法

  6. 如果静态内部类成员与其外部类成员同名,可以使用对应的类名访问指定类中的同名成员(记得考虑成员是静态还是非静态)

如下代码:

java 复制代码
public class OutClass {
    public String s1 = "外部类的非静态成员";
    public static String outs2 = "外部类的静态成员";
    public int i = 10;

    static class InnerClass {
        public String s1 = "静态内部类的非静态成员变量";
        public String inners2 = "静态内部类的静态成员变量";

        //静态内部类的构造方法
        public InnerClass(String s1) {
            this.s1 = s1;
        }

        public void test1() {
            System.out.println("静态内部类的非静态成员方法执行了...");

            //静态内部类中不能直接访问其外部类的非静态的成员,要依赖外部类的对象进行访问
            OutClass outClass = new OutClass();
            System.out.println(outClass.i);
        }

        public static void test2() {
            System.out.println("静态内部类的静态成员方法");
        }
    }
}

class Main {
    public static void main(String[] args) {
        //静态内部类实例化对象不依赖于外部类,不需要先实例化外部类对象
        OutClass.InnerClass innerClass = new OutClass.InnerClass("新静态内部类的非静态成员变量");
        innerClass.test1();
    }
}

实例内部类

即在外部类类内,方法外定义的非static修饰的内部类

【特点】

  • 实例内部类依赖其外部类,实例化 实例内部类对象时,要先实例化外部类对象
  • 可以使用publicprotecteddefault(默认权限)private修饰实例内部类
  • 实例内部类中不能定义静态成员变量,除非它由final修饰
  • 实例内部类中不能定义静态方法
  • 实例内部类可以存在构造方法
  • 实例内部类可以直接访问其外部类的成员,包括privatestatic修饰的成员
  • 当实例内部类成员与其外部类成员同名时,会优先访问实例内部类自己的成员,如果想访问其外部类的同名成员,要通过下面的方式:外部类.this.成员

如下代码:

java 复制代码
public class OutClass {
    private String s1 = "外部类的非静态成员变量";
    public static String s2 = "外部类的静态成员变量";
    public int a = 10;

    class InnerClass {
        public String s = "实例内部类的非静态成员";
        public static final String ss = "实例内部类的静态成员,必须由final修饰";
        public int a = 20;

        public InnerClass() {

        }

        public InnerClass(String s) {
            this.s = s;
        }

        public void test() {
            //同名成员默认访问实例内部类自己的
            System.out.println(a);
            //通过 父类.this.同名成员 访问外部类的同名成员a
            System.out.println(OutClass.this.a);

            //实例内部类可以访问其外部类的所有成员,包括private、static修饰的
            System.out.println(s1);
            System.out.println(s2);
        }
    }
}

class Main {
    public static void main(String[] args) {
        //实例化实例内部类对象
        //1.分两步:先实例化外部类的对象,再通过外部类对象实例化实例内部类对象
        OutClass outClass = new OutClass();
        OutClass.InnerClass innerClass1 = outClass.new InnerClass();
        
        //2.实例化完外部类对象后直接实例化实例内部类对象
        OutClass.InnerClass innerClass2 = new OutClass().new InnerClass();

        innerClass1.test();
    }
}

匿名内部类

匿名内部类没有类名,直接在创建对象时定义并实现,一般用于创建只需要使用一次的类对象

匿名内部类用于简化代码、增加代码的可读性和可维护性

【特点】

  • 匿名内部类中不能定义任何的静态成员
  • 由于匿名内部类没有类名,自然也不存在构造方法
  • 一个匿名内部类一定是在new后面,用来隐式地实现一个接口或继承一个类
  • 匿名内部类的类内就是花括号的范围
  • 匿名内部类可以用来给方法传参,以此实现多态
  • 可以通过匿名内部类实现的接口或匿名内部类继承的父类的引用变量接收,不过前提是花括号后面不能用.访问任何成员
java 复制代码
//ITest.java
public interface ITest {
    void func();
}

//Animal.java
public class Animal {
    private String name;
    //...
    public void test() {
        System.out.println("Animal类中的方法...");
    }
}

//OutClass.java
public class OutClass {

    //匿名内部类可以作为方法的参数,实现多态
    public static void func(ITest iTest) {
        iTest.func();
    }

    public static void test() {
        
        //匿名内部类隐含实现接口,并直接调用自己的成员方法
        new ITest() {
            public int a = 10;
            public void innerClassTest() {
                System.out.println("匿名内部类中的成员方法...");
            }
            @Override
            public void func() {
                System.out.println("重写接口的抽象方法...");
            }
        }.innerClassTest();

        //匿名内部类隐含继承Animal类,并可以调用父类的方法,证明这里确实隐含地继承了Animal类
        new Animal() {
            public void childTest() {
                System.out.println("匿名内部类的成员方法...");
            }
        }.test();
        
        //可以通过匿名内部类实现的接口或匿名内部类继承的父类的引用变量接收,不过前提是花括号后面不能用 . 访问任何成员
        ITest iTest = new ITest() {
            @Override
            public void func() {
                System.out.println("实现接口方法...");
            }
        };
        
        Animal animal = new Animal() {
            public String name;
        };
    }
}

class Main {
    public static void main(String[] args) {
        OutClass.test();
        
        //匿名内部类作为方法参数传入,在此方法内部实现了多态
        OutClass.func(new ITest() {
            @Override
            public void func() {
                System.out.println("实现接口的方法...");
            }
        });
    }
}

局部内部类

定义在方法体内的类就是局部内部类,在方法外就不能使用了。

【特点】

  • 局部内部类位于方法体内,其只能在方法体内使用
  • 局部内部类中不能定义静态成员
  • 局部内部类中可以存在构造方法
  • 局部内部类可以直接访问其所在方法的局部变量以及方法所在类的成员
  • 局部内部类不能被访问修饰符publicprotectedprivate以及static修饰
java 复制代码
public class OutClass {
    public String s1 = "局部内部类所在方法的类的非静态成员变量";
    private static String s2 = "局部内部类所在方法的类的静态私有成员变量";

    public static void innerClassFunc() {
        int a = 10;
        final int b = 20;

        class InnerClass {
            public String s1 = "局部内部类的非静态成员变量";
            //public static s2 = "局部内部类中 不能存在 静态的成员";

            public InnerClass() {

            }

            public InnerClass(String s1) {
                this.s1 = s1;
            }

            public void test() {
                System.out.println(a);
                System.out.println(b);
                System.out.println(s1);
                System.out.println(s2);
            }
        }

        InnerClass innerClass = new InnerClass();
        innerClass.test();
    }
}

class Main {
    public static void main(String[] args) {
        OutClass.innerClassFunc();
    }
}

相关推荐
火烧屁屁啦11 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
飞飞-躺着更舒服15 分钟前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
w_312345425 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安27 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA30 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_192849990637 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法