Java内部类超详细总结(含代码示例)

简介: Java内部类超详细总结(含代码示例)什么是内部类什么是内部类?顾名思义,就是将一个类的定义放在另一个类的内部。概念很清楚,感觉很简单,其实关键在于这个内部类放置的位置,可以是一个类的作用域范围、一个方法的或是一个代码块的作用域范围。

Java内部类超详细总结(含代码示例)
什么是内部类
什么是内部类?
顾名思义,就是将一个类的定义放在另一个类的内部。
概念很清楚,感觉很简单,其实关键在于这个内部类放置的位置,可以是一个类的作用域范围、一个方法的或是一个代码块的作用域范围。
所以理解了概念只是第一步,掌握细节才能彻底搞定Java的内部类特性。
看例子,这是最普通的内部类:

public class Product1 {

class Design{
    private String name = "P30 pro";
    public String showName() {
        return name;
    }
}

class Content{
    private int i;
    Content(int value){
        i = value;
    }
    int value() {return i;}
}
public void show(int value) {
    Content c = new Content(value);
    Design d = new Design();
    System.out.println(d.showName());
    System.out.println(c.value());
}
public static void main(String[] args) {
    Product1 p = new Product1();
    p.show(6000);
}

}
说明:
上面这个示例展示了内部类最基础的用法,就是将一个或多个类的定义放在了外围内的内部。可以看到在show()方法中的使用和普通类一样,没有区别。

另外,在外围类的非静态方法之外的任意位置,不能通过直接new 内部类的方式创建内部类对象。会报编译错误。
像这样:
在这里插入图片描述
还有这样:
在这里插入图片描述
如果想要在外围类非静态方法之外创建内部类对象。怎么办呢?

正确的姿势是这样子:
在外围类中增加两个公共方法,返回内部类的引用。

public Design design() {
    return new Design();
}
public Content content(int value) {
    return new Content(value);
}

然后通过外部类对象调用方法的方式获取内部类对象。

public static void main(String[] args) {
    Product2 p = new Product2();
    p.show(6000);
    Product2.Content c1 = p.content(100);
    Product2.Design d1 = p.design();
}

值得注意的是,外部类之外的其他类,也是不能直接访问到该外部类的内部类对象的。
会报编译错误。这也符合内部类的定义,就是为外围类服务的嘛!

内部类的特性
1.可以链接到外部类
当生成一个内部类对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问外围对象的所有成员,而不需要任何特殊的条件。

下面的例子是《Java编程思想》中的示例
首先定义一个Selector接口

public interface Selector {

boolean end();
Object current();
void next();

}
然后定义一个Sequence类,其中定义有一个private的内部类。

public class Sequence {

private Object[] items;
private int next = 0;
public Sequence(int size) {items = new Object[size];}
public void add(Object x) {
    if(next < items.length) {
        items[next++] = x;
    }
}
private class SequenceSelector implements Selector{
    private int i = 0;
    public boolean end() {
        return i == items.length;
    }
    public Object current() {
        return items[i];
    }
    public void next() {
        if(i < items.length) {i++;}
    }
}
public Selector selector() {
    return new SequenceSelector();
}
public static void main(String[] args) {
    Sequence sequence = new Sequence(10);
    for(int i = 0; i < 10; i++) {
        sequence.add(Integer.toString(i));
    }
    Selector selector = sequence.selector();
    while(!selector.end()) {
        System.out.print(selector.current() + " ");
        selector.next();
    }
}

}
说明:
可以看到SequenceSelector是一个内部类,其end()、current()和next()都用到了外围类中private的items字段。

2.使用.this和.new
.this的用法
如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。
如下所示:

public class DotThis {

void name() {System.out.println("name");}
public class Inner{
    public DotThis outer() {
        return DotThis.this;
    }
}
public Inner inner() {return new Inner();}
public static void main(String[] args) {
    DotThis dt = new DotThis();
    DotThis.Inner inner = dt.inner();
    inner.outer().name();
}

}
需要注意DotThis.this只是产生了正确的外部类引用。并没有创建外部类对象。

.new的用法
可以通过该语法创建内部类对象,不过要注意的是要使用外部类的对象去创建。

public class DotNew {

public class Inner{}
public static void main(String[] args) {
    DotNew dn = new DotNew();
    DotNew.Inner dnInner = dn.new Inner();
}

}
内部类分类
1、局部内部类
定义在一个方法中或是方法中某一作用域内的类。称作局部内部类。

public class Product3 {

public Section section(String inputName) {
    class ASection implements Section{
        private String name;
        private ASection(String name) {
            this.name = name;
        }
        @Override
        public String hello() {
            return name + " say hello";
        }
    }
    return new ASection(inputName);
}
public static void main(String[] args) {
    Product3 p = new Product3();
    Section section = p.section("aaaaa");
    System.out.println(section.hello());
}

}
ASection是一个Section接口的实现,Section接口代码如下:

public interface Section {

String hello();

}
说明:

该内部类在section()方法中,该方法之外不能访问ASection类;
方法内部类不允许使用访问权限修饰符(public、private、protected);
注意方法返回的是Section 的引用,即有向上转型。
另外还可以将内部类的定义放在方法中某一语句块中,如if语句块中。

public class Product4 {

public String check(boolean flag) {
    String checkId = null;
    if(flag) {
        class DetailCheck{
            private String id;
            private DetailCheck(String id) {
                this.id = id;
            }
            String getId() {
                return id;
            }
        }
        DetailCheck dc = new DetailCheck("1111");
        checkId = dc.getId();
    }
    return checkId;
}
public static void main(String[] args) {
    Product4 p = new Product4();
    System.out.println(p.check(true));
}

}
说明:
DetailCheck内部类在if语句块中,因此它的作用范围也在if语句块的范围之内。超出该范围是不可用的。比如这样就会编译报错:
在这里插入图片描述

2、匿名内部类
匿名内部类其实是一种特殊的方法内部类(局部内部类)。它特殊在于将内部类的定义和其对象创建结合在了一块。没有通过class关键字显示声明内部类名称,故谓之“匿名”。
看代码示例:

public class Product5 {

public Section section() {
    return new Section() {
        private String name = "hayli";
        @Override
        public String hello() {
            // TODO Auto-generated method stub
            return name + " haha";
        }
    };
}
public static void main(String[] args) {
    Product5 p = new Product5();
    p.section();
}

}
说明:
此处Section可以是接口,也可是基类。

3、嵌套类(静态内部类)
使用static关键字修饰的内部类,叫做静态内部类,也称作嵌套类。
嵌套类和普通内部类之间最大的区别是:

普通内部类对象隐式地保存了一个引用,指向创建它的外部类对象。而嵌套类创建对象,并不需要外部类对象。
不能从嵌套类的对象中访问非静态的外部类对象。
普通内部类不能有static数据和static字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西。
public class Product6 {

private static int id = 100;
private static class BSection implements Section{
    private String name = "bbbb";
    @Override
    public String hello() {
        return name + " hello";
    }
    // 只能访问外部类的静态数据或字段
    public int getId() {return id;}
    
    // 可以包含静态数据或方法
    static int x = 200;
    public static void test1() {}
    
    // 可以再嵌套一层
    static class BInner{
        private String name;
        static void test1() {System.out.println("inner ===");}
    }
}
public static void main(String[] args) {
    Section section = new BSection();
    section.hello();
}

总结
本篇介绍了什么是内部类、内部类最普通定义方法和Java内部类的几种具体类型详解。虽然工作中使用内部类的机会不会,但是了解这些最基础的知识,真的在项目中遇到内部类的写法,也能看懂是怎么回事了。
原文地址https://www.cnblogs.com/happyone/p/11306419.html

相关文章
|
1天前
|
Java 编译器 程序员
Java一分钟之第一行Java代码:输出"Hello, World!"
【5月更文挑战第7天】本文引导初学者编写运行第一个Java程序——打印&quot;Hello, World!&quot;,介绍基本代码结构及常见问题。包括语法错误(如缺少分号、缩进不规范)、编译运行问题(忘记编译、运行错误)和环境配置问题(JDK未安装、环境变量未设置)。建议检查语法、熟悉编译运行流程并正确安装配置JDK。通过实战演练,从编写到运行,迈出Java编程第一步。
10 0
|
1天前
|
Java
接口在增强Java代码的灵活性方面起着关键作用
Java接口增强代码灵活性,实现多态性、解耦、多继承和扩展性。通过接口,类可隐藏实现细节,实现抽象化,促进模块化和维护性。接口定义方法,允许不同类实现,减少依赖,便于测试和修改。同时,接口提供多继承解决方案,使代码更具扩展性,易于添加新功能。
13 4
|
2天前
|
搜索推荐 Java Shell
8大Java排序方法(由简入繁),有代码详解和原理指导
8大Java排序方法(由简入繁),有代码详解和原理指导
17 0
|
2天前
|
Java Apache
Java代码使用POI导出的单元格加上边框和背景色
【5月更文挑战第3天】Java代码使用POI导出的单元格加上边框和背景色
19 0
|
2天前
|
Java Apache
Java代码使用POI导出的单元格的字体加粗设置
【5月更文挑战第3天】Java代码使用POI导出的单元格的字体加粗设置
20 1
|
6天前
|
Java
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
35 0
|
7天前
|
Java
简单的 Java 计算器示例
这是一个Java计算器程序,接收用户输入的两个数字和一个运算符(+,-,*,/),通过`Scanner`获取输入,使用`switch`进行计算。当运算符为除法时,检查除数是否为0,防止除零错误。最后,它打印出计算结果。
13 0
|
8天前
|
Java Spring
Java 效率编码 必备插件 Lombok 让代码更优雅
该内容是一个关于Lombok插件的教程摘要:介绍了Lombok用于减少Java开发中的模板代码,提升效率;讲解了如何在IntelliJ IDEA中安装Lombok插件,以及在pom.xml中添加依赖;并提到了@Data注解能自动生成getter/setter、equals、hashCode和toString方法,@Slf4j注解自动处理日志,@Builder用于构建对象,以及@AllArgsConstructor和@NoArgsConstructor注解生成构造函数。还鼓励探索更多Lombok的注解用法。
|
8天前
|
Java 关系型数据库 测试技术
Java代码一键生成数据库文档(案例详解)
Screw是一个自动化数据库文档生成工具,能根据数据库表结构快速生成简洁、多格式(HTML、Word、Markdown)的文档,支持MySQL、MariaDB等多数据库。它使用Freemarker模板,允许用户自定义样式。依赖包括HikariCP数据库连接池和对应JDBC驱动。通过在Java代码或Maven插件中配置,可方便生成文档。示例代码展示了如何在测试用例中使用Screw。文档效果依赖于数据库中的表和字段注释。
|
8天前
|
NoSQL Java API
java一行代码实现RESTFul接口
Spring Data REST是构建在Spring Data之上的库,可自动将repository转换为REST服务,支持JPA、MongoDB、Neo4j、GemFire和Cassandra。无需手动创建Service和Controller层。要开始,需配置JPA数据源,创建实体类和Repository接口。快速实现REST接口,只需引入spring-boot-starter-data-rest Maven依赖,并在Repository接口上添加@RepositoryRestResource注解。