首页 > 其他分享 >彻底理解内部类的使用(详细篇)

彻底理解内部类的使用(详细篇)

时间:2022-10-05 20:23:31浏览次数:74  
标签:内部 彻底 void class 理解 static 详细 public String

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

前言

内部类相信大家都应该用过,但我也相信大家应该都只是很简单的使用。

所以今天,就来详细讲解内部类的使用,废话不多说,我们先赶紧来看吧。

在普通类中使用内部结构

先来看个示例:

Teacher类里面有个内部类Student

public class Teacher {

    private String msg = "我是一名老师";//只能在类内部访问

    public void say() {
        Student s = new Student();//实例化内部类的对象
        s.print();
    }

    //在Teacher类中的内部类
    class Student {
        public void print() {
            System.out.println(Teacher.this.msg);   //msg是Teacher类里面的属性
        }
    }

}
复制代码

测试类:

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.say();
    }
}
复制代码

输出结果:

我是一名老师

Process finished with exit code 0
复制代码

从整体的代码结构来讲,内部类的结构并不合理,所以内部类本身最大的缺陷在于破坏了程序的结构,但是破坏需要有目的的破坏,那么它也一定会有其优势,如果要想更好的观察出内部类的优势,就可以将内部类拿到外面来。我将上面的代码Student拿出来。

Teacher 类:

public class Teacher {

    private String msg = "我是一名老师";//只能在类内部访问

    public void say() {
        Student student = new Student(this);//实例化内部类的对象
        student.print();
    }

    public String getMsg() {
        return this.msg;
    }
}
复制代码

Student 类:

public class Student {

    private Teacher teacher;

    public Student(Teacher teacher) {
        this.teacher = teacher;
    }

    public void print() {
        System.out.println(this.teacher.getMsg());   //msg是Teacher类里面的属性
    }

}
复制代码

测试:

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.say();
    }
}
复制代码

输出结果:

我是一名老师

Process finished with exit code 0
复制代码

我们折腾了半天主要的目的就是为了让Student这个内部类可以访问Teacher这个类中的私有属性,如果不用内部类的时候整体代码会非常的麻烦,所以可以得出内部类的优点:轻松的访问外部类中的私有属性

需要注意的是内部类虽然可以方便的访问外部类中的私有成员或私有方法,同理**,外部类也可以轻松访问内部类中的私有成员或私有方法**。

示例如下:

public class Teacher {

    private String msg = "我是一名老师";//只能在类内部访问

    public void say() {
        Student student = new Student();//实例化内部类的对象
        student.print();
        System.out.println(student.info);
    }

    class Student {
        private String info = "我是一名学生";

        public void print(){
            System.out.println(Teacher.this.msg);
        }
    }
}

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.say();
    }
}
复制代码

输出结果:

我是一名老师
我是一名学生

Process finished with exit code 0
复制代码

使用了内部类之后,内部类与外部类之间的私有操作的访问就不再需要通过setter,getter以及其他的间接方式完成了,可以直接进行操作,但是需要注意的是,内部类本身也属于一个类,虽然在大部分情况下内部类往往是被外部类包裹的,但是外部依然可以产生内部类的实例化对象,而此时,内部类实例化对象的格式如下:

外部类.内部类 内部类对象 = new 外部类().new 内部类()

在内部类编译完成之后会自动形成一个Teacher$Student.class类文件,其中“$”这个符号换到程序中就变为“.”,所以内部类的全称:“外部类.内部类”。内部类与外部类之间可以直接进行私有成员的访问,这样一来内部类如果要是提供有实例化对象了,一定要先保证外部类实例化了。

public class Test {

    public static void main(String[] args) {
        Teacher.Student student = new Teacher().new Student();
        student.print();
    }
}
复制代码

如果此时Student类只允许Teacher类来使用,那么在这样的情况下就可以使用private进行私有定义

这样,此时的Student类就无法再外部使用,即在test中的这条语句 Teacher.Student student = new Teacher().new Student()就失效

在抽象类和接口中使用内部结构

在我们的java之中,类作为最基础的结构体实际上还有与之类似的抽象类或者是接口,抽象类和接口中都可以定义内部结构。

接口中定义内部接口

我们现在定义内部接口

public interface Study {

    public void study(XiaoMing xiaoMing);

    interface XiaoMing {
        public String getName();
    }

}
复制代码
public class StudyImpl implements Study {

    public void study(XiaoMing xiaoMing) {
        System.out.println(xiaoMing.getName());
    }

    class XiaoHua implements XiaoMing {

        public String getName() {
            return "我叫小华";
        }
    }
}
复制代码

测试:

public class Test {

    public static void main(String[] args) {
        Study study = new StudyImpl();
        study.study(((StudyImpl)study).new XiaoHua());
    }
}
复制代码

输出结果:

我叫小华

Process finished with exit code 0
复制代码

接口中定义内部抽象类

下面我们继续观察一个内部抽象类,内部抽象类可以定义在普通类,抽象类,接口内部都可以。

public interface Study {

    public void study();

    abstract class XiaoMing {
        public abstract String getName();
    }

}
复制代码
public class StudyImpl implements Study {

    public void study() {
        XiaoMing xiaoMing = new XiaoHua();
        System.out.println(xiaoMing.getName());
    }

    class XiaoHua extends XiaoMing {
        public String getName(){
            return "我叫小华";
        }
    }
}
复制代码

测试:

public class Test {

    public static void main(String[] args) {
        Study study = new StudyImpl();
        study.study();
    }
}
复制代码

输出结果:

我叫小华

Process finished with exit code 0
复制代码

用内部类实现外部接口

内部类还有一些更为有意思的结构,即:如果现在定义了一个接口,那么可以在内部利用类实现该接口,在JDK1.8之后,接口中追加了static方法可以不受到实例化对象的控制,现在就可以利用此特性来完成功能。

接口内部进行接口实现:

public interface Study {

    public void study();

    class XiaoMing implements Study {

        public void study() {
            System.out.println("我爱学习!!");
        }
    }

    public static Study getInstance() {
        return new XiaoMing();
    }
}
复制代码

测试:

public class Test {

    public static void main(String[] args) {
        Study study = Study.getInstance();
        study.study();
    }
}
复制代码

输出结果:

我爱学习!!

Process finished with exit code 0
复制代码

从上面可以看到,内部类是非常灵活的结构,只要你的语法满足了,各种需求都可以帮你实现!

static 定义内部类

static定义内部类

如果说现在内部类上使用了static定义,那么这个内部类就变成了外部类,static定义的都是独立于类的结构,所以该类结构就相当于是一个独立的程序类了。需要注意,static定义的不管是类还是方法只能够访问static成员,所以static定义的内部类只能够访问外部内中的static属性和方法

public class Teacher {

    private static final String msg = "我是一名老师";

    static class Student {
        public void print(){
            System.out.println(Teacher.msg);
        }
    }
}
复制代码

这个时候的Student类是一个独立类,如果此时要想实例化Student类对象,只需要根据“ 外部类.内部类 ”的结构实例化对象即可

格式如下 外部类.内部类 内部类对象 = new 外部类.内部类()

测试:

public class Test {

    public static void main(String[] args) {
        Teacher.Student student = new Teacher.Student();
        student.print();
    }
}
复制代码

输出结果:

我是一名老师

Process finished with exit code 0
复制代码

所以以后如果发现类名称上提供有.,首先应该立刻想到这是一个内部类的结构,如果可以直接进行实例化,则应该立刻认识到这是一个static定义的内部类,但是static定义内部类的形式来讲并不常用,static定义内部接口的形式最为常用

static定义内部接口

public interface StudyWarp {

    static interface XiaoMing {
        public String getToSchool();
    }

    static interface GOSchool {
        public boolean hasCar();
    }

    public static void study(XiaoMing xiaoMing, GOSchool goSchool) {
        if (goSchool.hasCar()) {
            System.out.println(xiaoMing.getToSchool());
        } else {
            System.out.println("没车送小明上学。");
        }
    }

}
复制代码
public class DefaultStudy implements StudyWarp.XiaoMing{
    @Override
    public String getToSchool() {
        return "我去上学!";
    }
}
复制代码
public class DefaultSchool implements StudyWarp.GOSchool{
    @Override
    public boolean hasCar() {
        return true;
    }
}
复制代码

测试:

public class Test {

    public static void main(String[] args) {
        StudyWarp.study(new DefaultStudy(),new DefaultSchool());
    }
}
复制代码

输出结果:

我去上学!

Process finished with exit code 0
复制代码

方法中定义内部类

内部类可以在任意的结构中定义,这就包括了:类中、方法中、代码块中。但在方法中定义内部类的情况比较多。

public class Teacher {

    private String msg = "我是一名老师";

    public void say(long time){

        class Student {     //内部类
            public void print(){
                System.out.println(Teacher.this.msg);
                System.out.println(time);
            }
        }

        new Student().print();

    }
}
复制代码
public class Test {

    public static void main(String[] args) {
        new Teacher().say(System.currentTimeMillis());
    }
}
复制代码

输出结果:

我是一名老师
1629704407680

Process finished with exit code 0
复制代码

此时在say方法内部提供有Student内部类的定义,并且发现内部类可以直接访问外部类中的私有属性也可以直接访问方法中的参数,但对于方法中的参数直接访问时从 JDK1.8 开始支持的。而在 JDK1.8 之前**,如果方法中定义的内部类要想访问方法中的参数则参数前必须追加final。**

之所以取消这样的限制是为了扩展函数式编程准备的。

匿名内部类

匿名类是一种简化的内部类的处理形式,其主要是在抽象类和接口的子类上使用的。

接口和抽象类是一样的。

public interface Study {

    public void study(String book);

}
复制代码
public class XiaoMing implements Study{
    @Override
    public void study(String book) {
        System.out.println(book);
    }
}
复制代码
public class Test {

    public static void main(String[] args) {
        Study study = new XiaoMing();
        study.study("红楼梦");
    }
}
复制代码

如果说现在Study接口中的XiaoMing子类只使用唯一的一次,那么是否还有必要将其定义为单独的类?那么在这样的要求下就发现这个时候定义的子类是有些多余了,所以就可以利用内部类的形式来解决此问题。

public interface Study {

    public void study(String book);

}
复制代码
public class Test {

    public static void main(String[] args) {
        Study study = new Study() {
            @Override
            public void study(String book) {
                System.out.println(book);
            }
        };
        study.study("红楼梦");
    }
}
复制代码

匿名内部类不一定要在抽象类或接口上,但只有在抽象类和接口上才有意义。有些时候为了更加方便的体现出匿名内部类的使用,往往可以利用静态方法做一个内部类的匿名内部类实现。

在接口中直接定义匿名内部类。

public interface Study {

    public void study(String book);

    public static Study getInstance(){
        return new Study() {
            @Override
            public void study(String book) {
                System.out.println(book);
            }
        };
    }
}
复制代码
public class Test {

    public static void main(String[] args) {
        Study.getInstance().study("红楼梦");
    }
}
复制代码

与内部类相比匿名内部类只是一个没有名字的只能够使用一次的,并且结构固定的一个子类。

总结:

方法,类,抽象类,接口,代码块中都可以定义内部结构——类,抽象类,接口。

本文主要讲了如何在内部类中使用内部类和接口中使用内部类以及如何使用static修饰的内部类和如何在方法中使用内部类。看完这篇相信你对内部类的理解更加深入了。

结尾

我是一个正在被打击还在努力前进的码农。如果文章对你有帮助,记得点赞、关注哟,谢谢!

来源:https://juejin.cn/post/6999533412881006600

标签:内部,彻底,void,class,理解,static,详细,public,String
From: https://www.cnblogs.com/konglxblog/p/16756274.html

相关文章

  • 程序员必备:Git入门,超详细
    本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。对于一个刚入行的程序员或者是大学生,我建议大家还是好好的把git学学,因为在现在大部分企业代码的管理工具都是使......
  • PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)详细教程
    摘要:Qt是常用的用户界面设计工具,而在Python中则使用PyQt这一工具包,它是Python编程语言和Qt库的成功融合。这篇博文通过图文详细介绍在PyCharm中如何完整优雅地安装配置P......
  • PyCharm与Anaconda超详细安装配置教程
    摘要:本文详细介绍如何在Windows10中安装PyCharm和Anaconda这两款Python中必备的软件,博文中每一步均有详细截图和步骤讲解,最后介绍如何使用Anaconda创建虚拟环境并在PyC......
  • 一篇文章让你彻底理解Java的单例设计模式
    下文是笔者编写的单例模式实现的八种方式,如下所示:单例模式的简介我们将一个类在当前进程中只有一个实例的这种模式,称之为“单例模式”那么Java代码如何实现一个单例模式呢?......
  • 项目管理、项目质量概念的理解
     项目管理与软件开发的质量、效率、最终成果息息相关。   软件管理就是一位具有俯瞰全局意识的优秀软件管理人员领导和协调整个项目。软件项目的管理工作分位四个......
  • TVM:Schedule的理解
    schedule与计算逻辑分离是自动代码生成技术的核心概念,由MITCASIL组的JonathanRagan-Kelley在2012年发表在SIGGRAPH上的文章率先提出,然后在2013年发表在PLDI上的文章给出......
  • Oracle11g完全卸载的详细步骤(超管用)
    由于需要,这会儿需要卸载掉本机上的oracle11g数据库(我是在Windows7系统上装的),在网上搜的了挺多方法的,有些说的不清楚。下面小编给大家整理关于oracle11g卸载步骤,一起看看......
  • 干货 | 通用 api 封装实战,带你深入理解 PO
    在普通的接口自动化测试中,如果接口的参数,比如url,headers等传参改变,或者测试用例的逻辑、断言改变,那么整个测试代码都需要改变。apiobject设计模式借鉴了pageobject的设计模......
  • 说说你对Vue的keep-alive的理解
    什么是keep-alive在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。也就是说,keep......
  • 表的理解、SQL语句
    什么是表数据库中最基本的单元是表:table数据库当中是以表格的形式表示数据的,因为表比较直观任何一张表都有行和列:行(row):被称为数据/记录列(column):被称为字段姓名字段......