java 为什么在java中不允许分配给'this'?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7979623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:32:05  来源:igfitidea点击:

Why is assignment to 'this' not allowed in java?

javareferencethisvariable-assignment

提问by kostja

The error I get from the compiler is "The left hand side of an assignment must be a variable". My use case is deep copying, but is not really relevant.

我从编译器得到的错误是“赋值的左侧必须是一个变量”。我的用例是深度复制,但并不真正相关。

In C++, one can assign to *this.

在 C++ 中,可以赋值给*this.

The question is not how to circumvent assignment to this. It's very simple, but rather what rationale is there behind the decision not to make thisa variable.

问题不在于如何规避对this. 这很简单,但更重要的是决定不做this变量的背后有什么基本原理。

Are the reasons technical or conceptual?

原因是技术上的还是概念上的?

My guess so far - the possibility of rebuilding an Object in a random method is error-prone (conceptual), but technically possible.

到目前为止,我的猜测 - 以随机方法重建对象的可能性容易出错(概念上),但在技术上是可行的。

EDITPlease restrain from variations of "because java specs say so". I would like to know the reason for the decision

编辑请限制“因为 java 规范这么说”的变体。我想知道决定原因

采纳答案by aioobe

In C++, one can assign to *this

在 C++ 中,可以赋值给 *this

Yes, but you can't do this = somethingin C++, which I actually believe is a closer match for what you're asking about on the Java side here.

是的,但是你不能this = something用 C++来做,我实际上认为这与你在 Java 方面所问的更接近。

[...] what rationale is there behind the decision not to make thisa variable.

[...] 不制定this变量的决定背后有什么理由。

I would say clarity / readability.

我会说清晰度/可读性。

thiswas chosen to be a reserved word, probably since it's not passed as an explicit argument to a method. Using it as an ordinary parameter and being able to reassign a new value to it, would mess up readability severely.

this被选为保留字,可能是因为它没有作为显式参数传递给方法。将其用作普通参数并能够为其重新分配新值,会严重影响可读性。

In fact, many people argue that you shouldn't change argument-variables at all, for this very reason.

事实上,出于这个原因,很多人认为你根本不应该改变参数变量。

Are the reasons technical or conceptual?

原因是技术上的还是概念上的?

Mostly conceptual I would presume. A few technical quirks would arise though. If you could reassign a value to this, you could completely hide instance variables behind local variables for example.

我认为主要是概念性的。不过会出现一些技术怪癖。例如,如果您可以将值重新分配给this,则可以将实例变量完全隐藏在局部变量后面。

My guess so far - the possibility of rebuilding an Object in a random method is error-prone (conceptual), but technically possible.

到目前为止,我的猜测 - 以随机方法重建对象的可能性容易出错(概念上),但在技术上是可行的。

I'm not sure I understand this statement fully, but yes, error prone is probably the primary reason behind the decision to make it a keyword and not a variable.

我不确定我是否完全理解这个陈述,但是,容易出错可能是决定将其作为关键字而不是变量的主要原因。

回答by Stephen C

Are the reasons technical or conceptual?

原因是技术上的还是概念上的?

IMO, conceptual.

海事组织,概念。

The thiskeyword is a short hand for "the reference to the object whose method you are currently executing". You can't change what that object is. It simply makes no sense in the Java execution model.

this关键字是“对您当前正在执行其方法的对象的引用”的简写。你不能改变那个对象是什么。它在 Java 执行模型中毫无意义。

Since it makes no sense for thisto change, there is no sense in making it a variable.

既然this改变没有意义,把它变成一个变量也没有意义。

(Note that in C++ you are assigning to *this, not this. And in Java there is no *operator and no real equivalent to it.)

(请注意,在 C++ 中,您分配的是*this,而不是this。在 Java 中没有*运算符,也没有真正的等价物。)



If you take the view that you couldchange the target object for a method in mid flight, then here are some counter questions.

如果您认为可以在飞行途中更改方法的目标对象,那么这里有一些反问。

  • What is the use of doing this? What problems would this (hypothetical) linguistic feature help you solve ... that can't be solved in a more easy-to-understand way?

  • How would you deal with mutexes? For instance, what would happen if you assign to thisin the middle of a synchronized method ... and does the proposed semantic make sense? (The problem is that you either end up executing in synchronized method on an object that you don't have a lock on ... or you have to unlock the old thisand lock the new thiswith the complications that that entails. And besides, how does this make sense in terms of what mutexes are designed to achieve?)

  • How would you make sense of something like this:

    class Animal {
        foo(Animal other) {
           this = other;
           // At this point we could be executing the overridden
           // Animal version of the foo method ... on a Llama.  
        }
    }
    
    class Llama {
        foo(Animal other) {
        }
    }
    

    Sure you can ascribe a semantic to this but:

    • you've broken encapsulation of the subclass in a way that is hard to understand, and
    • you've not actually achieved anything particularly useful.
  • 这样做有什么用?这个(假设的)语言特征会帮助你解决哪些问题……无法以更易于理解的方式解决?

  • 你会如何处理互斥体?例如,如果你this在一个同步方法的中间赋值会发生什么......并且提议的语义有意义吗?(问题是你要么最终在一个没有锁定的对象上执行同步方法......要么你必须解锁旧的this并锁定新的this并伴随着随之而来的复杂性。此外,如何就互斥锁旨在实现的目标而言,这是否有意义?)

  • 你会如何理解这样的事情:

    class Animal {
        foo(Animal other) {
           this = other;
           // At this point we could be executing the overridden
           // Animal version of the foo method ... on a Llama.  
        }
    }
    
    class Llama {
        foo(Animal other) {
        }
    }
    

    当然,您可以为此赋予语义,但是:

    • 你以一种难以理解的方式破坏了子类的封装,并且
    • 你实际上并没有取得任何特别有用的东西。

If you try seriously to answer these questions, I expect you'll come to the conclusion that it would have been a bad idea to implement this. (But if you dohave satisfactory answers, I'd encourage you to write them up and post them as your own Answer to your Question!)

如果您认真地尝试回答这些问题,我希望您会得出这样的结论:实施这一点是个坏主意。(但如果您确实有满意的答案,我会鼓励您将它们写下来并作为您自己的问题的答案发布!)

But in reality, I doubt that the Java designers even gave this idea more than a moment's consideration. (And rightly so, IMO)

但实际上,我怀疑 Java 设计者是否考虑过这个想法。(没错,IMO)



The *this = ...form of C++ is really just a shorthand for a sequence of assignments of the the attributes of the current object. We can already do that in Java ... with a sequence of normal assignments. There is certainly no need for new syntax to support this. (How often does a class reinitialize itself from the state of another class?)

*this = ...C++的形式实际上只是当前对象属性赋值序列的简写。我们已经可以在 Java 中做到这一点……使用一系列正常的赋值。当然不需要新的语法来支持这一点。(一个类多久从另一个类的状态重新初始化自己?)

I note that you commented thus:

我注意到你是这样评论的:

I wonder what the semantics of this = xy;should be. What do you think it should do? – JimmyB Nov 2 '11 at 12:18

Provided xyis of the right type, the reference of this would be set to xy, making the "original" object gc-eligible- kostja Nov 2 '11 at 12:24

我想知道this = xy;应该是什么语义。你觉得它应该怎么做?– JimmyB 2011 年 11 月 2 日 12:18

如果xy类型正确,则 this 的引用将设置为xy从而使“原始”对象符合 gc 条件- kostja 2011 年 11 月 2 日 12:24

That won't work.

那行不通。

  1. The value of thisis (effectively) passed by value to the method when the method is invoked. The callee doesn't know where the thisreference came from.

  2. Even if it did, that's only one place where the reference is held. Unless nullis assigned in all places, the object cannot be eligible of garbage collection.

  1. 的值this为(有效)由值传递给该方法被调用的方法时。被调用者不知道this引用来自哪里。

  2. 即使是这样,那也只是一个保存参考的地方。除非null在所有地方都被赋值,否则对象不能被垃圾回收。

Ignoring the fact that this is technically impossible, I do not think that your idea would be useful OR conducive to writing readable / maintainable code. Consider this:

忽略这在技术上是不可能的事实,我认为您的想法对编写可读/可维护的代码没有用或有帮助。考虑一下:

public class MyClass {
    public void kill(MyClass other) {
        this = other;
    }
}

MyClass mine = new MyClass();

....

mine.kill(new MyClass());

// 'mine' is now null!

Why would you want to do that? Supposing that the method name was something innocuous rather than kill, would you expectthe method to be able to zap the value of mine?

你为什么想这么做?假设方法名称是无害的东西而不是kill,您是否希望该方法能够改变 的值mine

I don't. In fact, I think that this would be a misfeature: useless and dangerous.

我不。事实上,我认为这将是一个错误的特征:无用且危险。

Even without these nasty "make it unreachable" semantics, I don't actually see any good use-cases for modifying this.

即使没有这些讨厌的“使其无法访问”语义,我实际上也没有看到任何好的用例来修改this.

回答by Jigar Joshi

because thisis final,

因为thisfinal

thisis keyword, not a variable. and you can't assign something to keyword. now for a min consider ifit were a reference variable in design spec..and see the example below

this是关键字,而不是变量。并且您不能为关键字分配某些内容。现在考虑一下它是否是设计规范中的参考变量……并参见下面的示例

and it holds implicit reference to the object calling method. and it is used for reference purpose only, now consider you assign something to thisso won't it break everything ?

它包含对对象调用方法的隐式引用。它仅用于参考目的,现在考虑你分配一些东西,this所以它不会破坏一切吗?

Example

例子

consider the following code from Stringclass (Note: below code contains compilation error it is just to demonstrate OP the situation)

考虑String类中的以下代码(注意:下面的代码包含编译错误,只是为了演示 OP 的情况)

   public CharSequence subSequence(int beginIndex, int endIndex) {
      //if you assign something here
       this = "XYZ"  ;
       // you can imagine the zoombie situation here
      return this.substring(beginIndex, endIndex);
   }

回答by Xavi López

thisisn't even a variable. It's a keyword, as defined in the Java Language Specification:

this甚至不是一个变量。它是一个关键字,如Java Language Specification 中所定义:

When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed

当用作主要表达式时,关键字 this 表示一个值,该值是对调用实例方法的对象的引用(第 15.12 节),或对正在构造的对象的引用

So, it's not possible as it's not possible to assign a value to while.

因此,这是不可能的,因为无法为 赋值while

回答by nobar

Assigning to (*this)in C++ performs a copy operation -- treating the object as a value-type.

(*this)在 C++ 中赋值执行复制操作——将对象视为值类型

Java does not use the concept of a value-type for classes. Object assignment is always by-reference.

Java 不使用类的值类型的概念。对象分配始终是按引用的

To copy an object as if it were a value-type: How do I copy an object in Java?

将对象当作值类型复制如何在 Java 中复制对象?



The terminology used for Java is confusing though: Is Java “pass-by-reference” or “pass-by-value”

但是,Java 使用的术语令人困惑:Java 是“按引用传递”还是“按值传递”

Answer: Java passes references by value.(from here)

答:Java 按值传递引用。(从这里

In other words, because Java never treats non-primitives as value-types, every class-type variable is a reference (effectively a pointer).

换句话说,因为 Java 从不将非原语视为值类型,所以每个类类型变量都是一个引用(实际上是一个指针)。

So when I say, "object assignment is always by-reference", it might be more technically accurate to phrase that as "object assignment is always by the value ofthe reference".

因此,当我说“对象分配总是通过引用”时,将其表述为“对象分配总是通过引用的值”在技术上可能更准确。

The practical implication of the distinction drawn by Java alwaysbeing pass-by-value is embodied in the question "How do I make my swap function in java?", and its answer: You can't. Languages such as C and C++ are able to provide swap functions because they, unlike Java, allow you to assign from any variableby using a reference to that variable -- thus allowing you to change its value (if non-const) without changing the contents of the object that it previously referenced.

Java总是按值传递的区别的实际含义体现在问题“我如何在 Java 中创建交换函数?”及其答案:你不能。像 C 和 C++ 这样的语言能够提供交换函数,因为它们与 Java 不同,允许您通过使用对该变量的引用从任何变量进行赋值——从而允许您更改其值(如果非常量)而无需更改它先前引用的对象的内容。

It could make your head spin to try to think this all the way through, but here goes nothing...

试图从头到尾思考这件事可能会让你头晕目眩,但这里什么也没有......

  • Java class-type variables are always "references" which are effectively pointers.
  • Java pointers are primitive types.
  • Java assignment is alwaysby the value of the underlying primitive (the pointer in this case).
  • Java simply has no mechanism equivalent to C/C++ pass-by-reference that would allow you to indirectly modify a free-standing primitive type, which may be a "pointer" such as this.
  • Java 类类型变量始终是“引用”,它们实际上是指针。
  • Java 指针是原始类型。
  • Java 赋值总是通过底层原语的值(在这种情况下是指针)。
  • Java 根本没有等效于 C/C++ 传递引用的机制,它允许您间接修改独立的原始类型,它可能是一个“指针”,例如this.

Additionally, it is interesting to note that C++ actually has two different syntaxesfor pass-by-reference. One is based on explicit pointers, and was inherited from the C language. The other is based on the C++ reference-typeoperator &. [There is also the C++ smart pointerform of reference management, but that is more akin to Java-like semantics -- where the references themselves are passed by value.]

此外,有趣的是 C++ 实际上有两种不同的按引用传递语法。一种是基于显式指针,并且是从 C 语言继承而来的。另一个基于 C++引用类型operator&。[还有引用管理的 C++智能指针形式,但这更类似于 Java 类语义——引用本身是按值传递的。]

Note: In the above discussion assign-byand pass-byare generally interchangeable terminology. Underlying any assignment, is a conceptual operator functionthat performs the assignmentbased on the right-hand-side object being passedin.

注意:在上面的讨论中,assign-bypass-by通常是可互换的术语。在任何赋值的基础上,是一个概念运算符函数,它根据传入的右侧对象执行赋值



So coming back to the original question: If you could assign to thisin Java, that would imply changing the value of the reference held by this. That is actually equivalent to assigning directly to thisin C++, which is not legal in that language either.

所以回到最初的问题:如果您可以this在 Java 中赋值,那将意味着更改this. 这实际上相当于this在 C++ 中直接赋值,这在该语言中也不合法。

In both Java and C++, thisis effectively a pointer that cannot be modified. Java seemsdifferent because it uses the .operator to dereference the pointer -- which, if you're used to C++ syntax, gives you the impression that it isn't one.

在 Java 和 C++ 中,this实际上是一个无法修改的指针。Java似乎不同,因为它使用.运算符来取消引用指针——如果您习惯了 C++ 语法,这会给您的印象是它不是一个。

You can, of course, write something in Java that is similar to a C++ copy constructor, but unlike with C++, there is no way of getting around the fact that the implementation will need to be supplied in terms of an explicit member-wise initialization. [In C++ you can avoid this, ultimately, only because the compiler will provide a member-wise implementation of the assignment operatorfor you.]

当然,您可以在 Java 中编写类似于 C++复制构造函数的内容,但与 C++ 不同的是,无法避免需要根据显式成员方式初始化来提供实现的事实. [在 C++ 中,您最终可以避免这种情况,只是因为编译器将为您提供赋值运算符的成员实现。]

The Java limitation that you can't copy to thisas a whole is sort-of artificial though. You canachieve exactly the same result by writing it out member-wise, but the language just doesn't have a natural way of specifying such an operation to be performed on a this-- the C++ syntax, (*this)doesn't have an analogue in Java. And, in fact, there is no built-in operation in Java that reassigns the contents of any existing object -- even if it's not referred to as this.[Such an operation is probably more important for stack-based objects such as are common in C++.]

但是,您无法将其this作为一个整体复制到的 Java 限制有点人为。您可以通过按成员方式写出它来获得完全相同的结果,但是该语言没有一种自然的方式来指定要在 a 上执行的此类操作this——C++ 语法,(*this)在 Java 中没有类似物. 而且,事实上,Java 中没有内置操作可以重新分配任何现有对象的内容——即使它没有被称为this. [对于基于堆栈的对象(例如 C++ 中常见的对象),这种操作可能更为重要。]



Regarding the use-case of performing a deep copy: It's complicated in Java.

关于执行深层复制的用例:它在 Java 中很复杂

For C++, a value-type-oriented language. The semantic intention of assignment is generally obvious. If I say a=b, I typically want ato become and independent cloneof b, containing an equal value. C++ does this automatically for assignment, and there are plansto automate the process, also, for the comparison.

对于 C++,一种面向值类型的语言。赋值的语义意图一般是显而易见的。如果我说a=b,我通常希望a成为和独立的克隆b,包含一个相等的价值C++ 为赋值自动执行此操作,并且有计划使该过程自动化,也用于比较。

For Java, and other reference-oriented languages, copying an object, in a generic sense, has ambiguous meaning. Primitives aside, Java doesn't differentiate between value-types and reference-types, so copying an object has to consider every nested class-type member (including those of the parent) and decide, on a case-by-case basis, if that member object should be copied or just referenced. If left to default implementations, there is a very good chance that result would not be what you want.Comparingobjects for equality in Java suffers from the same ambiguities.

对于 Java 和其他面向引用的语言,复制对象在一般意义上具有不明确的含义。撇开原语不谈,Java 不区分值类型和引用类型,因此复制对象必须考虑每个嵌套的类类型成员(包括父类的成员),并根据具体情况决定是否该成员对象应该被复制或只是引用。 如果保留默认实现,结果很可能不是您想要的。在 Java 中比较对象的相等性也存在同样的歧义

Based on all of this, the answer to the underlying question: why can't I copy an object by some simple, automatically generated, operation on this, is that fundamentally, Java doesn't have a clear notion of what it means to copy an object.

基于所有这些,基本问题的答案是为什么我不能通过一些简单的、自动生成的、对 的操作来复制对象this从根本,Java 对复制对象的含义没有明确的概念对象



One last point, to answer the literal question:

最后一点,回答字面问题:

What rationale is there behind the decision not to make thisa variable?

不做this变量的决定背后有什么理由?

It would simply be pointless to do so. The value of thisis just a pointer that has been passed to a function, and if you were able to change the value of this, it could not directly affect whatever object, or reference, was used to invoke that method. After all, Java is pass-by-value.

这样做毫无意义。的值this只是一个已传递给函数的指针,如果您能够更改 的值this,它不会直接影响用于调用该方法的任何对象或引用。毕竟,Java 是按值传递的。

回答by Sibbo

The thisin Java is a part of the language, a key word, not a simple variable. It was made for accessing an object from one of its methods, not another object. Assigning another object to it would cause a mess. If you want to save another objects reference in your object, just create a new variable.

thisJava中是语言,一个关键的词,不是一个简单的变量的一部分。它用于从对象的一个​​方法访问一个对象,而不是另一个对象。将另一个对象分配给它会导致混乱。如果要在对象中保存另一个对象引用,只需创建一个新变量。

The reason is just conceptual. thiswas made for accessing an Object itself, for example to return it in a method. Like I said, it would cause a mess if you would assign another reference to it. Tell me a reason why altering thiswould make sense.

原因只是概念上的。this用于访问对象本身,例如在方法中返回它。就像我说的,如果你给它分配另一个引用,它会造成混乱。告诉我为什么改变this有意义的原因。

回答by user207421

Assigning to *thisin C++ isn't equivalent to assigning thisin Java. Assigning thisis, and it isn't legal in either language.

分配给*this在C ++中并不等同于分配this在Java中。赋值this是,而且在任何一种语言中都不合法。