繁体   English   中英

在java中初始化实例变量时使用'this'?

[英]Using 'this' when initializing an instance variable in java?

我在IB的API中声明一个实例变量时已经看过this ,但这似乎是一个坏主意。 被分配工作后,发生this已经完全构造? 有关系吗?

我认为实例变量是在构造函数之前初始化的,因为它们可以被构造函数使用。 有一些异常,如果this用的?

如果它以某种方式工作,它似乎不是一个好主意 - second可用于FirstClass的构造函数? 如果是这样, SecondClassFirstClass之前构建? 这意味着num最终为3而i是10? 或者会出现运行时错误吗? 甚至有任何保证吗?

public class FirstClass {

    SecondClass second = new SecondClass(this);
    public int i = 3;

    FirstClass(){
        i = second.DoSomething();
    }
}

public class SecondClass{

    private int num = 10;

    SecondClass(FirstClass first){
        num = first.i;
    }
    public int DoSomething(){
        return num;
    }
    ...
}

我想IB有一个非常扎实的开发团队,知道他们在做什么。 你怎么看:

  1. this可以用于初始化实例变量吗?
  2. 它应该完成吗?

编辑

答案是肯定的,有一个保证的结果(现在 - 但继续阅读...),但不应该这样做,因为它很容易无意中改变了可以改变这个'保证'结果的代码。

我现在知道在构造一个新对象(例如FirstClass )时JVM:

  1. 为该类及其所有超类的所有实例变量分配内存。
  2. 使用默认值初始化所有变量
  3. “正确” 以文本顺序从其最高超类(即对象)开始初始化所有变量并以此类结束 - 因此,在初始化为3之前, second被初始化(即构造)。
  4. 如果这些“正确”初始化中的任何一个调用另一个方法或另一个构造函数,则调用第一个构造函数之前完成 - 因此在构造FirstClass之前构造并返回second构造函数。
  5. 如果通过实例初始化调用另一个构造函数(例如在第4项中),它将从第1项开始执行相同的过程(内存分配,初始化等)

这样做的原因很糟糕,“保证”结果可以通过两种方式改变:

  1. 如果更改了源代码顺序(例如,如果在构造second之前初始化i ),结果将会改变。 很容易不注意到这一点。
  2. 如果有人将我们的类(或类)子类化,他们可能不会意识到微妙的平衡,并且可能会在覆盖时改变影响结果的内容。

因此看起来IB的API会受到这种美味的影响,我现在必须牢记这一点。

感谢Emil H的回答和他对本文的指导,这最终促使我理解上述内容: http//www.artima.com/designtechniques/initializationP.html - 强烈推荐阅读。

还要感谢Alexander Drobyshevsky在答案中提出了非常相似的观点。

当然,有时你必须使用它,例如当通过构造函数给出的变量被调用为与实例变量相同时:

int count;
public Test(int count){  
    this.count = count;
}

是的, this (在内部是构造中对象的“指针”)可以在构造函数中使用。

一个愚蠢的例子可能是一个自我引用的类

class MySelf {
    Myself _me;
    public MySelf() { _me = this; }
}

还有更现实的例子。 想象一下,您希望一个类表示一个数学图,您将使用连接到自身的单个元素进行初始化。

有趣的问题。 在您描述的情况下,当您调用new FirstClass() ,类加载器会查找该类并在未加载它时加载它。 然后它似乎创建了一个FirstClass实例,其中所有字段都有其默认值,例如,second为null,i为0。

然后是类加载器加载SecondClass 创建并初始化SecondClass的实例,将num字段设置为10.然后构造函数调用传入FirstClass实例(字段具有已初始化到该点的值)。 因此,在构造函数中, SecondClassnum的值将设置为0。

SecondClass构造函数完成后,将对象get分配给FirstClasssecond字段(仍在初始化)。 之后i初始化为3.现在调用FirstClass的构造函数,并为i分配DoSomething()的返回值,在本例中为0。

如需进一步参考,请查看: http//www.artima.com/designtechniques/initializationP.html它给出了对象初始化的描述。

TL; DR所以回答你的问题:

  1. 是的, this可以在初始化实例变量时使用。
  2. 应该避免,因为如果某人移动字段(例如对它们进行排序)可能会改变您的类的行为,这是不可能的。

这有两种可能的Java变化; 首先,是您希望引用全局变量(来自外部范围)。 例如:

class First {

    private int x;

    public void setX(int x) {
    this.x = x; // outer x is equal to the parameter
    }

}

另一个用途,是引用当前对象的构造函数。 例如:

public Color {

    private int red, green, blue;

    public void Color(int r, int g, int b) {
    red = red;
    green = g;
    blue = b;
    }

    public void setColor(int r, g, b) {
    this(r,g,b);
    } 

}

通过使用3个参数调用此(1,2,3)来告诉编译器您希望引用带有3个参数的构造函数。

希望有所帮助!

起初,这是一个糟糕的方式。 您必须避免使用这些结构:使用未完全初始化的变量。 有时候使用“模板方法”设计模式可能会有所帮助。

正是在你的例子中,在这种情况下,在执行FirstClass构造函数之后,i = 0的结果值; 它取决于FirstClass中i的赋值顺序。 如果您通过下一个方式更改分配顺序:

public int i = 3;
SecondClass second = new SecondClass(this); // just order changed

在FirstClass构造函数执行完后,你得到答案i = 3。

this - 仅引用当前类实例。 它已经存在于您的类实例变量开始初始化时。 首先,所有变量都有其默认值(object为null,int为0等)。 在第二个初始化所有简单的赋值,如“int i = 3”,之后执行当前类的超级构造函数,最后执行当前类的构造函数。 简单变量按类中的顺序初始化为up,但是你不应该依赖它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM