简体   繁体   English

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

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

I've seen this used when declaring an instance variable in IB's API, but this seems like a bad idea. 我在IB的API中声明一个实例变量时已经看过this ,但这似乎是一个坏主意。 Is assignment guaranteed to occur after this has been fully constructed? 被分配工作后,发生this已经完全构造? Does it matter? 有关系吗?

I thought that instance variables were initialized prior to the constructor since they can be used by the constructor. 我认为实例变量是在构造函数之前初始化的,因为它们可以被构造函数使用。 Is there some exception if this is used? 有一些异常,如果this用的?

If it somehow works, it doesn't seem like a good idea - is second available to FirstClass 's constructor? 如果它以某种方式工作,它似乎不是一个好主意 - second可用于FirstClass的构造函数? If so, is SecondClass constructed prior to FirstClass ? 如果是这样, SecondClassFirstClass之前构建? Which means that num ends up being 3 and i is 10? 这意味着num最终为3而i是10? Or will there be a runtime error? 或者会出现运行时错误吗? Is there even any guarantee either way? 甚至有任何保证吗?

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;
    }
    ...
}

I'd like to think that IB have a pretty solid team of developers and know what they're doing. 我想IB有一个非常扎实的开发团队,知道他们在做什么。 What do you think: 你怎么看:

  1. Can this be used initializing instance variables? this可以用于初始化实例变量吗?
  2. Should it be done? 它应该完成吗?

EDIT 编辑

The answer is yes there is a guaranteed result (for now - but read on...), but no it shouldn't be done since its easy to inadvertently make changes to the code that could change this 'guaranteed' result. 答案是肯定的,有一个保证的结果(现在 - 但继续阅读...),但不应该这样做,因为它很容易无意中改变了可以改变这个'保证'结果的代码。

I now know that when constructing a new object (such as FirstClass ) the JVM: 我现在知道在构造一个新对象(例如FirstClass )时JVM:

  1. Allocates memory for all the instance variables of this class and all its superclasses. 为该类及其所有超类的所有实例变量分配内存。
  2. Initializes all the variables with default values 使用默认值初始化所有变量
  3. "Properly" initializes all the variables in textual order starting from its highest superclasses (ie Object) and finishing with this class - so second is initialized (ie constructed) prior to i being initialized to 3. “正确” 以文本顺序从其最高超类(即对象)开始初始化所有变量并以此类结束 - 因此,在初始化为3之前, second被初始化(即构造)。
  4. If any of these "proper" initializations call another method or another constructor, this is done before the first constructor is invoked - so second is constructed and returned prior to the FirstClass constructor being run. 如果这些“正确”初始化中的任何一个调用另一个方法或另一个构造函数,则调用第一个构造函数之前完成 - 因此在构造FirstClass之前构造并返回second构造函数。
  5. If another constructor is invoked by instance initialization (such as in item 4), it goes through the same process from item 1 (memory allocation, initialization etc) 如果通过实例初始化调用另一个构造函数(例如在第4项中),它将从第1项开始执行相同的过程(内存分配,初始化等)

The reason doing this is bad is that the 'guaranteed' result can change in two ways: 这样做的原因很糟糕,“保证”结果可以通过两种方式改变:

  1. If the source code order is changed (eg if i is initialized before second is constructed) the result will change. 如果更改了源代码顺序(例如,如果在构造second之前初始化i ),结果将会改变。 It would be easy not to notice this. 很容易不注意到这一点。
  2. If someone subclasses our class (or classes), they may not be aware of the delicate balance and could change something that affects the result when overwriting. 如果有人将我们的类(或类)子类化,他们可能不会意识到微妙的平衡,并且可能会在覆盖时改变影响结果的内容。

So it looks like IB's API suffers from this delicacy, which I will have to now keep in mind. 因此看起来IB的API会受到这种美味的影响,我现在必须牢记这一点。

Thanks to Emil H's answer and his direction to this article which ultimately led me to my understanding above: http://www.artima.com/designtechniques/initializationP.html - this is highly recommended reading. 感谢Emil H的回答和他对本文的指导,这最终促使我理解上述内容: http//www.artima.com/designtechniques/initializationP.html - 强烈推荐阅读。

Also thanks to Alexander Drobyshevsky who made a very similar point in his answer. 还要感谢Alexander Drobyshevsky在答案中提出了非常相似的观点。

Sure, sometimes you have to use this, for example when a variable given through the Constructor is called as same as a instance variable: 当然,有时你必须使用它,例如当通过构造函数给出的变量被调用为与实例变量相同时:

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

Yes, this (being internally a "pointer" to the object in construction) can be used in a constructor. 是的, this (在内部是构造中对象的“指针”)可以在构造函数中使用。

A stupid example could be a self refering class 一个愚蠢的例子可能是一个自我引用的类

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

And there are more realistic examples. 还有更现实的例子。 Imagine that you want a class to represent a mathematical graph, that you would initialize with a single element connected to itself. 想象一下,您希望一个类表示一个数学图,您将使用连接到自身的单个元素进行初始化。

Interesting question. 有趣的问题。 What happens in the case you describe is that when you call new FirstClass() the class loader looks up that class and loads it if its not loaded already. 在您描述的情况下,当您调用new FirstClass() ,类加载器会查找该类并在未加载它时加载它。 Then it seems to create a instance of FirstClass where all the fields have their default values, eg second is null and i is 0. 然后它似乎创建了一个FirstClass实例,其中所有字段都有其默认值,例如,second为null,i为0。

Then it the classloader loads SecondClass . 然后是类加载器加载SecondClass An instance of SecondClass is created and initialized which sets the num field to 10. Then the constructor get's called passing in the FirstClass instance (the fields have the values that have been initialized up to that point). 创建并初始化SecondClass的实例,将num字段设置为10.然后构造函数调用传入FirstClass实例(字段具有已初始化到该点的值)。 So the value of num in SecondClass will be set to 0 in the constructor. 因此,在构造函数中, SecondClassnum的值将设置为0。

After the SecondClass constructor is finished the object get's assigned to the second field in the FirstClass (which is still being initialized). SecondClass构造函数完成后,将对象get分配给FirstClasssecond字段(仍在初始化)。 After that i gets initialized to 3. Now the constructor of FirstClass get's called and i is assigned the return value of DoSomething() which in this case will be 0. 之后i初始化为3.现在调用FirstClass的构造函数,并为i分配DoSomething()的返回值,在本例中为0。

For further reference you could look at: http://www.artima.com/designtechniques/initializationP.html It gives a description of object initalization. 如需进一步参考,请查看: http//www.artima.com/designtechniques/initializationP.html它给出了对象初始化的描述。

TL;DR So to answere your questions: TL; DR所以回答你的问题:

  1. Yes, this can be used when initializing instance variables. 是的, this可以在初始化实例变量时使用。
  2. It should be avoided, since if someone moves the fields around (for instance sorting them) could change the behaviour of your class, which would not be expected. 应该避免,因为如果某人移动字段(例如对它们进行排序)可能会改变您的类的行为,这是不可能的。

this has two possible variations in Java; 这有两种可能的Java变化; first, is when you wish to refer to a global variable (from an outer scope). 首先,是您希望引用全局变量(来自外部范围)。 eg: 例如:

class First {

    private int x;

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

}

another use, is to refer to the current object's constructor. 另一个用途,是引用当前对象的构造函数。 eg: 例如:

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);
    } 

}

By calling this(1,2,3) with 3 parameters to tell the compiler you wish to refer to the constructor that takes 3 parameters. 通过使用3个参数调用此(1,2,3)来告诉编译器您希望引用带有3个参数的构造函数。

Hope that helps! 希望有所帮助!

At first, its a bad way to do so. 起初,这是一个糟糕的方式。 You have to avoid these constructions: using not completely initialized variables. 您必须避免使用这些结构:使用未完全初始化的变量。 Some time it might be helpful to use "Template Method" design pattern. 有时候使用“模板方法”设计模式可能会有所帮助。

Exactly for your example, in this case, result value of i = 0 after FirstClass constructor have executed; 正是在你的例子中,在这种情况下,在执行FirstClass构造函数之后,i = 0的结果值; And it depends on order of assignment of i in FirstClass. 它取决于FirstClass中i的赋值顺序。 If you change assignment order by next way: 如果您通过下一个方式更改分配顺序:

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

You get answer i = 3 after FirstClass constructor have executed. 在FirstClass构造函数执行完后,你得到答案i = 3。

this - is only reference to current class instance. this - 仅引用当前类实例。 Its already exist at a time your class instance variable are beginning initializing. 它已经存在于您的类实例变量开始初始化时。 At first all variables have their default values (object is null, int is 0, etc.). 首先,所有变量都有其默认值(object为null,int为0等)。 At second are initialized all simple assignments like "int i = 3", after that executing super constructor of your current class and finally executing constructor of current class. 在第二个初始化所有简单的赋值,如“int i = 3”,之后执行当前类的超级构造函数,最后执行当前类的构造函数。 Simple variables are initialized by order in the class up to down, BUT you should not rely on it. 简单变量按类中的顺序初始化为up,但是你不应该依赖它。

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

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