likes
comments
collection
share

闲聊Java中$符的各种使用场景

作者站长头像
站长
· 阅读数 15

前言

在Java编程中,我们会经常看到$符的身影

闲聊Java中$符的各种使用场景

比如经常在配置文件中看到$符号作为变量占位符,用于在运行时动态地获取变量值。

闲聊Java中$符的各种使用场景

这种做法有助于提高代码的灵活性和可维护性。除了在配置文件中使用$符号外,我们还会在其他场景中遇到这个符号,例如内部类、Lambda表达式、自动生成的代码等。

闲聊Java中$符的各种使用场景

接下来,我将详细介绍$符号在Java编程中的各种应用场景,以帮助您更好地理解和运用这个符号。

1. $符号七大应用场景

1.1 内部类与匿名内部类

在Java中,当一个类被定义在另一个类的内部时,它被称为内部类。在编译之后,内部类的字节码文件名将包含外部类名、$符号和内部类名。例如,如果我们有一个名为Outer的外部类和一个名为Inner的内部类,那么编译后的字节码文件名为:Outer$Inner.class。同样,当我们创建匿名内部类时,编译器会为其生成一个类名,该类名包含外部类名、$符号以及一个编译器生成的数字序列,例如:Outer$1.class。

1.2 Lambda表达式与方法引用

从Java 8开始,Lambda表达式和方法引用成为了Java编程的重要组成部分。当编译器处理Lambda表达式和方法引用时,它会生成包含$符号的特殊方法名。例如,考虑以下Lambda表达式:

Runnable r = () -> System.out.println("Hello, world!");

编译后,将生成一个名为lambda$main$0的方法。在这种情况下,$符号用于区分由编译器生成的Lambda表达式方法和其他程序中的方法。

1.3. 自动生成的字段与方法

在某些情况下,Java编译器会为我们自动生成一些字段和方法,这些字段和方法的名字可能包含$符号。例如,当我们使用枚举类型(Enum)时,编译器会为枚举类生成一个名为$VALUES的静态字段,以及一个名为valueOf的静态方法。同样,当我们使用switch语句与枚举类型结合时,编译器会生成一个包含$符号的方法,用于实现对应的switch逻辑。

1.4. 自定义类名与变量名

虽然在Java编程中,通常不建议使用$符号作为类名或变量名的一部分,但这是允许的。例如,以下代码是有效的Java代码:

class MyClass$1 {
    int $value = 42;
}

然而,由于这种命名方法可能引起混淆,因此在实际编程中应该避免这样做。

1.5. 生成的代码和工具

在某些情况下,代码生成工具(如AspectJ,JAXB等)和字节码处理库(如ASM,CGLIB等)可能会在生成的类名、方法名或字段名中使用$符号。这是因为$符号在这些场景下能够提供一种有效的命名约定,避免与原始代码中的名称发生冲突。

1.6. 货币计算

在Java程序中,我们可能会使用BigDecimal或其他数据类型处理货币计算。在某些情况下,我们可以使用$符号作为货币值的前缀,以表示货币单位。虽然这不是Java语言的内置功能,但是可以作为一种编程约定来使用,以提高代码的可读性。

BigDecimal salary = new BigDecimal("5000.00");
BigDecimal bonus = new BigDecimal("1000.00");
BigDecimal total = salary.add(bonus);
System.out.println("Total: $" + total);

虽然这里的$符号并不是Java语言特性,但它在表示货币值时可以帮助提高代码的可读性。

1.7 在配置文件中动态获取变量值

在Java应用程序中,我们经常需要使用配置文件来存储和管理应用程序的设置。在许多情况下,配置文件会使用$符号作为占位符,用于动态获取变量值。以下是一些常见的配置文件格式和$符号的使用示例:

1.7.1 Java属性文件(.properties)

Java属性文件是一种简单的键值存储格式。在属性文件中,我们可以使用${key}的形式作为占位符,表示需要从其他地方获取值。

database.url = jdbc:mysql://${host}:${port}/${dbName}

在这个例子中,${host}、${port}和${dbName}是占位符,它们将在运行时被相应的值替换。

1.7.2 Spring Boot配置文件(application.yml 或 application.properties)

在Spring Boot应用程序中,我们通常使用YAML或属性文件来配置应用程序。在这些文件中,我们可以使用$符号和大括号来表示占位符。

server:
  port: ${app.port:8080}

在这个例子中,${app.port:8080}表示一个占位符,其值将在运行时从环境变量或其他配置源中获取。如果没有找到该值,将使用默认值8080。

1.7.3 Apache Maven POM文件(pom.xml)

Apache Maven是一种流行的Java构建工具。在Maven的POM文件中,我们可以使用$符号和大括号来表示占位符。

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

在这个例子中,${java.version}表示一个占位符,其值将在运行时从其他地方获取。

1.7.4 Java模板引擎(如Thymeleaf, FreeMarker, Velocity等)

在Java Web应用程序中,我们经常使用模板引擎来渲染HTML页面。许多模板引擎都支持使用$符号作为占位符,用于动态获取变量值。

<!-- Thymeleaf 示例 -->
<p th:text="${message}"></p>

<!-- FreeMarker 示例 -->
<p>${message}</p>

<!-- Velocity 示例 -->
<p>$message</p>

在这些例子中,$符号用于动态插入变量message的值。

1.7.5 Log4j2 配置文件中动态获取变量值

Log4j2是一个流行的Java日志框架,用于记录应用程序的运行状况。在Log4j2的配置文件中,我们可以使用$符号和大括号作为占位符,用于动态获取变量值。以下是一个Log4j2配置文件(log4j2.xml)的示例:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Properties>
        <Property name="logPath">${sys:user.home}/logs</Property>
    </Properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
        <RollingFile name="RollingFile" fileName="${logPath}/app.log" filePattern="${logPath}/app-%d{yyyy-MM-dd}.log.gz">
            <PatternLayout>
                <pattern>%d %p %c{1.} [%t] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
            <AppenderRef ref="RollingFile" />
        </Root>
    </Loggers>
</Configuration>

在这个例子中,我们使用${sys:user.home}作为占位符,表示用户主目录。在运行时,这个占位符将被相应的系统属性值替换。同时,我们还定义了一个名为logPath的自定义属性,它的值为${sys:user.home}/logs。在配置文件的其他部分,我们可以使用${logPath}来引用这个属性。

2. 在配置文件中$符号来获取变量值的原理

在配置文件中使用$符号获取变量值,其背后的原理主要包括解析占位符、变量替换和值来源。以下是详细说明:

  • 解析占位符: 配置文件中的占位符通常以$符号开头,后跟一对大括号({}),括号内包含变量名。例如,${variable}。在加载配置文件时,解析器会识别这种格式的占位符,并提取其中的变量名。

  • 变量替换: 解析器识别并提取占位符后,需要在运行时将其替换为实际的变量值。具体的替换过程取决于配置文件的格式和使用的库。例如,Java属性文件的解析器可能使用java.util.Properties类来完成变量替换,而Spring Boot配置文件的解析器可能使用Spring框架提供的PropertySourcesPlaceholderConfigurer类来完成替换。

  • 值来源: 变量值的来源可能有多种,例如环境变量、系统属性、外部配置文件等。解析器需要知道在哪里查找变量值。这通常是通过配置文件解析器的特性或规则来实现的。例如,在Java属性文件中,解析器可能首先查找系统属性,然后查找环境变量;而在Spring Boot配置文件中,解析器会按照特定的顺序查找多个PropertySource,这些PropertySource可以来自环境变量、系统属性、配置文件等。

  • 默认值和条件替换: 在某些情况下,配置文件解析器还支持为占位符提供默认值或进行条件替换。例如,Spring Boot的配置文件解析器允许我们使用:符号为占位符指定默认值,如${variable:defaultValue}。如果在运行时找不到variable的值,解析器将使用defaultValue作为替换值。此外,Spring Boot还支持@Conditional注解,这允许我们根据条件选择性地应用配置。

3. 为什么要是用$符而不使用别的符号?

在配置文件中使用$符号作为变量占位符的原因可以从历史、约定和可读性等方面来解释。

  • 历史原因: Unix和Linux操作系统中,环境变量的表示方法是以美元符号($)作为前缀,例如$PATH。这种表示法在很大程度上影响了其他技术的设计,包括各种配置文件格式。在很多配置文件中沿用$符号作为变量占位符,这是受到了Unix和Linux环境变量表示法的影响。

  • 约定俗成: 多年来,程序员们在各种配置文件和模板引擎中使用$符号作为变量占位符。这已经成为一种广泛接受的编程惯例。当大多数开发者都习惯于这种表示法时,继续使用$符号可以降低学习曲线,使新的配置文件格式更容易被接受。

  • 可读性: 在实际编程中,可读性是一个重要的考虑因素。$符号在许多编程语言和配置文件中具有特殊含义,它很容易引起开发者的注意。使用$符号作为占位符可以提高配置文件的可读性,有助于开发者快速理解代码的含义。

  • 避免冲突: 配置文件中的变量占位符需要使用一种不容易与其他文本内容混淆的符号。$符号在很多编程语言中具有特殊含义,因此在配置文件中使用$符号作为变量占位符可以减少与其他字符的冲突。

小结

总之,配置文件中$符号获取变量值的原理涉及到解析占位符、变量替换和值来源。通过在配置文件中使用$符号作为占位符,我们可以实现动态配置管理,从而提高代码的可读性和可维护性。不同的配置文件格式和库可能有不同的实现细节,但其背后的基本原理是相似的。

尽管$符号在配置文件中作为变量占位符有一定的优势,但并非所有的配置文件格式都使用$符号。有些配置文件可能会选择其他符号或表示法,这主要取决于设计者的偏好和目标。然而,在许多流行的配置文件和模板引擎中,$符号已经成为一种广泛使用的占位符。