JavaSE内部类

内部类概述

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 就相当于外部类的对象)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

01、创建型-单例模式--只有一个实例

文章目录 前言一、基本介绍1.1 什么是单例模式1.2 为什么要用单例模式1.3 应用场景1.4 单例优缺点 二、单例模式的实现方式2.1 饿汉式单例2.1.1 静态变量方式2.1.2 静态代码块 2.2 懒汉式单例2.2.1 懒汉式单例2.2.2 懒汉式优化①-线程安全2.2.2 懒汉式优化②-双重检查锁2.2.3 懒…

ROS1快速入门学习笔记 - 04创建工作环境与功能包

一、定义 工作空间(workspace)是一个存放工程开发相关文件的文件夹。 src:代码空间(Source Space)build: 编辑空间(Build Space)devel:开发空间(Development Space)install:安装空间(Install …

深入理解Linux文件系统于日志分析

目录 一.Inode 和 block 概述 ​编辑 1.inode 的内容 (1)Inode 包含文件的元信息 (2)用 stat 命令可以查看某个文件的 inode 信息 (3) Linux系统文件三个主要的时间属性 (4)目…

CentOS 系统的优缺点

CentOS (社区企业操作系统的缩写)是一个基于红帽企业 Linux (RHEL)的免费开源发行版, 旨在为服务器和工作站提供稳定、可靠和安全的平台。 不应将其与CentOS Stream 混淆,后者是即将发布的 RHEL 版本的上游开发平台。 CentOS Li…

第67天:APP攻防-Frida反证书抓包移动安全系统资产提取评估扫描

思维导图 案例一:内在-资产提取-AppinfoScanne AppinfoScanner 一款适用于以 HW 行动/红队/渗透测试团队为场景的移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具,可以帮助渗透测试工程师、攻击队成员、红队成员快速收集到移动端或者静态 WEB …

机器学习之sklearn基础教程

ChatGPT Scikit-learn (简称sklearn) 是一个非常受欢迎的Python机器学习库。它包含了从数据预处理到训练模型的各种工具。下面是一个关于如何使用sklearn进行机器学习的基础教程。 1. 安装和导入sklearn库 首先,你需要安装sklearn库(如果你还没有安装的…

使用写入这类接口后,文件指针fp是否会偏移?

以fprintf为例: 在使用 fprintf 函数写入数据时,文件指针 fp 会自动进行偏移,以确保数据被写入到文件的正确位置。 每次调用 fprintf 函数都会将数据写入文件,并且文件指针会在写入完成后自动移动到写入的末尾,以便下…

56-FMC连接器电路设计

视频链接 FMC连接器电路设计01_哔哩哔哩_bilibili FMC连接器电路设计 1、FMC简介 1.1、FMC介绍 FMC(FPGA Mezzanine Card)是一个应用范围、适应环境范围和市场领域范围都很广的通用模块。FMC连接器连接了由FPGA提供的引脚和FMC子板的I/O接口。最新的…

NLP方面知识

NLP方面知识 一 基础1.Tokenizer1.1 分词粒度:1.2 大模型的分词粒度1.3 各路语言模型中的tokenizer 2.Embedding layer2.1 理解Embedding矩阵 一 基础 1.Tokenizer tokenizer总体上做三件事情: 分词。tokenizer将字符串分为一些sub-word token string&…

ISSCC论文详解:“闪电”数模混合存内计算,适应transformer和CNNs架构

本文聚焦存内计算前沿论文ISSCC 2024 34.3,总结归纳其创新点,并对与之相似的创新点方案进行归纳拓展。 一、文章基本信息 ISSCC 2024 34.4:《A 22nm 64kb Lightning-Like Hybrid Computing-in-Memory Macro with a Compressed Adder Tree a…

实验七 智能手机互联网程序设计(微信程序方向)实验报告

请编写一个用户登录界面&#xff0c;提示输入账号和密码进行登录&#xff0c;要求在输入后登陆框显示为绿色&#xff1b; 二、实验步骤与结果&#xff08;给出对应的代码或运行结果截图&#xff09; index.wxml <view class"content"> <view class"a…

Linux——界面和用户

本篇文章所写的都是基于centos 7 64位&#xff08;通过虚拟机运行&#xff09;。 一、Linux的界面 Linux操作系统提供了多种用户界面&#xff0c;主要分为图形用户界面&#xff08;GUI&#xff09;和命令行界面&#xff08;CLI&#xff09;。 1、图形用户界面(GUI)&#xff…

2024 年选择安全运营中心 (SOC) 工具指南

安全运营中心 (SOC) 是对抗网络威胁的前线。他们使用各种安全控制措施来监控、检测和快速响应任何网络威胁。这些控制措施对于确保信息系统全天候安全至关重要。 大型组织中的现代 SOC 与各种安全供应商合作&#xff0c;处理 75 到 100 种不同的工具。让我们探讨一下您可能遇到…

vue【vuex状态管理】

1&#xff1a;vuex是什么&#xff1a; vuex是一个状态管理工具&#xff0c;状态就是指的数据&#xff0c;可以将数据存放到vuex中以供其他组件使用时进行调用 2&#xff1a;应用场景&#xff1a; ①&#xff1a;像用户登录客户端&#xff0c;这个用户的数据需要在多个组件中…

天锐绿盾 | 文件资料透明加解密系统

"天锐绿盾 | 文件资料透明加解密系统" 是一款专为企业及各类组织机构设计的数据安全防护软件。它以“透明加解密”为核心技术&#xff0c;旨在对用户的重要文件资料进行实时、无缝的加密保护&#xff0c;确保数据在存储、传输和使用过程中的安全性&#xff0c;防止敏…

javascript(第三篇)原型、原型链、继承问题,使用 es5、es6实现继承,一网打尽所有面试题

没错这是一道【去哪儿】的面试题目&#xff0c;手写一个 es5 的继承&#xff0c;我又没有回答上来&#xff0c;很惭愧&#xff0c;我就只知道 es5 中可以使用原型链实现继承&#xff0c;但是代码一行也写不出来。 关于 js 的继承&#xff0c;是在面试中除了【 this 指针、命名提…

一文速览Llama 3及其微调:如何通过paper-review数据集微调Llama3 8B

前言 4.19日凌晨正准备睡觉时&#xff0c;突然审稿项目组的文弱同学说&#xff1a;Meta发布Llama 3系列大语言模型了 一查&#xff0c;还真是 本文以大模型开发者的视角&#xff0c;基于Meta官方博客的介绍&#xff1a;Introducing Meta Llama 3: The most capable openly a…

基于FPGA轻松玩转AI

启动人工智能应用从来没有像现在这样容易&#xff01;受益于像Xilinx Zynq UltraScale MPSoC 这样的FPGA&#xff0c;AI现在也可以离线使用或在边缘部署、使用.可用于开发和部署用于实时推理的机器学习应用&#xff0c;因此将AI集成到应用中变得轻而易举。图像检测或分类、模式…

Android Studio查看viewtree

前言&#xff1a;之前开发过程一直看的是手机上开发者选项中的显示布局边界&#xff0c;开关状态需要手动来回切换&#xff0c;今天偶然在Android Studio中弄出了布局树觉得挺方便的。

国产FTP文件传输服务器需要具备哪些关键特性?

国产FTP文件传输服务器是指根据中国国内信息技术创新&#xff08;信创&#xff09;的要求和标准&#xff0c;自主研发的文件传输服务器软件。这类软件旨在替代传统的FTP服务器&#xff0c;以更好地适应国产化和信息安全的需要。国产FTP文件传输服务器通常需要具备以下要求&…