JavaSE内部类

news2025/3/10 15:03:43

内部类概述

1.内部类的基础

内部类的分类:实例化内部类,静态内部类,局部内部类和匿名内部类

public class OutClass {
    // 成员位置定义:未被static修饰 --->实例内部类
    public class InnerClass1{
   }
 
    // 成员位置定义:被static修饰 ---> 静态内部类
    static class InnerClass2{
 
   }
 
 
    public void method(){
        // 方法中也可以定义内部类 ---> 局部内部类:几乎不用
        class InnerClass5{
 
       }
   }
}

内部类的基本概念:一个类的内部又完整地嵌套了另一个类结构,则被嵌套的类成为内部类(inner class),嵌套其他类的类称为外部类(outer class)。

  • 一个类中有五大成员:属性、方法、构造器、代码块、内部类。
  • 内部类最大的特点就是可以直接访问外部类的私有属性,并且可以体现类与类之间的包含关系。
  • 内部类是面向对象学习的重难点,底层源码中包含大量的内部类。

 2.内部类基本语法

class Outerclass { // 外部类

	class Innerclass { // 内部类
		
	}
}

class Otherclass { // 外部其他类
}

一.实例内部类

实例化内部类成员位置定义:未被static修饰 --->实例内部类

① 

 实例化实例内部类:

//第一种写法
Outerclass outclass = new Outerclass();
Outerclass.InnerClass innerClass = outclass.new InnerClass();

第二种写法
Outerclass.InnerClass innerClass = new Outerclass().new InnerClass();

② 

内部类成员方法能访问外部类的成员变量和方法

内部类访问外部类的成员: 

class Outerclass {
    public int a = 1;
    private int b = 2;
    public void method() {
        System.out.println("外部类成员方法");
    }
    class InnerClass {
        int c = 10;
        public void methodInner() {
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
            method();
        }
    }

    public static void main(String[] args) {
        Outerclass outclass = new Outerclass();
        Outerclass.InnerClass innerClass = outclass.new InnerClass();
        //第二种写法
        //Outerclass.InnerClass innerClass = new Outerclass().new InnerClass();
        
        innerClass.methodInner();
    }
}

当内部类成员变量与外部类的成员变量名字相同时应该先访问自己内部类的成员变量

若要访问外部类则需要通过:

  1. 外部类名称.this.同名成员名字
  2. 实例化外部类再访问
class Outerclass {
    public int c = 100;
    public void method() {
        System.out.println("外部类成员方法");
    }
    class InnerClass {
        char c = 'a';
        public void methodInner() {
            System.out.println(c);
            method();
        }
    }

    public static void main(String[] args) {
        Outerclass outclass = new Outerclass();
        Outerclass.InnerClass innerClass = outclass.new InnerClass();
        //第二种写法
        //Outerclass.InnerClass innerClass = new Outerclass().new InnerClass();

        innerClass.methodInner();
    }
}

 

方法一:

System.out.println(Outerclass.this.c);

 方法二:

Outerclass outerclass = new Outerclass();
System.out.println(outerclass.c);

在内部类定义main方法不能运行

用 $ 区分内部类和外部类来命名

整体代码

class Outerclass {
    int a = 1;
    public int c = 100;
    public void method() {
        System.out.println("外部类成员方法");
    }

    class InnerClass {
        char c = 'a';
        public void methodInner() {
            System.out.println(a);
            method();
            //访问与内部类成员变量名形同的外部类成员变量

            //方法一:
            Outerclass outerclass = new Outerclass();
            System.out.println(c);
            System.out.println(outerclass.c);
            //方法二
            System.out.println(Outerclass.this.c);
        }
    }

    public static void main(String[] args) {
        //实例化 实例内部类
        Outerclass outclass = new Outerclass();
        Outerclass.InnerClass innerClass = outclass.new InnerClass();
        //第二种写法
        //Outerclass.InnerClass innerClass = new Outerclass().new InnerClass();

        innerClass.methodInner();
    }
}

总结

  1. 成员内部类实质上就是一个类;同时它也是一个成员变量,因此它可以用任意的访问修饰符来修饰(public、protected、默认、private),也可以用 final 来修饰,但不用 static 修饰(用 static 修饰的成员内部类叫做静态内部类)。
  2. 成员内部类的作用域是整个类体;它可以直接访问外部类的所有成员,包含私有的、静态的(不需要创建外部类对象);注意:成员内部类中不能定义静态成员。
  3. 外部类的其他成员想访问成员内部类中的非静态成员,需要先创建成员内部类的对象,再通过该对象来访问(成员内部类中没有静态成员)。
  4. 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。 
  5. 如果外部类中的成员和成员内部类中的成员重名时,内部类访问该成员默认遵循就近原则;在成员内部类中想访问外部类的同名成员,使用 外部类名.this.成员 访问。

 二.静态内部类

成员位置定义:被static修饰 ---> 静态内部类

 ①

实例化静态内部类

Outerclass.StaticInnerclass staticInnerclass = new Outerclass.StaticInnerclass();

静态内部类方法只能访问外部类的静态的成员变量和方法,非静态变量和方法不能直接访问

可以通过实例化外部类再进行访问

Outerclass outerclass = new Outerclass();
System.out.println(outerclass.a);

如果外部类中的成员和静态内部类中的成员重名时,内部类访问该成员默认遵循就近原则;在静态内部类中想访问外部类的同名成员,使用 外部类名.成员 访问(静态内部类中不能使用 this 关键字) 

class Outerclass {
    static int  c = 111; 
    //此时外部类的成员变量必须是static修饰

    static class StaticInnerclass {
        static int c = 100;
        public void methodStaticInner() {
            System.out.println(c);
            System.out.println(Outerclass.c);
        }
    }
}

 整体代码

class Outerclass {
    public int a = 1;
    private int b = 2;
    static int  c = 111;
    public void method() {
        System.out.println("外部类成员方法");
    }

    static void method1() {
        System.out.println("外部类静态成员方法");
    }

    static class StaticInnerclass {
        int a = 100;
        public void methodStaticInner() {
            System.out.println(c);
            method1();
            //System.out.println();
            //System.out.println(b);  只能访问外部类的static修饰的成员
        }
    }

    public static void main(String[] args) {
        //访问外部类的非静态方法
        Outerclass outerclass = new Outerclass();
        System.out.println(outerclass.a);
        outerclass.method();

        //实例化静态内部类
        Outerclass.StaticInnerclass staticInnerclass = new Outerclass.StaticInnerclass();
        staticInnerclass.methodStaticInner();
    }
}

总结

  1.  静态内部类实质上就是一个类;同时它也是一个成员变量,因此它可以用任意的访问修饰符来修饰(public、protected、默认、private),也可以用 final 来修饰,而必须使用 static 修饰。
  2. 静态内部类的作用域是整个类体;它可以直接访问外部类的所有静态成员,包含私有的(不需要创建外部类对象);注意:静态内部类中可以定义非静态成员和静态成员。
  3. 外部类的其他成员想访问静态内部类中的非静态成员,需要先创建静态内部类的对象,再通过该对象来访问;外部类的其他成员想访问静态内部类中的静态成员,则只需要使用静态内部类名.成员 便可直接访问。

辨析实例内部类和静态内部类

 区别

实例化内部类(非静态内部类)与外部类实例紧密相关。这意味着非静态内部类可以访问外部类的所有成员(包括私有成员),因为它们持有外部类的隐式引用。此外,非静态内部类可以有非静态成员(方法和属性),这使得它们能够更灵活地与外部类进行交互。然而,实例化内部类的一个限制是它们必须依赖于外部类的实例才能被创建。

静态内部类则与外部类实例没有直接关联,它们可以独立于外部类对象而存在。静态内部类可以使用static关键字来修饰,这意味着它们可以访问外部类的静态成员,但不能直接访问非静态成员。静态内部类的一个主要优势是它们可以在没有外部类实例的情况下被创建和实例化,这使得它们在某些情况下更加灵活和方便。

使用场景

  1. 访问权限:如果需要访问外部类的非静态成员,则实例化内部类是更好的选择。如果只需要访问外部类的静态成员,那么静态内部类可能更合适。
  2. 创建和实例化:如果内部类需要独立于外部类对象存在,或者不需要外部类实例即可创建,那么静态内部类更适用。
  3. 设计考虑:在某些情况下,为了遵循面向对象的设计原则(如单一职责原则、开闭原则等),可能更倾向于使用静态内部类来将功能模块化。

三.匿名内部类

  • 匿名内部类定义在外部类的局部位置(即方法和代码块中),并且不具有类名。

用法一:实现接口的匿名内部类

interface IA {
    public void run();
}

class Outer {
    public void OuterMethod() {
        //实现接口的匿名内部类
        IA tiger = new IA() {
            @Override
            public void run() {
                System.out.println("tiger用四条腿跑");
            }
        };//内部类创建完毕
        System.out.println("tiger的运行类型=" + tiger.getClass());
        tiger.run();// tiger对象 可以一直使用
        tiger.run();
    }
}

public class Test2 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.OuterMethod();
    }
}

        1.需求: 想实现IA接口,并创建对象
        2.传统方式,是写一个实现接口的类,实现该接口,并创建该类对象
        3.可要求是:该类只是使用一次,后面再不使用
        4. 可以使用匿名内部类来简化开发
        5. tiger的编译类型是: IA接口
        6. tiger的运行类型是: 就是匿名内部类 Outer$1 (jdk分配的类名,不能使用)

                底层分配 类名 Outer$1 ,如下:
           

class Outer$1 implements IA {
                @Override
                public void run() {
                    System.out.println("");
                }
            }

        7. jdk底层在创建匿名内部类 Outer$1,并立即就创建了 Outer$1 实例对象, 并且把对象地址返回给 tiger;

        8. 匿名内部类 Outer$1 使用一次后,就不能再使用,但其对象 tiger可以一直使用。

 用法二:继承父类的匿名内部类

                继承抽象类的匿名内部类

class Father {
    public Father(String name) {
        System.out.println("接收到name=" + name);
    }
    //方法
    public void test() {
    }
}
// 抽象类
abstract class Animal {
    abstract void eat();
}

class Outer {
    public void method() {
        //继承父类的匿名内部类
        Father father = new Father("张三"){
            @Override
            public void test() {
                System.out.println("重写父类的方法");
            }
        };
        System.out.println("father对象的运行类型=" + father.getClass()); // 输出 Outer$2
        father.test();
    }
    //继承抽象类的匿名内部类
    Animal animal = new Animal() {
        @Override
        void eat() {
            System.out.println("继承抽象类的方法");
        }
    };
}
public class A{
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
        outer.animal.eat();
    }
}

1. father编译类型 Father

2. father运行类型 Outer$2

3. 底层会创建匿名内部类,如下       

class Outer$2 extends Father{
                @Override
                public void test() {
                    System.out.println("匿名内部类重写了test方法");
                }
            }

4. 同时也直接返回了 匿名内部类 Outer$2的对象

5. 注意("张三") 参数列表会传递给 构造器。


class Fu {
    int a;
    public void test(){};

    public Fu(int a) {
        this.a = a;
        System.out.println(a);
    }
    public void ok(String str) {
        System.out.println("ok(String str) " + str);
        test();//动态绑定
    }
}

abstract class Animal1 {
    abstract void eat1();
}

class Outerclass {
    public void Out() {
        Fu fu = new Fu(1){
            @Override
            public void test() {
                System.out.println("重写父类Fu()");
            }

        };
        fu.test();
        System.out.println("Fu的运行类型" + fu.getClass());

        new Fu(2) {
            @Override
            public void test() {
                System.out.println("第二次重写父类Fu()");
            }
        }.ok("aaa");
    }
    //继承抽象类的匿名内部类
    Animal1 animal1 = new Animal1() {
        @Override
        void eat1() {
            System.out.println("继承抽象类Animal1的方法eat1()");
        }
    };
}
public class Test3 {
    public static void main(String[] args) {
        Outerclass outerclass = new Outerclass();
        outerclass.Out();
        outerclass.animal1.eat1();
    }
}

public class Interface01 {
    public static void main(String[] args) {
        f(new A() {
            @Override
            public void eat() {
                System.out.println("没有创建对象便成功的调用了f方法,不需要实现接口");
            }
        });
    }
    public static void f(A a){
        a.eat();
    }
}
interface A{
    public void eat();
}
---------------------------
没有创建对象便成功的调用了f方法,不需要实现接口

  1. 匿名内部类本质上还是类,但同时它本身还是一个对象。
  2. 匿名内部类就是实现了接口的一个类,或者是继承了父类的一个子类;匿名内部类只会被创建一次,之后便被销毁;其对象也只会被创建一次,但是该对象可以被一直使用。
  3. 匿名内部类既是一个类的定义,同时本身也是一个对象,又是一个局部变量。因此它可以不返回对象地址,通过自身直接调用其内部的成员;但这样该匿名内部类的对象便只能使用一次。
  4. 匿名内部类的作用域只在定义它的方法或者代码块中;匿名内部类不能添加访问修饰符 和 static,可以用 final 修饰,因为它的地位就是一个局部变量。
  5. 匿名内部类可以直接访问外部类的所有成员,包括私有的(不需要创建外部类对象)。
  6. 外部类的其他成员不能直接访问匿名内部类的成员,只能通过在定义了匿名内部类的方法中用匿名内部类的对象调用其成员,然后再调用该方法,实现间接使用匿名内部类的成员。
  7. 外部其他类不能访问匿名内部类及其成员
  8. 如果外部类中成员和匿名内部类中的成员重名时,内部类访问该成员默认遵循就近原则;在匿名内部类中想访问外部类的同名成员,使用 外部类名.this.成员 访问。

四.局部内部类

局部内部类定义在外部类的局部位置(即方法和代码块中),并且具有类名 

局部内部类定义在方法当中,相当于一个局部变量

作用域只在定义它的方法或者代码块中。

在内部类下实例化内部类

使用 外部类名.this.成员 访问与内部类成员变量名相同的外部成员变量 

整体代码 

class OutClass {
    int a = 10;
    public void method(){
        int a = 11;
        int b = 10;
        // 局部内部类:定义在方法体内部
        // 不能被public、static等访问限定符修饰
        class InnerClass{
            public void methodInnerClass(){
                System.out.println(a);

                //通过类名.this.成员的方式来访问与内部类成员变量名相同的外部类成员变量
                System.out.println(OutClass.this.a);
                System.out.println(b);
            }
        }

        // 只能在该方法体内部使用,其他位置都不能用
        InnerClass innerClass = new InnerClass();
        innerClass.methodInnerClass();
    }

    public static void main(String[] args) {
        // OutClass.InnerClass innerClass = null; 编译失败
        OutClass outClass = new OutClass();
        outClass.method();
    }
}

总结

  1. 局部内部类本质上还是类;但同时又相当一个局部变量,因此不能用任何访问修饰符和 static 来修饰局部内部类,可以使用 final 修饰。
  2. 局部内部类的作用域只在定义它的方法或者代码块中。
  3. 局部内部类可以直接访问外部类的所有成员,包括私有的(不需要创建外部类对象)
  4. 外部类的其他成员不能直接访问局部内部类的成员,只能通过在定义了局部内部类的方法中用局部内部类的对象调用其成员,然后再调用该方法,实现间接使用局部内部类的成员
  5. 外部其他类不能访问局部内部类。
  6. 如果外部类中的成员和局部内部类中的成员重名时,内部类访问该成员默认遵循就近原则;在局部内部类中想访问外部类的同名成员,使用 外部类名.this.成员 访问(外部类名.this 就相当于外部类的对象)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1618491.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南 由北京海特伟业任洪卓发布于2024年4月23日 随着“互联网”被提升为国家战略,传统行业与互联网的深度融合正在如火如荼地展开。在这一大背景下,海特伟业紧跟时代步伐,凭借其深厚…

如何在PostgreSQL中跟踪和分析查询日志,以便于排查性能瓶颈?

文章目录 启用查询日志分析查询日志1. 查找执行时间长的查询2. 分析资源消耗3. 使用pgBadger分析4. 优化查询 示例代码结论 在PostgreSQL中,跟踪和分析查询日志是排查性能瓶颈的重要步骤。通过查看和分析查询日志,我们可以了解哪些查询在执行时遇到了问题…

17.Nacos与Eureka区别

Nacos会将服务的提供者分为临时实例和非临时实例。默认为临时实例。 临时实例跟eureka一样,会向注册中心报告心跳监测自己是否还活着。如果不正常了nacos会剔除临时实例。(捡来的孩子) 非临时实例,nacos会主动询问服务提供者是否…

232 基于matlab的MIMO雷达模型下一种子空间谱估计方法

基于matlab的MIMO雷达模型下一种子空间谱估计方法,采用过估计的方法,避免了信源数估计的问题,对数据协方差矩阵进行变换,构造信号子空间投影矩阵和噪声子空间投影矩阵,不需要像经典的MUSIC一样对其进行特征分解&#x…

BBS前后端混合项目--03

展示 static/bootstrp # bootstrap.min.css /*!* Bootstrap v3.4.1 (https://getbootstrap.com/)* Copyright 2011-2019 Twitter, Inc.* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)*//*! normalize.css v3.0.3 | MIT License | github.com/n…

Python练习03

题目 解题思路 Demo58 通过字符串切片来进行反转操作 def _reverse():"""这是一个反转整数的函数"""num input("请输入想要反转的整数")print(num[::-1]) 运行结果 Demo61 首先制作一个判断边长的函数,通过三角形两边…

vue3项目 使用 element-plus 中 el-collapse 折叠面板

最近接触拉了一个项目,使用到 element-plus 中 el-collapse 折叠面板,发现在使用中利用高官网多多少少的会出现问题。 (1.直接默认一个展开值,发现时显时不显 2 . 数据渲染问题,接口请求了,页面数据不更新 …

捕捉信号的处理

文章目录 信号捕捉 信号捕捉 信号捕捉是进程从内核态返回用户态时会对信号进行检测处理。 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处…

linux——cron定时任务

cron定时任务配置文件中可以查看一些信息 crontab就是在提交以及管理需要周期性执行的任务 定时任务具体实现需要使用crontab命令编辑对应定时任务文件 这里执行定时任务,每分钟创建一个文件1.txt

jvm中的垃圾回收器

Jvm中的垃圾回收器 在jvm中,实现了多种垃圾收集器, 包括: 1.串行垃圾收集器 2.并行垃圾收集器 3.CMS(并发)垃圾收集器 4.G1垃圾收集器 1.串行垃圾回收器 效率低,使用较少 2.并行垃圾回收器 3.并发垃圾回…

mysql download 2024

好久没在官网下载 mysql server 安装包。今天想下载发现: 我访问mysql官网的速度好慢啊。mysql server 的下载页面在哪里啊,一下两下找不到。 最后,慢慢悠悠终于找到了下载页面,如下: https://dev.mysql.com/downlo…

3 命名实体识别调优化

能走到这里说明你对模型微调有了一个基本的认识。那么开始一段命名实体的任务过程,下面使用huggingface官网的数据。 1 准备模型 下面的模型自己选择一个吧,我的内存太第一个模型跑不了。 https://huggingface.co/ckiplab/bert-base-chinese-ner/tree…

医学访问学者专栏—研究领域及工作内容

在国外访问学者申请中,医学领域的研究、教学及从业人员占有相当大的比例,这些医学访问学者的研究领域及工作内容都有哪些?本文知识人网小编就相关问题进行详细阐述,并附带案例说明。 一、在国外做医学访问学者可以从事哪些工作&am…

Win10 打开有些软件主界面会白屏不显示,其他软件都正常

环境: Win10专业版 英伟达4070 显卡 问题描述: Win10 打开有些软件主界面会白屏不显示,打开远程协助软件AIRMdesk,白色,其他软件都正常 解决方案: 网上说电脑没有接显示器独立显卡的关系导致 我是只有一台主机,没…

appium相关的知识

>adb shell dumpsys window | findstr mCurrentFocus adb devices # 实例化字典 desired_caps = dict() desired_caps[platformName] = Android desired_caps[platformVersion] = 9 # devices desired_caps[deviceName] = emulator-5554 # 包名 desired_caps[appPackage] …

DRF 查询(排序、过滤、分页)

查询(排序、过滤、分页) 【0】准备 (1)Q查询 详细内容可见:Django模型层-CSDN博客Django 的 Q 对象提供了一种在数据库查询中构造复杂查询的方法。当你想在单个查询中组合多个过滤条件,并且这些条件之间不仅仅是简单的 AND 关系…

MySQL8.0.36-社区版:二进制日志(4)

什么是二进制日志(binlog):记录了所有的ddl和dml语句,但是不包括查询类的 二进制日志的作用:1.灾难恢复,2.mysql主从复制 查看二进制日志状态 show variables like %log_bin%; 在mysql8中默认是开启的 | l…

TLV61048非同步升压BOOST转换器输入电压2.6-5.5V输出电流4A输出电压最高15V

推荐原因: 输入电压较低,输出电流可达3.5A SOT23-6封装 批量价格约0.70元 TLV61048引脚 TLV61048引脚功能 7 详细说明 7.1 概述 TLV61048是一款非同步升压转换器,支持高达 15 V 的输出电压和输入范围从 2.61 V 到 5.5 V。该TLV61048集成了…

C++ map和set的应用

1. 关联式容器 我们已经接触过STL中的部分容器,比如:vector、list、deque、 forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它…

如何用Java语言实现远程控制多路照明

如何用Java语言实现远程控制多路照明呢? 本文描述了使用Java语言调用HTTP接口,实现控制多路照明。通过多路控制器,可独立远程控制多路照明。 可选用产品:可根据实际场景需求,选择对应的规格 序号设备名称1智能WiFi控…