实例变量是否应该从Java中的非静态上下文进行操作

实例变量是否应该从Java中的非静态上下文进行操作,java,constructor,static-methods,Java,Constructor,Static Methods,我只是被Java弄湿了脚,所以如果这看起来有点幼稚,我道歉。我试图在实践中更好地理解访问实例/成员变量的约定 非静态实例变量是否可以从 非静态上下文 例如,如何修改下面的类定义以允许id和版本变量递增 class Foo { private int id; private int version; public String product; public String model; pr

我只是被Java弄湿了脚,所以如果这看起来有点幼稚,我道歉。我试图在实践中更好地理解访问实例/成员变量的约定

非静态实例变量是否可以从 非静态上下文

例如,如何修改下面的类定义以允许id和版本变量递增

    class Foo {
    
        private int id;
        private int version;
        public String product;
        public String model;
    
        private Foo( ) {
    
            // Can these variables be accessed from a non-static context?
            id++;
            version++;
    
        }
        ...
与静态场相比

      class Foo {

        private static int id;
        private static int version;
        public String product;
        public String model;

        private Foo( ) {

            id++;
            version++;

        }
        ...

        
第一个例子

一, 1. 模型一 首先

一, 1. 模式二 第二

第二个例子

一, 1. 模型一 首先

二, 2. 模式二 第二

您可以从非静态上下文访问静态变量,因为静态变量绑定到类。所以,即使您在非静态上下文中访问它,也会像在静态上下文中一样访问它

例如:-

MyClass obj = null;
obj.staticVar = 10;
令人惊讶的是,上面的代码没有抛出NPE,因为静态变量是在类名上访问的,而不管您如何访问它

因此,obj.staticVar实际上被MyClass.staticVar替换

但事实并非如此。不能从静态上下文访问非静态变量。因为,在静态上下文中,您没有对实例的任何引用。如果不引用该类的实例,则无法访问实例变量

话虽如此,也要注意,仅仅因为你能做某事,并不意味着这是一个好主意。在构造函数内部或任何非静态上下文中修改静态变量是一个糟糕的想法。因为,您对这些变量所做的任何更改都将反映在该类的所有实例中

相反,您应该使用静态初始化块来初始化静态变量。静态初始化块在类加载时执行,以初始化所有静态变量

您可以从非静态上下文访问静态变量,因为静态变量绑定到类。所以,即使您在非静态上下文中访问它,也会像在静态上下文中一样访问它

例如:-

MyClass obj = null;
obj.staticVar = 10;
令人惊讶的是,上面的代码没有抛出NPE,因为静态变量是在类名上访问的,而不管您如何访问它

因此,obj.staticVar实际上被MyClass.staticVar替换

但事实并非如此。不能从静态上下文访问非静态变量。因为,在静态上下文中,您没有对实例的任何引用。如果不引用该类的实例,则无法访问实例变量

话虽如此,也要注意,仅仅因为你能做某事,并不意味着这是一个好主意。在构造函数内部或任何非静态上下文中修改静态变量是一个糟糕的想法。因为,您对这些变量所做的任何更改都将反映在该类的所有实例中


相反,您应该使用静态初始化块来初始化静态变量。静态初始化块在类加载时执行,以初始化所有静态变量

如果您试图将这些属性保存为类中的静态变量,我强烈建议您不要这样做。这些id和版本字段应该放在管理它们的特定类中,用于该对象和需要它们的每个对象

这样,您可以向IdManager请求新id和新版本,并将其分配给您创建的对象


为了回答您的问题,某个类的所有实例都共享一个静态字段`因此任何修改都会影响所有实例。

如果您试图将这些属性作为类中的静态变量保存,我强烈建议您不要这样做。这些id和版本字段应该放在管理它们的特定类中,用于该对象和需要它们的每个对象

这样,您可以向IdManager请求新id和新版本,并将其分配给您创建的对象


为了回答您的问题,某个类的所有实例都共享一个静态字段`因此任何修改都会影响所有实例。

我认为您真正想要的是这样的

    private static int globalID;
    private int id;
    private static int version;
    public String product;
    public String model;

    private Foo( ) {

        this.id = globalID;
        globalID++;
        //...
      }

我想你真正想要的是这样的东西

    private static int globalID;
    private int id;
    private static int version;
    public String product;
    public String model;

    private Foo( ) {

        this.id = globalID;
        globalID++;
        //...
      }
静态字段在实例之间共享

相反,实例字段关闭到一个特定的实例范围

这就是为什么从第二个实例获取字段时,字段看起来会重置的原因

因此,要增加第一个实例的字段,请提供如下一些公共方法:

public void incrementId(){
  id++;
}
因此,您可以通过以下方式实现您的要求:

fooOne.incrementId(); // id => 2

fooTwo.incrementId(); // id => 2
静态字段在实例之间共享

相反,实例字段关闭到一个特定的实例范围

这就是为什么从第二个实例获取字段时,字段看起来会重置的原因

因此,要增加第一个实例的字段,请提供一些公共me 像这样的方法:

public void incrementId(){
  id++;
}
因此,您可以通过以下方式实现您的要求:

fooOne.incrementId(); // id => 2

fooTwo.incrementId(); // id => 2

你所展示的事实上是你想要的行为

在第一个示例中,您声明实例变量并在构造函数中递增它们,这只会影响实例


在第二个示例中,声明静态/类变量并在构造函数中递增它们。当您实例化类两次时,每次构造函数调用都会增加类变量,从而增加它们两次。

您演示的实际上是所需的行为

在第一个示例中,您声明实例变量并在构造函数中递增它们,这只会影响实例



在第二个示例中,声明静态/类变量并在构造函数中递增它们。将类实例化两次,每次构造函数调用都会增加类变量,从而使它们增加两次。

那么所有这些代码都是演示问题所需的最低限度的代码?我不这么认为。。。这是复制粘贴懒惰。请阅读@Bohemian我并不想懒惰,我只是想提供一个我想要表达的清晰的例子。抱歉,如果它太冗长了。@Bohemian。。。更新。。。更好?好多了!现在更清楚了。那么所有这些代码都是演示您的问题的最低要求?我不这么认为。。。这是复制粘贴懒惰。请阅读@Bohemian我并不想懒惰,我只是想提供一个我想要表达的清晰的例子。抱歉,如果它太冗长了。@Bohemian。。。更新。。。更好?好多了!现在更清楚了。除了您想使用AtomicInteger和incrementAndGet或getAndIncrement来管理并发性之外。除了您想使用AtomicInteger和incrementAndGet或getAndIncrement来管理并发性。@Bhesh:谢谢您纠正我的错误。我用你的方式思考,却写错了@贝什:谢谢你纠正我的错误。我用你的方式思考,却写错了+1感谢您的免责声明。。。我试图运用我对建筑蓝图规则的理解,哪种状态,应该意味着你可以;“应该”意味着你必须.+1谢谢你的“应该”免责声明。。。我试图运用我对建筑蓝图规则的理解,哪种状态,应该意味着你可以;应该意味着你必须。谢谢你的回答。。。我知道静态变量对于类来说是“全局的”,我非常确定它们是否可以或者应该从类的实例进行操作。我不认为这样做是非常明智的…谢谢你的回答。。。我知道静态变量对于类来说是“全局的”,我非常确定它们是否可以或者应该从类的实例进行操作。我不认为这样做是非常明智的…+1我喜欢你在这里的观点。。。在这方面,我可以简单地使用一个抽象类为所有实例提供默认的ctor字段吗?@Eddie B abstract class不会改变这个概念。即使这一个包含实例的字段,它们也将严格关闭到其实例范围,因为抽象类+子类被合并以创建一个实例。如果您真的需要在每个实例中共享这些字段,请将它们设置为静态。@Eddie B我建议您查看这本完美的书:我读过的学习Java基本概念的最佳书籍。现在开始订购。。。You rock:-@Eddie B这本书真正关注的是Java 6,但Java 7并没有带来很多东西,顺便说一句,这本新书还不存在。不客气+我喜欢你在这里的观点。。。在这方面,我可以简单地使用一个抽象类为所有实例提供默认的ctor字段吗?@Eddie B abstract class不会改变这个概念。即使这一个包含实例的字段,它们也将严格关闭到其实例范围,因为抽象类+子类被合并以创建一个实例。如果您真的需要在每个实例中共享这些字段,请将它们设置为静态。@Eddie B我建议您查看这本完美的书:我读过的学习Java基本概念的最佳书籍。现在开始订购。。。You rock:-@Eddie B这本书真正关注的是Java 6,但Java 7并没有带来很多东西,顺便说一句,这本新书还不存在。不客气;