【问题标题】:Java: How are my static methods referencing their class' static global objects?Java:我的静态方法如何引用其类的静态全局对象?
【发布时间】:2015-09-13 16:17:01
【问题描述】:

this question regarding static methods 相关,但我觉得我的问题没有得到明确回答,因为我的问题有一些我不确定的细节。

我有一个手工制作的小型 api 类(只是一个 .class,没什么花哨的),它有一个在全局级别实例化的 javax 客户端对象。

final private static Login login = new Login("emadden", "password");
final private static String baseUrl = "http://example.com";

private static Client client = ClientBuilder.newClient().register(JacksonJsonProvider.class);
private static WebTarget target;
private static Invocation.Builder builder;
private static Response response;

因为 javax 客户端对象相当大,我想防止自己和其他可能想要使用 api 的人意外创建一堆这些相当大的客户端对象,所以所有的属性(包括客户端)和方法,除了 api 构造函数之外,都是静态的。

// example method
public static Response getFrom(String pathUrl) throws RuntimeException{
    try {
        target = (WebTarget) client.target(baseUrl).path(pathUrl); // TODO: remove cast
        builder = target.request(MediaType.APPLICATION_JSON);
        response = builder.get();
        response.close();
        if (response.getStatus() == 204) {
            System.out.println("GET successful");
        } else if (response.getStatus() != 200) {
            throw new RuntimeException("Failed : HTTP error cod : "
                    + response.getStatus());
        }
    } catch(RuntimeException e) {System.out.println(e.getMessage());}
    return response;
}

现在,在我使用 api 类的类 (main.class) 中,是一个全局变量,一个名为 data 的 ArrayList,它通过对 api 类的静态方法调用来实例化。

// Global scope
private static ArrayList<List> data = api.getFrom(baseUrl + pathUrl).readEntity(ArrayList.class)

在 main 中没有实例化 api 类,但 api.getFrom 方法确实引用了 api 的全局客户端对象,那么这是否意味着简单地调用此方法会创建客户端对象的实例?在其他地方再次调用它会创建另一个吗?

最后,我只是从方法中删除了“静态”,保持属性静态,允许我使用 main 中的 api 实例非静态地访问 api,但我担心有人创建的可能性一个 api 的实例,然后将其作为参数传递,无意中创建了它的副本。

所以,为了知识起见,并且可能阻止我上面描述的事情发生,当从静态上下文调用 api.getFrom() 时会发生什么,就像我最初所做的那样?它是否创建了全局变量的实例,只是在我们超出方法调用范围时才丢弃它们?我只是在方法中放弃并删除静态是正确的,还是有更好的方法来确保我或其他用户不会意外创建 api 实例和一堆大型客户端对象?

【问题讨论】:

  • 也许你应该问问自己为什么你觉得有必要创建这些大客户对象。最好学习如何正确使用数据库并对传递的内容进行分区。
  • 还有,你知道范围是什么吗?
  • 您没有提供足够的信息来回答这个问题。你只能说;这取决于。
  • "...这是否意味着简单地调用此方法会创建客户端对象的实例?"物体不会从有人摇晃的树上掉下来。创建对象的操作只有一种。
  • "...有人创建了 api 的实例,然后将其作为参数传递,无意中创建了它的副本。"再说一遍:仅仅通过传递对一个对象的引用并不能将另一个对象从某个帽子中拉出来。你是从哪里得到这个概念的?

标签: java static


【解决方案1】:

在java中,作用域的概念是相对于类的。没有全局变量,而是有类成员。当您定义一个静态方法变量时,它会在您所期望的对象之间共享。但真正的意图是静态变量是在没有类的任何对象的情况下使用的(使用类名而不是对象访问)。这施加了一个限制,即静态方法只能访问类的静态成员(非静态成员仅在使用构造函数实例化对象时创建)。

因为客户端相当大,我想让自己和其他任何可能想要使用 api 的人不小心创建一堆这些相当大的客户端对象,所以所有的属性(包括客户端)和方法,除了 api 构造函数,都是静态的。

似乎您想实现单例模式。让你所有的方法static.

那么这是否意味着简单地调用此方法会创建客户端对象的实例?在其他地方再次调用它会创建另一个吗?

没有一个没有实例化的静态成员,你必须使用静态块来实例化静态成员。加载类时执行静态块(在程序开头一次)。

希望这个简单的例子有所帮助

public class MyApi {
    private static ArrayList<List> data;

    static {
    data =  // initaion logic
    }
}

更多关于静态块tutorial
initialization using static blocks上的文档

【讨论】:

  • 谢谢!我只是在课堂环境中学习 Java,从来不用担心这类东西。我真正知道的是静态字段只能通过类名和其他静态方法访问。我从来不知道静态块。我现在可以看到我的“创建静态变量实例”的想法是完全错误的。我一定会更多地研究单例模式示例。
猜你喜欢
  • 1970-01-01
  • 2011-03-24
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-25
  • 1970-01-01
  • 2012-12-03
相关资源
最近更新 更多