枚举*似乎*被多次初始化,构造函数被调用不止一次。如果我是对的,那为什么呢?

Enum *seems* to be initialized more than once, the constructor is called more than once. If I’m right, then why?

我正在通读本教程:

JAX-RS Delete Example

它首先 运行s: ClientAllOrders(),它创建了 5 个订单。然后它 运行s: ClientDeleteById(),删除订单 2 和 4。然后它 运行s ClientAllOrders(),并获取除订单 2、4 之外的所有订单。它创建订单这里:

public enum OrderService {
    Instance;
    private Map<Integer, Order> orders = new HashMap<>();

    OrderService() {
        Instant instant = OffsetDateTime.now().toInstant();
        for (int i = 1; i <= 5; i++) {
            Order order = new Order();
            order.setId(i);
            order.setItem("item " + i);
            order.setQty((int) (1 + Math.random() * 100));
            long millis = instant.minus(Period.ofDays(i))
                                 .toEpochMilli();
            order.setOrderDate(new Date(millis));
            orders.put(i, order);
        }
    }
//---
}

请注意 OrderResource 不是 Singleton,因此默认情况下会为每个新请求创建资源 class 的新实例,但是 OrderService.constructor仅被称为 ones 并且 Enum 按预期仅初始化一次。

上述情况导致此输出:

// ClientAllOrders:

Order{id=1, item='item 1', qty=62, orderDate=Fri Jul 24 18:27:51 EDT 2020}
Order{id=2, item='item 2', qty=100, orderDate=Thu Jul 23 18:27:51 EDT 2020}
Order{id=3, item='item 3', qty=29, orderDate=Wed Jul 22 18:27:51 EDT 2020}
Order{id=4, item='item 4', qty=28, orderDate=Tue Jul 21 18:27:51 EDT 2020}
Order{id=5, item='item 5', qty=28, orderDate=Mon Jul 20 18:27:51 EDT 2020}

// ClientDeleteById – deletes orders 2 and 4:

true
true

// Run ClientAllOrders again:

Order{id=1, item='item 1', qty=62, orderDate=Fri Jul 24 18:27:51 EDT 2020}
Order{id=3, item='item 3', qty=29, orderDate=Wed Jul 22 18:27:51 EDT 2020}
Order{id=5, item='item 5', qty=28, orderDate=Mon Jul 20 18:27:51 EDT 2020}

但是,如果我在 ClientAllOrders 中添加这一行:

Collection<Order> c = OrderService.Instance.getAllOrders();
c.forEach(System.out::println);

然后再次调用OrderService.constructor,地图中现在有5个新订单。为什么不像 REST 请求都共享同一个 Enum 对象,在这里,Enum 被再次初始化并且 constructor() 被再次调用创建 5 个新订单?

    public class ClientAllOrders {
        
        public static void main(String[] args) {
            Client client = ClientBuilder.newClient();
            
            //get all  orders
            WebTarget allOrderTarget = client.target("http://localhost:8080/jaxrs-delete-example/orders");
    
            Response response = allOrderTarget.request().get();
            List<Order> orders = response.readEntity(new GenericType<List<Order>>() {});
            System.out.println("Orders by REST call:");
            orders.forEach(System.out::println);
            
// Added this line - Enum is initialized again and constructor called again, creating new orders:
            Collection<Order> c = OrderService.Instance.getAllOrders();
            System.out.println("Orders created again:");
            c.forEach(System.out::println);
        }
    }

这是我 运行 ClientAllOrders 的输出,请注意创建的订单不同:

Orders by REST call:
Order{id=1, item='item 1', qty=59, orderDate=Fri Jul 24 18:35:24 EDT 2020}
Order{id=2, item='item 2', qty=14, orderDate=Thu Jul 23 18:35:24 EDT 2020}
Order{id=3, item='item 3', qty=78, orderDate=Wed Jul 22 18:35:24 EDT 2020}
Order{id=4, item='item 4', qty=3, orderDate=Tue Jul 21 18:35:24 EDT 2020}
Order{id=5, item='item 5', qty=2, orderDate=Mon Jul 20 18:35:24 EDT 2020}

Orders created again:
Order{id=1, item='item 1', qty=1, orderDate=Fri Jul 24 18:35:24 EDT 2020}
Order{id=2, item='item 2', qty=53, orderDate=Thu Jul 23 18:35:24 EDT 2020}
Order{id=3, item='item 3', qty=76, orderDate=Wed Jul 22 18:35:24 EDT 2020}
Order{id=4, item='item 4', qty=31, orderDate=Tue Jul 21 18:35:24 EDT 2020}
Order{id=5, item='item 5', qty=25, orderDate=Mon Jul 20 18:35:24 EDT 2020}

客户端和服务器 运行 在不同的进程中,在不同的 JVM 中,独立。服务器有一个版本的enum OrderService,客户端有另一个。没有任何东西将枚举的这两个实例相互联系起来。

在您的例子中,“服务器”是一个应用程序服务器,您在其中部署 Web 应用程序“war”存档。 “客户端”是一个单独的 Java 程序,带有 main 方法。你 运行 从你的 IDE 使用“运行 作为 Java 应用程序”操作。