Java基本语法之内部类示例详解

目录
  • 1.内部类概念及分类
  • 2.实例内部类
    • 2.1实例内部类的创建
    • 2.2使用.this和.new
    • 2.3内部类实现迭代打印
    • 2.4内部类的继承
  • 3.静态内部类
  • 4.匿名内部类

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获取外围类对象,然后使用获得的这个外围类对象来使用外围类的变量与方法。

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()才能通过编译。

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

程序生成一个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<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            @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<Preson> {
    @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<Preson>() {
            @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内部类的资料请关注我们其它相关文章!

(0)

相关推荐

  • 全面探究 Java 内部类

    目录 一. 实例内部类 1. 定义 2. 如何获取实例内部类这个对象的引用 3. 注意事项 二. 静态内部类 1. 定义 2. 如何获取静态内部类这个对象的引用 3. 注意事项 三. 匿名内部类 1. 定义 2. 常见用法 3. 注意事项 内部类(inner class)是定义在另一个类中的类.为什么要使用内部类呢?主要有两个原因:1.内部类可以对同一个包中的其他类隐藏.2.内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据. 下面,我就来带领大家去学习Java中比较常见的几种内部

  • 详解Java匿名内部类

    匿名内部类: 先举个例子吧,给大家看一下什么是匿名内部类,Endeavor刚刚接触的时候,觉得哇哦,好奇怪的样子,这也太别扭了吧,不知道大家是什么感觉. 为了进行对比,先举一个正常的类方法调用的例子(大家应该都看的懂吧): 输出结果为: 接下来便开始说正题吧,匿名内部类,通过名字,想必大家就知道什么是匿名内部类了吧, 1.定义:就是没有名字的内部类(内部类之前介绍过了哦). 2.使用内部类有什么好处呢,一句话就概括了:简化书写,至于是怎么简化的,哪里简化了等下再说. 3.先说一下什么时候使用匿名

  • 一起来了解Java的内部类

    目录 内部类: 内部类的总结: 一.为什么要用内部类? 二.内部类的好处: 总结 内部类: 其实内部类顾名思义,就是类中类,一个类里面还有一个类. 内部类分为四种: 1.普通内部类 2.静态内部类 3.方法内部类 4.匿名内部类 我们一一去了解一下~~ A.普通内部类: 我们先通过代码去了解一下: package InternalClass; /** * 内部类 */ public class Car { public int a = 10; public int b = 20; //外部类的方

  • 解析JavaSe的内部类

    目录 内部类 1.内部类简介 2.非静态内部类 3.静态内部类 4.匿名内部类 总结 内部类 1. 内部类简介 (1) 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类. (2) 内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问.但外部类不能访问内部类的实现细节,例如内部类的成员变量. (3) 匿名内部类适合用于创建那些仅需要一次使用的类. (4) 在java中内部类主要分为成员内部类(非静态内部类.静态内

  • Java的内部类总结

    目录 前言 一,成员内部类 1,成员内部类的特点 2,成员内部类的实现 3,内部类和外部类的关系 二,静态内部类 1,静态内部类的特点 2,比较成员内部类和静态内部类 3,静态内部类的实现 三,方法内部类 1,方法内部类的特点 2,方法内部类的实现 四, 匿名内部类 1,匿名内部类的特点 2,匿名内部类的实现 总结 前言 最近看了内部类后,总结一下,首先内部类嵌套在其他内部的类,根据出现的位置和关键字,可以分为以下四种类:成员内部类,静态内部类,方法内部类,匿名内部类,接下来就介绍下这四种类,记

  • Java十分钟精通内部类的使用

    内部类: 其实内部类顾名思义,就是类中类,一个类里面还有一个类. 内部类分为四种: 普通内部类 静态内部类 方法内部类 匿名内部类 我们一一去了解一下~~ A.普通内部类: 我们先通过代码去了解一下: package InternalClass; /** * 内部类 */ public class Car { public int a = 10; public int b = 20; //外部类的方法 public void method() { System.out.println("我是外部

  • Java基本语法之内部类示例详解

    目录 1.内部类概念及分类 2.实例内部类 2.1实例内部类的创建 2.2使用.this和.new 2.3内部类实现迭代打印 2.4内部类的继承 3.静态内部类 4.匿名内部类 1.内部类概念及分类 将一个类定义在另一个类的内部或者接口内部或者方法体内部,这个类就被称为内部类,我们不妨将内部类所在的类称为外围类,除了定义在类,接口,方法中的内部类,还有一种特殊的内部类,那就是使用关键字new创建一个匿名类的对象,而这个匿名类其实就是一个内部类,具体说是一个匿名内部类,经常用于传入构造器实参构造对

  • Java的jstack命令使用示例详解

    目录 jstack命令简介 jstack命令参数 -F参数 -l参数 -m参数 -h 和 -help 结尾 jstack命令简介 jstack(Java Virtual Machine Stack Trace)是JDK提供的一个可以生成Java虚拟机当前时刻的线程快照信息的命令行工具.线程快照一般被称为threaddump或者javacore文件,是当前Java虚拟机中每个线程正在执行的Java线程.虚拟机内部线程和可选的本地方法堆栈帧的集合.对于每个方法栈帧,将会显示完整的类名.方法名.字节码

  • Java垃圾回收机制的示例详解

    目录 一.概述 二.对象已死? 1.引用计数算法 2.可达性分析算法 3.四种引用 4.生存还是死亡? 5.回收方法区 三.垃圾收集算法 1.分代收集理论 2.名词解释 3.标记-清除算法 4.标记-复制算法 5.标记-整理算法 一.概述 说起垃圾收集(Garbage Collection,下文简称GC),有不少人把这项技术当作Java语言的伴生产 物.事实上,垃圾收集的历史远远比Java久远,在1960年诞生于麻省理工学院的Lisp是第一门开始使 用内存动态分配和垃圾收集技术的语言.当Lisp

  • Java之单例设计模式示例详解

    单例设计模式 保证一个类在内存中只能有一个对象. 思路: 1)如果其他程序能够随意用 new 创建该类对象,那么就无法控制个数.因此,不让其他程序用 new 创建该类的对象. 2)既然不让其他程序 new 该类对象,那么该类在自己内部就要创建一个对象,否则该类就永远无法创建对象了. 3)该类将创建的对象对外(整个系统)提供,让其他程序获取并使用. 饿汉式: 一上来我就把对象给你 new 好了,你来了直接就可以拿去"吃"了 懒汉式 (要是有人问单例的延迟加载方式指的就是这种方式) 一开始

  • java 实现迷宫回溯算法示例详解

    用一个7 x 7的矩形表示迷宫,0和1分别表示的是通路和障碍.通过设计编写程序找到蓝色小球达到蓝色旗子的路线 思路: 构建一个迷宫(用二维数组)实现找通路的方法findRoad() 构建二维数组不难,我们主要是要实现findRoad()这个方法,在实现这个方法前,我们需要约定好一下几个点:小球的位置当作入口(1,1),小旗的位置当作出口(5,5)数组里数的含义分别为(0没有走过).(1障碍).(2走过且为正确的路线).(3走过且为错误的路线)将我们每一步的走法称为策略:下 -> 右 -> 上

  • Java实现并查集示例详解

    目录 题目 思路 find实现 join的实现 整体代码  题目 题目背景 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 思路 对于该题而言,考察的是并查集,也就是小怪兽逐个找上级领导的思路,指导找到最终的Boss停止下来,如果两个怪兽要打架,需要问一问他们的上级领导,领导再问领导,逐级向上,最终发现它们属于同一个Boss的部署的话就不能再打架了,这道题同样的思路,如果斗罗大陆的一开始白沉香不知道唐三是亲戚的话,他们就

  • Java实现广度优先遍历的示例详解

    目录 什么是广度优先 一个简单的例子 程序实现 总结 什么是广度优先 广度就是扩展开,广度优先的意思就是尽量扩展开.所以在算法实现的时候,就是一个循环遍历枚举每一个邻接点.其基本思路就是按层扩展,扩得越广越好. 伪代码如下: for(int i = 0; i < children.size(); i++){ children.get(i); // 调用每一个子节点 } 一个简单的例子 我们以一个简单的迷宫为例,以1代表墙,0代表路径,我们构造一个具有出入口的迷宫. 1 1 0 1 1 1 1 1

  • Java设计模式之适配器模式的示例详解

    目录 定义 分类 案例 需求 方案一:类适配器 方案二:对象适配器 方案三:接口适配器 对比分析 方案一:类适配器 方案二:对象适配器 方案三:接口适配器 总结 定义 适配器模式,即将某个类的接口转换成客户端期望的另一个接口的表示,主要目的是实现兼容性,让原本因为接口不匹配,没办法一起工作的两个类,可以协同工作. 分类 类适配器 对象适配器 接口适配器 案例 需求 手机充电,通过手机充电器将220V电压适配为5V 方案一:类适配器 定义220V交流电(被适配者的角色) /** * 220V交流电

  • Java装饰者模式的示例详解

    目录 定义 案例 需求 方案 分析 使用场景 知识点补充 定义 装饰者模式:在不改变原有对象的基础之上,动态的将功能附加到对象上,提供了继承更有弹性的替代方案,也体现了开闭原则 案例 需求 一个人去咖啡店点了一杯卡布奇诺,加了一份热牛奶 方案 定义咖啡基类 public abstract class Coffee { private String desc; private float price; public abstract float cost(); public String getD

  • Java设计模式之外观模式示例详解

    目录 定义 案例 需求 方案:外观模式实现 分析 总结 定义 外观模式为多个复杂的子系统,提供了一个一致的界面,使得调用端只和这个接口发生调用,而无须关系这个子系统内部的细节 案例 需求 看电影的时候需要进行一系列的操作,比如打开播放器,放下屏幕,打开投影仪,打开音响等,这个要怎么进行管理呢 方案:外观模式实现 定义播放器类 public class Player { private static Player player = new Player(); private Player(){}

随机推荐