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

huangapple go评论75阅读模式
英文:

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

它首先运行:ClientAllOrders(),这将创建5个订单。然后它运行:ClientDeleteById(),这将删除订单2和4。然后它运行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,因此默认情况下,资源类的每个新请求都会创建一个新的实例,但是 OrderService.constructor 仅会被调用一次,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 – 删除订单2和4:

true
true

// 再次运行 ClientAllOrders:

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个新订单。为什么与所有共享同一 Enum 对象的 REST 请求不同,这里 Enum 被再次初始化,constructor() 被再次调用,创建了5个新订单?

public class ClientAllOrders {
    
    public static void main(String[] args) {
        Client client = ClientBuilder.newClient();
        
        // 获取所有订单
        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);
        
        // 添加了这行代码 - Enum 被再次初始化,构造函数被再次调用,创建了新订单:
        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}
英文:

I’m reading thru this tutorial:

JAX-RS Delete Example

It first runs: ClientAllOrders(), which creates 5 orders. Then it runs: ClientDeleteById(), which deletes orders 2 and 4. Then it runs ClientAllOrders(), and gets all orders except for orders 2, 4. It creates orders here:

public enum OrderService {
    Instance;
    private Map&lt;Integer, Order&gt; orders = new HashMap&lt;&gt;();

    OrderService() {
        Instant instant = OffsetDateTime.now().toInstant();
        for (int i = 1; i &lt;= 5; i++) {
            Order order = new Order();
            order.setId(i);
            order.setItem(&quot;item &quot; + 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);
        }
    }
//---
}

Note that OrderResource is not a Singleton, so by default a new instance of the resource class is created for each new request, however, the OrderService.constructor is called only ones and Enum in initialized only once as expected.

The above scenario results in this output:

// ClientAllOrders:

Order{id=1, item=&#39;item 1&#39;, qty=62, orderDate=Fri Jul 24 18:27:51 EDT 2020}
Order{id=2, item=&#39;item 2&#39;, qty=100, orderDate=Thu Jul 23 18:27:51 EDT 2020}
Order{id=3, item=&#39;item 3&#39;, qty=29, orderDate=Wed Jul 22 18:27:51 EDT 2020}
Order{id=4, item=&#39;item 4&#39;, qty=28, orderDate=Tue Jul 21 18:27:51 EDT 2020}
Order{id=5, item=&#39;item 5&#39;, 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=&#39;item 1&#39;, qty=62, orderDate=Fri Jul 24 18:27:51 EDT 2020}
Order{id=3, item=&#39;item 3&#39;, qty=29, orderDate=Wed Jul 22 18:27:51 EDT 2020}
Order{id=5, item=&#39;item 5&#39;, qty=28, orderDate=Mon Jul 20 18:27:51 EDT 2020}

However, if I add this line in ClientAllOrders:

Collection&lt;Order&gt; c = OrderService.Instance.getAllOrders();
c.forEach(System.out::println);

Then OrderService.constructor is called again, and the map now has 5 new orders in it. Why unlike the REST requests that all share the same Enum object, here, Enum was initialized again and the constructor() was called again creating 5 new orders?

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

This is the output if I run ClientAllOrders, note the orders created are different:

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

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

答案1

得分: 0

客户端和服务器在单独的进程中运行,分别在单独的JVM中独立运行。服务器拥有enum OrderService的一个版本,而客户端有另一个版本。没有任何东西将这两个枚举实例彼此链接起来。

在您的情况下,“服务器”是一个应用服务器,您在其中部署Web应用程序“war”存档。而“客户端”是一个独立的Java程序,带有一个main方法。您可以从IDE中以“run as Java application”的操作运行该程序。

英文:

The client and the server run in separate processes, in separate JVMs, independently. The server has one version of enum OrderService, and the client has another. Nothing links these two instances of the enum to each other.

In your case, the "server" is an application server, where you deploy the web application "war" archive. The "client" is a separate Java program with a main method. that you run from your IDE with the "run as Java application" action.

huangapple
  • 本文由 发表于 2020年7月26日 06:53:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63094390.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定