Java类的初始化和清理(七)

简介: Java类的初始化和清理
// housekeeping/VarargType.java
public class VarargType {
    static void f(Character... args) {
        System.out.print(args.getClass());
        System.out.println(" length " + args.length);
    }
    static void g(int... args) {
        System.out.print(args.getClass());
        System.out.println(" length " + args.length)
    }
    public static void main(String[] args) {
        f('a');
        f();
        g(1);
        g();
        System.out.println("int[]: "+ new int[0].getClass());
    }
}

输出:

class [Ljava.lang.Character; length 1
class [Ljava.lang.Character; length 0
class [I length 1
class [I length 0
int[]: class [I

getClass() 方法属于 Object 类,将在"类型信息"一章中全面介绍。它会产生对象的类,并在打印该类时,看到表示该类类型的编码字符串。前导的 [ 代表这是一个后面紧随的类型的数组,I 表示基本类型 int;为了进行双重检查,我在最后一行创建了一个 int 数组,打印了其类型。这样也验证了使用可变参数列表不依赖于自动装箱,而使用的是基本类型。


然而,可变参数列表与自动装箱可以和谐共处,如下:

// housekeeping/AutoboxingVarargs.java
public class AutoboxingVarargs {
    public static void f(Integer... args) {
        for (Integer i: args) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        f(1, 2);
        f(4, 5, 6, 7, 8, 9);
        f(10, 11, 12);
    }
}

输出:

1 2
4 5 6 7 8 9
10 11 12

注意吗,你可以在单个参数列表中将类型混合在一起,自动装箱机制会有选择地把 int 类型的参数提升为 Integer


可变参数列表使得方法重载更加复杂了,尽管乍看之下似乎足够安全:

// housekeeping/OverloadingVarargs.java
public class OverloadingVarargs {
    static void f(Character... args) {
        System.out.print("first");
        for (Character c: args) {
            System.out.print(" " + c);
        }
        System.out.println();
    }
    static void f(Integer... args) {
        System.out.print("second");
        for (Integer i: args) {
            System.out.print(" " + i);
        }
        System.out.println();
    }
    static void f(Long... args) {
        System.out.println("third");
    }
    public static void main(String[] args) {
        f('a', 'b', 'c');
        f(1);
        f(2, 1);
        f(0);
        f(0L);
        //- f(); // Won's compile -- ambiguous
    }
}

输出:

first a b c
second 1
second 2 1
second 0
third

在每种情况下,编译器都会使用自动装箱来匹配重载的方法,然后调用最明确匹配的方法。


但是如果调用不含参数的 f(),编译器就无法知道应该调用哪个方法了。尽管这个错误可以弄清楚,但是它可能会使客户端程序员感到意外。


你可能会通过在某个方法中增加一个非可变参数解决这个问题:

// housekeeping/OverloadingVarargs2.java
// {WillNotCompile}
public class OverloadingVarargs2 {
    static void f(float i, Character... args) {
        System.out.println("first");
    }
    static void f(Character... args) {
        System.out.println("second");
    }
    public static void main(String[] args) {
        f(1, 'a');
        f('a', 'b');
    }
}

{WillNotCompile} 注释把该文件排除在了本书的 Gradle 构建之外。如果你手动编译它,会得到下面的错误信息:

OverloadingVarargs2.java:14:error:reference to f is ambiguous f('a', 'b');
\^
both method f(float, Character...) in OverloadingVarargs2 and method f(Character...) in OverloadingVarargs2 match 1 error

如果你给这两个方法都添加一个非可变参数,就可以解决问题了:

// housekeeping/OverloadingVarargs3
public class OverloadingVarargs3 {
    static void f(float i, Character... args) {
        System.out.println("first");
    }
    static void f(char c, Character... args) {
        System.out.println("second");
    }
    public static void main(String[] args) {
        f(1, 'a');
        f('a', 'b');
    }
}

输出:

first
second

你应该总是在重载方法的一个版本上使用可变参数列表,或者压根不用它。

10 枚举类型

Java 5 中添加了一个看似很小的特性 enum 关键字,它使得我们在需要群组并使用枚举类型集时,可以很方便地处理。以前,你需要创建一个整数常量集,但是这些值并不会将自身限制在这个常量集的范围内,因此使用它们更有风险,而且更难使用。枚举类型属于非常普遍的需求,C、C++ 和其他许多语言都已经拥有它了。在 Java 5 之前,Java 程序员必须了解许多细节并格外仔细地去达成 enum 的效果。现在 Java 也有了 enum,并且它的功能比 C/C++ 中的完备得多。下面是个简单的例子:


这里创建了一个名为 Spiciness 的枚举类型,它有5个值。由于枚举类型的实例是常量,因此按照命名惯例,它们都用大写字母表示(如果名称中含有多个单词,使用下划线分隔)。


要使用 enum,需要创建一个该类型的引用,然后将其赋值给某个实例:

// housekeeping/SimpleEnumUse.java
public class SimpleEnumUse {
    public static void main(String[] args) {
        Spiciness howHot = Spiciness.MEDIUM;
        System.out.println(howHot);
    }
}

输出:

MEDIUM

在你创建 enum 时,编译器会自动添加一些有用的特性。例如,它会创建 toString()方法,以便你方便地显示某个 enum 实例的名称,这从上面例子中的输出可以看出。编译器还会创建 ordinal() 方法表示某个特定 enum 常量的声明顺序,static values()方法按照 enum 常量的声明顺序,生成这些常量值构成的数组:

// housekeeping/EnumOrder.java
public class EnumOrder {
    public static void main(String[] args) {
        for (Spiciness s: Spiciness.values()) {
            System.out.println(s + ", ordinal " + s.ordinal());
        }
    }
}


目录
相关文章
|
4天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
10 0
|
4天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
10 0
|
5天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
21 9
|
6天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
25 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
|
7天前
|
存储 安全 Java
java多线程之原子操作类
java多线程之原子操作类
|
8天前
|
Java
Java中的多线程实现:使用Thread类与Runnable接口
【4月更文挑战第8天】本文将详细介绍Java中实现多线程的两种方法:使用Thread类和实现Runnable接口。我们将通过实例代码展示如何创建和管理线程,以及如何处理线程同步问题。最后,我们将比较这两种方法的优缺点,以帮助读者在实际开发中选择合适的多线程实现方式。
18 4
|
9天前
|
Java
在Java中,多态性允许不同类的对象对同一消息做出响应
【4月更文挑战第7天】在Java中,多态性允许不同类的对象对同一消息做出响应
15 2
|
14天前
|
Java
Java通过反射获取类调用方法
Java通过反射获取类调用方法
17 0
|
18天前
|
存储 安全 Java
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
32 0
|
25天前
|
Java
java面向对象高级分层实例_测试类(main方法所在的类)
java面向对象高级分层实例_测试类(main方法所在的类)
8 1