Java---内部类的定义与用法

简介: 内部类是定义在另一个类中的类,内部类也是封装的一种的体现。

一. 内部类概述

内部类是定义在另一个类中的类,内部类也是封装的一种的体现。为什么要使用内部类,主要有两个原因:


· 内部类可以对同一个包的其他类进行隐藏。


· 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据。


格式:

public class OutClass {
    class InnerClass {
    }              //Outclass是外部类    Innerclass是内部类


注意事项:


1. 定义在class类名花括号外的,即使是在一个文件里,都不能称为内部类,例:

public class OutClass {
}
class InnerClass {      //不是内部类,它在花括号外
}


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


先看一下内部类都可以在一个类的哪些位置可以定义:

public class OutClass {
    public class InnerClass1{     //未被static修饰,普通内部类
    }
    static class InnerClass2{     //被static修饰,静态内部类
    }
    public void method(){
        class InnerClass3{      //在方法中定义,局部内部类
        }
    }
    {
        class InnerClass4{      //实例代码块中,局部内部类
        }
    }
    static {
        class InnerClass5{        //静态代码块中,局部内部类
        }
    }
}


二. 成员内部类

内部类定义的位置与外部类成员所处的位置相同,称为成员内部类


2.1 普通内部类

未被static修饰的内部类称为普通内部类


想了解普通内部类的用法,看完下面的代码和注释,所有问题就迎刃而解了

public class OutClass {
    private int a;
    static int b;
    int c;
    public void method1() {
        a = 1;
        System.out.println(a);
    }
    public static void method2(){
        b = 2;
        System.out.println(b);
    }
    public class InnerClass1 {
        int c;
        public void innerMethod(){
            a = 10;
            b = 20;
            method1();       //内部类中可以直接访问外部类任何访问限定符修饰的成员
            method2();
            c = 30;           //访问的是内部类自己的成员c
            innerMethod();
            OutClass.this.c = 300;    //通过访问 外部类.this.同名成员名字 来访问外部类中与内部类同名的成员
            System.out.println(OutClass.this.c);
        }
    }
    public static void main(String[] args) {
        //普通内部类的成员创建以及访问
        OutClass oc = new OutClass();
        System.out.println(oc.a);
        System.out.println(oc.b);
        System.out.println(oc.c);
        oc.method1();
        oc.method2();
        //要访问普通内部类中的成员,必须先构造普通内部类对象
        //构造普通内部类对象方法:
        OutClass.InnerClass1 ic = new OutClass().new InnerClass1();
        //也就是说想构造内部类对象必须借助外部类
        System.out.println(ic.c);
        ic.innerMethod();
    }
}


注意事项:


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


2. 普通内部类所处的成员与外部类成员位置相同,因此受public private 等访问限定符约束


3. 在内部类方法中访问同名的成员时,优先访问自己的,如果访问外部类同名的成员必须以:外部类名称.this.成员变量 来访问


4. 普通内部类对象必须在先有外部类前体下才能创建


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


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


2.2 静态内部类

被static修饰的内部成员类称为静态内部类


想了解静态内部类的用法,看下面的代码和注释

public class OutClass {
    private int a;
    static int b;
    int c;
    public void method1(){
        a = 1;
        System.out.println(a);
    }
    public static void method2(){
        b = 2;
        System.out.println(b);
    }
    static class InnerClass{
        public void methodInner(){
            //  a = 10;    编译器会报错,因为静态内部类中只能访问外部类的静态成员
            b = 20;    //这一编译器不会报错,因为b是静态成员
           // method1();   编译器报错,因为method1不是静态成员方法
            method2();    //这里编译器正常通过
        }
    }
    public static void main(String[] args) {
        //静态内部类对象创建及成员访问
        OutClass.InnerClass ic = new OutClass.InnerClass();
        ic.methodInner();
    }
}


注意事项:


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


2.在创建内部类对象时不需要创建外部类成员


3.成员内部类经过编译之后会产生独立的字节码文件,命名格式为:外部类名称$内部类名称


三. 局部内部类

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般用的较少。


看以下代码:

public class OutClass {
    int a = 10;
    public void method(){
        int b = 20;
        class InnerClass{      //不能被public static等访问修饰符修饰
            public void methodInner(){
                System.out.println(a);
                System.out.println(b);
            }
        }
        InnerClass ic = new InnerClass(); //只能在该方法体内部使用,其他位置都不能用
        ic.methodInner();
    }
    public static void main(String[] args) {
      //  InnerClass ic = new InnerClass();    在这里变异错误
    }
}


注意事项:

1.局部内部类只能在定义本方法体中内部使用


2.不能被public,static修饰


3.编译器也有自己独立的字节码文件,命名格式:外部类名字$x内部类名字.class,x是一个整数


四.匿名类

该类会在后面详细介绍


五.对象的打印

public class Student {
    String name;
    String gender;
    int age;
    public Student(String name,String gender,int age){
        this.name = name;
        this .gender = gender;
        this.age = age;
    }
    public static void main(String[] args) {
        Student st = new Student("XiaoHua","男",10);
        System.out.println(st);
    }
}


打印结果:

微信图片_20221028190304.jpg



那该如何打印呢?重写toString方法即可。

public class Student {
    String name;
    String gender;
    int age;
    public Student(String name,String gender,int age){
        this.name = name;
        this .gender = gender;
        this.age = age;
    }
    public String toString(){
        return name+"-"+gender+"-"+age;
    }
    public static void main(String[] args) {
        Student st = new Student("XiaoHua","男",10);
        System.out.println(st);
    }
}


打印结果:

微信图片_20221028190324.jpg

相关文章
|
7月前
|
存储 Java 数据挖掘
Java 中数组的多种定义方式
本文深入解析了Java中数组的多种定义方式,涵盖基础的`new`关键字创建、直接初始化、动态初始化,到多维数组、`Arrays.fill()`方法以及集合类转换为数组等高级用法。通过理论与实践结合的方式,探讨了每种定义方法的适用场景、优缺点及其背后的原理,帮助开发者掌握高效、灵活的数组操作技巧,从而编写更优质的Java代码。
349 0
|
8月前
|
存储 JSON Java
《从头开始学java,一天一个知识点》之:方法定义与参数传递机制
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问"`a==b`和`equals()`的区别",大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 🚀 这个系列就是为你打造的Java「速效救心丸」!我们承诺:每天1分钟,地铁通勤、午休间隙即可完成学习;直击痛点,只讲高频考点和实际开发中的「坑位」;拒绝臃肿,没有冗长概念堆砌,每篇都有可运行的代码标本。上篇:《输入与输出:Scanner与System类》 | 下篇剧透:《方法重载与可变参数》。
173 25
|
8月前
|
存储 监控 Java
《从头开始学java,一天一个知识点》之:数组入门:一维数组的定义与遍历
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问"`a==b`和`equals()`的区别",大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列就是为你打造的Java「速效救心丸」!我们承诺:每天1分钟,地铁通勤、午休间隙即可完成学习;直击痛点,只讲高频考点和实际开发中的「坑位」;拒绝臃肿,没有冗长概念堆砌,每篇都有可运行的代码标本。明日预告:《多维数组与常见操作》。 通过实例讲解数组的核心认知、趣味场景应用、企业级开发规范及优化技巧,帮助你快速掌握Java数组的精髓。
183 23
|
11月前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
10230 5
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
存储 安全 Java
深入理解Java中的FutureTask:用法和原理
【10月更文挑战第28天】`FutureTask` 是 Java 中 `java.util.concurrent` 包下的一个类,实现了 `RunnableFuture` 接口,支持异步计算和结果获取。它可以作为 `Runnable` 被线程执行,同时通过 `Future` 接口获取计算结果。`FutureTask` 可以基于 `Callable` 或 `Runnable` 创建,常用于多线程环境中执行耗时任务,避免阻塞主线程。任务结果可通过 `get` 方法获取,支持阻塞和非阻塞方式。内部使用 AQS 实现同步机制,确保线程安全。
1242 3
|
Oracle Java 关系型数据库
重新定义 Java 对象相等性
本文探讨了Java中的对象相等性问题,包括自反性、对称性、传递性和一致性等原则,并通过LaptopCharger类的例子展示了引用相等与内容相等的区别。文章还介绍了如何通过重写`equals`方法和使用`Comparator`接口来实现更复杂的相等度量,以满足特定的业务需求。
111 3
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
92 1
|
Java 编译器
【Java】内部类
【Java】内部类
102 0