0

0

Java内部类示例分析

WBOY

WBOY

发布时间:2023-04-23 14:43:14

|

733人浏览过

|

来源于亿速云

转载

    1.内部类概念及分类

    将一个类定义在另一个类的内部或者接口内部或者方法体内部,这个类就被称为内部类,我们不妨将内部类所在的类称为外围类,除了定义在类,接口,方法中的内部类,还有一种特殊的内部类,那就是使用关键字new创建一个匿名类的对象,而这个匿名类其实就是一个内部类,具体说是一个匿名内部类,经常用于传入构造器实参构造对象,例如priorityqueue对象的创建。

    一个类定义在另一个类的内部或者接口内部,并且没有static修饰时,这个内部类就称为实例内部类,使用static修饰时,这个内部类被称为静态内部类(嵌套类),将一个类定义在代码块内部,特别是方法体内部,这个内部类被称为本地内部类或者局部内部类,还有一种就是上面所说的匿名内部类。

    2.实例内部类

    2.1实例内部类的创建

    实例内部类的定义很简单,就直接定义在外围类的里面就可以了。问题是如何创建一个内部类对象,首先,需要明白内部类与外围类中的成员变量与方法是平起平坐的,都是属于外围类对象的(无static修饰),所以想要内部类对象先得有外围类对象,第一种创建内部类对象的方式就是使用一个方法返回一个内部类对象,并且这个内部类对象的类型为OutClassName.InnerClassName,即外围类名.内部类名。

    public class Outer {
    
        class Inner1 {
            private String str;
            public Inner1(String s) {
                this.str = s;
            }
            public String readStr() {
                return this.str;
            }
        }
    
        class Inner2 {
            private int val;
            public Inner2(int i) {
                this.val = i;
            }
            public int readVal() {
                return this.val;
            }
        }
        //创建内部类
        public Inner1 creatInner1(String s) {
            return new Inner1(s);
        }
        public Inner2 creatInner2(int i) {
            return new Inner2(i);
        }
    
        public static void main(String[] args) {
            Outer outer = new Outer();
            Outer.Inner1 inner1 =  outer.creatInner1("Inner1");
            Outer.Inner2 inner2 = outer.creatInner2(2);
    
            System.out.println(inner1.readStr());
            System.out.println(inner2.readVal());
        }
    }
    //output:
    Inner1
    2
    
    Process finished with exit code 0

    2.2使用.this和.new

    当然,创建一个内部类还有其他的方法,就是使用外围类的对象.new来创建一个内部类对象,语法为:

    外部类对象.new 内部类构造方法;
    public class Outer {
    
        class Inner1 {
            private String str;
            public Inner1(String s) {
                this.str = s;
            }
            public String readStr() {
                return this.str;
            }
        }
    
        class Inner2 {
            private int val;
            public Inner2(int i) {
                this.val = i;
            }
            public int readVal() {
                return this.val;
            }
        }
    
    
        public static void main(String[] args) {
            Outer outer = new Outer();
            Outer.Inner1 inner1 =  outer.new Inner1("Inner1");
            Outer.Inner2 inner2 = outer.new Inner2(2);
    
            System.out.println(inner1.readStr());
            System.out.println(inner2.readVal());
        }
    }
    //output:
    Inner1
    2
    
    Process finished with exit code 0

    内部类的特性不止如此,内部类还能与外围类链接,首先实例内部类对象的创建是依赖外围类对象的引用,实例内部类与外围类的成员变量地位一样,如果想要通过内部类对象访问外围类的成员变量与方法(特别是同名变量)。在内部类中,可以使用外围类名.this获取外围类对象,然后使用获得的这个外围类对象来使用外围类的变量与方法。

    立即学习Java免费学习笔记(深入)”;

    public class Outer {
        private String outStr;
        public Outer(String str) {
            this.outStr = str;
        }
    
        public void printOuter() {
            System.out.println(this.outStr);
        }
    
        class Inner {
            private String str;
            public Inner(String s) {
                this.str = s;
            }
            public String readStr() {
                return this.str;
            }
            //使用.this获取父类对象引用
            public Outer outer() {
                return Outer.this;
            }
        }
    
    
    
        public static void main(String[] args) {
            Outer outer = new Outer("outerString");
            Outer.Inner inner = outer.new Inner("innerString");
    
            Outer out = inner.outer();
            out.printOuter();
        }
    }
    //output:
    outerString
    
    Process finished with exit code 0

    其实内部类对象中有两个this,直接使用this.成员获取的是内部类对象自己的成员,而像上面使用外围类名.this.成员获取的是外围类的成员,也就是说在内部类中this指向内部类对象自己的引用,外部类名.this指向外围类对象的引用。

    当出现内部类与外围类变量名相同时,这两个this就有很大的用处了。

    public class Outer {
        public int a = 12;
        public int b = 16;
        public int c = 20;
    
        class Inner{
            public int a = 8;
            public int c = 48;
            public int d = 2;
    
            public void printVal() {
                System.out.println("外围类变量a=" + Outer.this.a);
                System.out.println("外围类变量b=" + Outer.this.b);
                System.out.println("外围类变量c=" + Outer.this.c);
                System.out.println("内部类变量a=" + this.a);
                System.out.println("内部类变量c=" + this.c);
                System.out.println("内部类变量d=" + this.d);
            }
        }
    
        public Inner creatInner() {
            return new Inner();
        }
    
        public static void main(String[] args) {
            Outer outer = new Outer();
    
            Outer.Inner inner = outer.creatInner();
            inner.printVal();
        }
    }
    //output:
    外围类变量a=12
    外围类变量b=16
    外围类变量c=20
    内部类变量a=8
    内部类变量c=48
    内部类变量d=2
    
    Process finished with exit code 0

    如果没有出现同名,直接获取的成员即可,可以不用使用上面所说的this,出现同名,直接访问的成员默认是内部类对象的。

    2.3内部类实现迭代打印

    内部类可以与外围类的所有元素的访问权限,所以我们可以尝试使用内部类来遍历输出外围类中的元素,虽然内部类与外围类的成员地位是平等,但内部类毕竟也是类,它也可以像外围类一样继承类和实现接口。

    import java.util.Arrays;
    
    interface Selector{
        //判断是否迭代完全部元素
        public boolean end();
        //获取当前元素
        public Object current();
        //迭代下一个元素
        public void next();
    }
    
    public class SequeArray {
        private Object[] items;
        private int usedSize;
    
        public SequeArray(int capacity) {
            items = new Object[capacity];
        }
        public void add(Object val) {
            if (usedSize == items.length) items = Arrays.copyOf(items, 2 * usedSize);
    
            items[usedSize++] = val;
        }
    
        private class SequeSelector implements Selector{
            private int index;
    
            public boolean end() {
                return index == usedSize;
            }
            public Object current() {
                return items[index];
            }
            public void next() {
                if (index < usedSize) index++;
            }
        }
        public SequeSelector sequeSelector() {
            return new SequeSelector();
        }
    
        public static void main(String[] args) {
            SequeArray array = new SequeArray(10);
    
            for (int i = 0; i < 10; i++) {
                array.add(i+1);
            }
            //发生了向上转型
            Selector selector = array.sequeSelector();
    
            while (!selector.end()) {
                System.out.print(selector.current() + "   ");
                selector.next();
            }
        }
    }
    //output:
    1   2   3   4   5   6   7   8   9   10   
    Process finished with exit code 0

    2.4内部类的继承

    内部类的继承有一点麻烦,因为内部类的构造器必须依赖外围类的引用,所以需要一段特殊的语法来说明内部类与外围类的关联:

    外围类引用.super();

    具体怎么使用看如下一段代码:

    public class Outer {
        class Inner{
            
        }
    }
    class Person extends Outer.Inner {
        private String str;
        private int id;
        public Person(Outer out, String str, int id) {
            out.super();
            this.str = str;
            this.id = id;
        }
        public void readVal() {
            System.out.println(this.str + this.id);
            
        }
    }

    当内部类被继承的时候,需要通过外围类的引用传入父类的构造方法中并调用super()才能通过编译。

    I-Shop购物系统
    I-Shop购物系统

    部分功能简介:商品收藏夹功能热门商品最新商品分级价格功能自选风格打印结算页面内部短信箱商品评论增加上一商品,下一商品功能增强商家提示功能友情链接用户在线统计用户来访统计用户来访信息用户积分功能广告设置用户组分类邮件系统后台实现更新用户数据系统图片设置模板管理CSS风格管理申诉内容过滤功能用户注册过滤特征字符IP库管理及来访限制及管理压缩,恢复,备份数据库功能上传文件管理商品类别管理商品添加/修改/

    下载

    如果内部类继承外部类,直接继承即可,不需要这么麻烦。

    程序生成一个java文件的字节码文件时,命名为公共外部类$内部类。

    内部类可以无限嵌套,一般没人这么干。

    3.静态内部类

    静态内部类也称嵌套类,它就是在实例内部类的定义前加入一个static关键字,像下面这样:

    public class Outer {
        
        static class Inner{
            
        }
    }

    与实例内部类的区别是静态内部类是属于类的而不是属于对象的,因此静态内部类的创建不依赖与外部类对象,这是和实例内部类最大的区别之一。

    public class Outer {
        static class Inner{
            private String str;
            public Inner(String s) {
                str = s;
            }
        }
    
        public static void main(String[] args) {
            Outer.Inner inner = new Outer.Inner("我是静态内部类!");
            System.out.println(inner.str);
        }
    }
    //output:
    我是静态内部类!
    
    Process finished with exit code 0

    4.匿名内部类

    匿名内部类的用法我们已经见过了,就是创建PriorityQueue对象时,默认创建的是小堆,需要传入比较器来创建大堆。

            PriorityQueue priorityQueue = new PriorityQueue<>(new Comparator() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 - o2;
                }
            });

    像上面这种在方法中使用new关键字创建一个匿名类的对象作为实参,里面这个匿名类就是匿名内部类,创建过程中的Comparator匿名类对象是继承所需传参类型的,在这里也就是Comparator类。

    如果使用自定义类型传入优先队列,是一定要实现比较器的,实现比较器最常见的方式就是匿名内部类与Lambda表达式。

    假设我有一个Person类数组,需要对他们的name排序,如果不使用内部类,就需要在Person类中实现比较器。

    import java.util.Arrays;
    import java.util.Comparator;
    
    class Preson {
        public String name;
        public Integer id;
        public Preson(String name, Integer id) {
            this.name = name;
            this.id = id;
        }
    
        @Override
        public String toString() {
            return "Preson{" +
                    "name='" + name + '\'' +
                    ", id=" + id +
                    '}';
        }
    }
    class PersonComparator implements Comparator
     {
        @Override
        public int compare(Preson o1, Preson o2) {
            return o1.name.compareTo(o2.name);
        }
    }
    public class Main {
        public static void main(String[] args) {
            Preson preson1 = new Preson("aboluo", 24);
            Preson preson2 = new Preson("zhousi", 25);
            Preson preson3 = new Preson("syyfjy", 2);
            Preson[] presons = {preson1, preson2, preson3};
            Arrays.parallelSort(presons, new PersonComparator());
            System.out.println(Arrays.toString(presons));
        }
    }
    //output:
    [Preson{name='aboluo', id=24}, Preson{name='syyfjy', id=2}, Preson{name='zhousi', id=25}]
    
    Process finished with exit code 0

    使用内部类上述代码就变为:

    import java.util.Arrays;
    import java.util.Comparator;
    
    class Preson {
        public String name;
        public Integer id;
        public Preson(String name, Integer id) {
            this.name = name;
            this.id = id;
        }
    
    
        @Override
        public String toString() {
            return "Preson{" +
                    "name='" + name + '\'' +
                    ", id=" + id +
                    '}';
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Preson preson1 = new Preson("aboluo", 24);
            Preson preson2 = new Preson("zhousi", 25);
            Preson preson3 = new Preson("syyfjy", 2);
            Preson[] presons = {preson1, preson2, preson3};
            Arrays.parallelSort(presons, new Comparator
    () {
                @Override
                public int compare(Preson o1, Preson o2) {
                    return o1.name.compareTo(o2.name);
                }
            });
            System.out.println(Arrays.toString(presons));
        }
    }
    //output:
    [Preson{name='aboluo', id=24}, Preson{name='syyfjy', id=2}, Preson{name='zhousi', id=25}]
    
    Process finished with exit code 0

    还有一个本地内部类,就是类定义在方法中,就不多说了,基本上不用,用法如下:

    public class Outer {
        public void func() {
            class Inner{
                //
            }
        }
    }

    相关文章

    java速学教程(入门到精通)
    java速学教程(入门到精通)

    java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

    下载

    相关标签:

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    相关专题

    更多
    PS使用蒙版相关教程
    PS使用蒙版相关教程

    本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

    23

    2026.01.19

    java用途介绍
    java用途介绍

    本专题整合了java用途功能相关介绍,阅读专题下面的文章了解更多详细内容。

    11

    2026.01.19

    java输出数组相关教程
    java输出数组相关教程

    本专题整合了java输出数组相关教程,阅读专题下面的文章了解更多详细内容。

    3

    2026.01.19

    java接口相关教程
    java接口相关教程

    本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

    2

    2026.01.19

    xml格式相关教程
    xml格式相关教程

    本专题整合了xml格式相关教程汇总,阅读专题下面的文章了解更多详细内容。

    4

    2026.01.19

    PHP WebSocket 实时通信开发
    PHP WebSocket 实时通信开发

    本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

    13

    2026.01.19

    微信聊天记录删除恢复导出教程汇总
    微信聊天记录删除恢复导出教程汇总

    本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

    93

    2026.01.18

    高德地图升级方法汇总
    高德地图升级方法汇总

    本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

    112

    2026.01.16

    全民K歌得高分教程大全
    全民K歌得高分教程大全

    本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

    155

    2026.01.16

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Kotlin 教程
    Kotlin 教程

    共23课时 | 2.7万人学习

    C# 教程
    C# 教程

    共94课时 | 7万人学习

    Java 教程
    Java 教程

    共578课时 | 47.8万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号