Java 内部类(1): 基本语法

2023-11-13

可以将一个类的定义放在另一个类的内部,这就是内部类。内部类的表面意义一目了然,不过内部类的实现语法还是稍显繁琐。

内部类的分类

:内部类主要分为:普通内部类,匿名内部类,局部内部类,嵌套内部类(静态内部类)。

普通内部类

普通内部类内不能有静态成员变量和静态方法

    public class Outer{
        class Inner{
            private String name;
            public Inner(String name){
                this.name = name;
            }
            public void setName(String name){
                this.name = name;
            }
            public String getName(){
                return name;
            }
        }

        public Inner getInner(String name){
            return new Inner(name);
        }
        public static void main(String[] args){
            Outer out = new Outer();
            Inner inner = out.getInner("inner");
            System.out.println(inner.getName());
        }
    }

普通内部类拥有对外部类的全部访问权,它能够与外部类进行通信并且可以操作外部类。当某个外部类对象创建了一个内部类对象,该内部类对象会秘密的保留一个指向创建它的外部类对象的引用。当内部类中访问外部类成员时,就是通过这个隐藏引用来拥有外部类的访问权。换句话说,内部类对象只能在与其外围类的对象关联的情况下才能创建(不包括静态内部类),构建内部类对象时,需要一个指向其外部类的引用,如果找不到这个引用,则编译器报错。
普通内部类不能含有静态成员变量和静态方法。

最典型的应用就是外部类有一个公共方法a,该方法返回一个内部类(该内部类是private的并且实现了某个公共接口,外部无法直接访问类,只能通过接口)对象的引用,也就是返回类型为公共接口类型
这样既可以得到一个公共接口的实现类,又完美隐藏了其实现细节,客户端不知道实现类的名字(因为该类是私有的,客户端无法访问),只能通过公共方法a得到它。java集合中的迭代器Iterator()就是其一。
例如:

//接口类
public interface Selector {
    boolean end();
    void next();
    Object curr();
}
//主类
public class Outer_3 {
    class SelectorImpl implements Selector {
        @Override
            public boolean end() {
                return false;
            }

            @Override
            public void next() {

            }

            @Override
            public Object curr() {
                return null;
            }
    }

    public Selector selector() {
        return new SelectorImpl();
    }

    public static void main(String[] args) {
        Outer_3 outer3 = new Outer_3();
        Selector selector = outer3.selector();
        System.out.println(selector.end());
    }
}

匿名内部类

   匿名内部类的使用基本上需要符合一下几点:
        
- 匿名内部类只能使用一次,创建匿名内部类的同时也会创建该类的一个对象,之后该类的定义消失。通常用来简化代码编写。
- 匿名内部类内部无法定义构造函数
- 匿名内部类不能有静态成员变量或静态方法
- 匿名内部类是局部内部类,所以局部内部类的限制匿名内部类也有
- 匿名内部类必须继承某个类或者实现某个接口(因为匿名,所以无法访问,要想使用只能通过向上转型为父类或者接口)
匿名内部类的典型应用是用来开启一个线程:

public class Main{
    public static void main(String[] args){
        Runnable r = new Runnable(){
                public void run(){
                      System.out.println("new Tread is running");
                }
            };
        Thread thread = new Thread(r);
        thread.start();
    }
}

局部内部类:

//局部内部类
public class Out_4 {
    public void inner(final String name) { //jdk8以下必须用final修饰,jdk8虽然不是必须,但是在类内部也是无法改变该变量的。
        class Inner {
            private String sname;
            Inner(){
                //name = name = "";  编译错误,局部内类部无法改变方法参数
                this.sname = name;
            }
            Out_4 getOut() {
                return Out_4.this;
            }
        }
        System.out.println(new Inner().sname);
        System.out.println(new Inner().getOut());
    }

    public static void main(String[] args) {
        Out_4 out_4 = new Out_4();
        out_4.inner("out_4");
        //out_4.new Inner(); 在局部外部类所在的方法外部无法访问局部内部类
    }
}

嵌套内部类(静态内部类)

public class Out_5 {
    private int i;
    static private String j;
    public Out_5(int i,String jj){
        this.i = i;
        j = jj;
    }
    public static void staticMethod(){

    }

    static public class Inner {
        public  int x;
        private int y;
        public Inner(int x,int y){
            this.x = x;
            this.y = y;
        }
        public int getX(){
            return x;
        }
        public int getY(){
            return y;
        }
        public void print(){
            System.out.println(j+":"+x+":"+y);;
            staticMethod();;
            //System.out.println(i);  //静态内部类不能访问外部类的非静态成员
        }
    }

    public static void main(String[] args) {
        Out_5.Inner inner = new Inner(1,2);
        Out_5.Inner inner1 = new Inner(3,4);
        inner.print();   //null:1:2
        inner1.print();  //null:3:4
        Out_5 out_5 = new Out_5(5,"10");
        System.out.println(out_5.i+":"+out_5.j);  //5:10
        Out_5 out_ = new Out_5(5,"15");
        System.out.println(out_.i+":"+out_.j);  //5:15
        inner.print();   15:1:2
    }
}

静态内部类能够访问外部类的静态成员,除了创建时要在前面加上外部类名称.之外,跟普通静态类没什么区别。

静态内部类的特殊用途:接口内部的嵌套类。你放到接口中的类自动是public和static的,并不违反接口的语法。
通常情况下,接口内部不能放置任何代码,但如果你想要实现该接口的所有实现类共享一段公共代码,可以考虑在接口内定义静态类。
这有点类似于抽象类的非抽象方法。

//接口类ClassInInterface
public interface ClassInInterface {
    void f();
    class Test{ //接口中的类自动是static,所以不需要额外加static
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}


//接口实现类
public class ClassInInterfaceImpl implements ClassInInterface {
    @Override
    public void f() {
        System.out.println("method f()");
    }

    public static void main(String[] args) {
          ClassInInterfaceImpl instance = new         ClassInInterfaceImpl();
        Test test = new Test();
        test.setName("name");
        System.out.println(test.getName());
    }
}

new 和 this

非嵌套类情况下,内部类拥有对外部类的全部访问权,内部类内部拥有一条外部类的引用,那么如何在内部类中得到外部类的引用呢,这就是this的作用了。另外内部类的创建依赖于外部类的某个实例对象,如何由外部类对象创建一个内部类对象,这就需要用到new的新用法。示例如下

public Outer{
    class Inner{
        private String name;
        Inner(String name){
            this.name = name;
        }
        public String getName(){
            return this.name;
        }
        public Outer getOuter(){
        //外部类名字.this
            return Outer.this;
        }
    }

    public static void main(String[] args){
        Outer out = new Outer();
        //外部对象.new 内部类构造器(匿名内部类无法用这种方式,但匿名内部类通用可以访问到外部类)
        Inner inner = out.new Inner("inner");
        System.out.println(inner.getName());
        Outer out2 = inner.getOuter();
        System.out.println(out==out2); // true
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 内部类(1): 基本语法 的相关文章

随机推荐

  • okyo Cabinet简介

    http idning github io ssd cache html http blog 163 com zbr 4690 blog static 126613593200910312346337 http blog chinaunix
  • Param ‘serviceName‘ is illegal, serviceName is blank --------报错

    报错内容为 java lang IllegalArgumentException Param serviceName is illegal serviceName is blank 报错原因 SpringBoot2 4版本之后不会默认加载b
  • linux测试命令

    如下是一份 Linux 机器的渗透测试备忘录 是在后期开发期间或者执行命令注入等操作时的一些典型命令 设计为测试人员进行本地枚举检查之用 系统信息命令 对于本地的枚举检查很有用 基于 Redhat CentOS RPM 的发行版 YUM 命
  • 解决SpringMVC Controller中接受日期格式发生400错误

    解决SpringMVC Controller中接受日期格式发生400错误 用户中有生日 Date 属性 用户注册的时候 选择日期即可 然后提交表单 可SpringMVC报错 意思是不能把字符串转为日期类型的 如果是strtus的话 压根不是
  • Vuex概念+实现原理

    文章目录 一 Vuex概念 1 Vuex是什么 2 Vuex的具体工作 3 Vuex 的属性包含以下6个 二 Vuex实现原理 2 1 store是怎么注册的 2 2 mutaions是怎么实现的 2 3 commit是怎么实现的 2 4
  • GPIO 模拟SPI

    GPIO 模拟SPI SPI简介 SCPH 0 SCPOL 0 的 SPI 协议时序图 在这里插入图片描述 https img blog csdnimg cn daeedeab80d14239aa1331736b17bf7d png SCP
  • 火狐浏览器书签无法同步问题解决

    问题 个人笔记本的火狐浏览器登录帐号后无法同步公司火狐浏览器的书签信息 更换了不同版本的火狐浏览器后仍然同步不了 解决方案 经过查找问题发现火狐提供了本地服务和全球服务两套服务方案 而两套服务是不互通的 公司电脑登录帐号时选择的是本地服务
  • 初始C语言——100-1000之间的素数排序,10个数一行

    思路分析 首先我们要清楚什么是素数 一个大于1的自然数 且除了1和它本身外 不能被其他自然数整除的数叫素数 然后我们需要考虑怎样实现100 1000之间素数的输出 是不是需要用到遍历 而for循环就是一种遍历 那怎么写for循环呢 很显然
  • HCIP第四天笔记

    网络类型 根据数据链路层所使用的协议及规则来进行划分 P2P网络 点到点网络 MA网络 多点接入网络 BMA 广播型多点接入网络 NBMA 非广播型多点接入 数据链路层协议以太网协议 封装数据帧是 需要假如源MAC地址和目标MAC地址 MA
  • 利用Qemu Guest Agent (Qemu-ga) 实现 Openstack 监控平台

    http www csdn123 com html itweb 20130729 27101 27081 27076 htm 利用Qemu Guest Agent Qemu ga 实现 Openstack 监控平台 经常使用vmWare的同
  • java.lang.NoClassDefFoundError: org/apache/hadoop/fs/FSDataInputStream

    使用不带hadoop的spark包 在成功启动pyspark前需要在spark的配置文件conf spark env sh里指定hadoop 格式是spark要求好的 现在以hadoop这个命令已经在环境变量中存在的情况为例 spark e
  • Win10安装docker遇到的坑

    记录下Win10安装docker遇到的坑 首先win10是分版本的 这里举例其中两个版本 家庭版 和 企业版 我电脑的操作系统之前是家庭版的 安装了Docker Desktop 又启用了hyper v 安装成功后使用docker versi
  • typedef struct

    用途一 定义一种类型的别名 而不只是简单的宏替换 可以用作同时声明指针型的多个对象 比如 char pa pb 这多数不符合我们的意图 它只声明了一个指向字符变量的指针 和一个字符变量 以下则可行 typedef char PCHAR PC
  • SpringBoot自定义banner

    在resources下添加文件banner 自定义编写然后重新启动 也可以去网站上找Text to ASCII Art Generator TAAG 然后复制到banner txt
  • 人工智能与具体应用领域如何进行有效的结合

    人工智能与具体应用领域如何进行有效的结合 人工智能 Artificial Intelligence 简称AI 它是研究 开发用于模拟 延伸和扩展人的智能的理论 方法 技术及应用系统的一门新的技术科学 它是计算机科学的一个分支 它企图了解智能
  • 阿里云ECS服务器购买及域名绑定 新手教程

    教程内容 购买阿里云域名 DNS域名解析 购买阿里云域名 1 校验域名是否已被注册 阿里云域名注册地址 https wanwang aliyun com 2 购买域名 选择钟意的域名 添加到购物车 填写信息 如何没用进行域名实名认证 就需要
  • linux 的grep命令

    一 语法 grep全称是Global Regular Expression Print 表示全局正则表达式打印 grep命令是一种强大的文本搜索工具 用于查找文件中符合条件的字符串 它能使用正则表达式搜索文本 并把匹配的行打印出来 root
  • stringbuffer方法简单使用

    buf delete 0 buf length 清空StringBuffer buf delete 30 40 清除下标30 40之间的元素 buf insert 20 str 从下标为20的位置开始写添加进去 列如 buf hello12
  • Fine Report 连接 MySQL的问题

    工作需要今天来搞Fine Report 10 0 连接MySql 数据库 MySQL 驱动器 com mysql jdbc Driver URL jdbc mysql localhost 3306 数据库名称 useSSL false se
  • Java 内部类(1): 基本语法

    可以将一个类的定义放在另一个类的内部 这就是内部类 内部类的表面意义一目了然 不过内部类的实现语法还是稍显繁琐 内部类的分类 内部类主要分为 普通内部类 匿名内部类 局部内部类 嵌套内部类 静态内部类 普通内部类 普通内部类内不能有静态成员