英文:
Enum *seems* to be initialized more than once, the constructor is called more than once. If I’m right, then why?
问题
我正在阅读这个教程:
它首先运行: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:
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<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);
}
}
//---
}
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='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}
However, if I add this line in ClientAllOrders
:
Collection<Order> 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("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);
}
}
This is the output if I run ClientAllOrders
, note the orders created are different:
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}
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论