我从编译器得到的错误是“赋值的左侧必须是变量”。我的用例是深度复制,但并不真正相关。
在C ++中,可以分配给*this
。
问题不在于如何规避this
的作业。这很简单,但是决定不让this
成为变量的背后有什么理由。
原因是技术性的还是概念性的?
我的猜测到目前为止 - 在随机方法中重建Object的可能性容易出错(概念性),但技术上可行。
编辑请限制“因为java规格如此说”的变体。我想知道决定的原因
答案 0 :(得分:12)
在C ++中,可以分配到
*this
是的,但你不能在C ++中做this = something
,我实际上认为这与你在Java方面所要求的内容更接近。
[...]决定不将
this
变为变量的背后有什么理由。
我会说清晰度/可读性。
this
被选为保留字,可能因为它没有作为方法的显式参数传递。将它用作普通参数并能够为其重新赋值,会严重损害可读性。
事实上,很多人认为你根本不应该改变论证变量,原因就在于此。
技术或概念上的原因是什么?
我认为主要是概念性的。但是会出现一些技术怪癖。如果您可以将值重新分配给this
,则可以完全隐藏局部变量后面的实例变量。
我的猜测到目前为止 - 在随机方法中重建对象的可能性容易出错(概念性),但技术上可行。
我不确定我是否完全理解这一陈述,但是,容易出错可能是决定将其作为关键词而不是变量的主要原因。
答案 1 :(得分:4)
因为 this
是final
,
this
是关键字,而不是变量。并且您无法为关键字分配内容。现在一分钟考虑 if 它是设计规范中的参考变量..并参见下面的例子
并且它包含对象调用方法的隐式引用。它仅用于参考目的,现在考虑为this
分配一些东西,这样会不会破坏一切?
示例强>
考虑来自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);
}
答案 2 :(得分:4)
原因是技术性的还是概念性的?
IMO,概念性。
this
关键字是“对当前正在执行其方法的对象的引用”的简写。你不能改变那个对象是什么。它在Java执行模型中毫无意义。
由于this
改变没有意义,因此将其变为变量是没有意义的。
(请注意,在C ++中,您要分配给*this
,而不是this
。而在Java中,没有*
运算符,也没有真正的等价运算符。)
如果您认为可能更改了飞行途中方法的目标对象,那么这里有一些反问题。
这样做有什么用?这个(假设的)语言特征会帮助你解决哪些问题......这些问题无法以更容易理解的方式解决?
您如何处理互斥锁?例如,如果您在同步方法的中间分配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) {
}
}
当然,您可以将语义归于此,但是:
如果你认真地回答这些问题,我希望你能得出结论,实施这个问题本来是个坏主意。 (但如果你做有令人满意的答案,我建议你把它们写下来并将它们作为你自己的问题答案发布!)
但实际上,我怀疑Java设计师甚至不仅仅考虑了这个想法。 (这是正确的,IMO)
C ++的*this = ...
形式实际上只是当前对象属性赋值序列的简写。我们已经可以在Java中用一系列正常的赋值来做到这一点。当然不需要新的语法来支持这一点。 (一个类多久一次从另一个类的状态重新初始化?)
我注意到你评论过:
我想知道
this = xy;
的语义应该是什么。你认为应该怎么做? - JimmyB 11年11月2日12:18如果
xy
属于正确类型,则此引用将设置为xy
,将“原始”对象设为gc-eligible - kostja Nov 2' 11点12:24
那不行。
调用方法时,this
的值(有效地)通过值传递给方法。被调用者不知道this
引用的来源。
即使它确实如此,那只是举行参考的地方。除非在所有地方分配null
,否则该对象无法进行垃圾收集。
忽略这在技术上是不可能的事实,我不认为你的想法会有用或有助于编写可读/可维护的代码。考虑一下:
public class MyClass {
public void kill(MyClass other) {
this = other;
}
}
MyClass mine = new MyClass();
....
mine.kill(new MyClass());
// 'mine' is now null!
你为什么要那样做?假设方法名称是无关紧要而不是kill
,您是否期望该方法能够消除mine
的值?
我没有。事实上,我认为这将是一种错误:无用和危险。
即使没有这些令人讨厌的“使它无法访问”的语义,我实际上也没有看到任何用于修改this
的好用例。
答案 3 :(得分:3)
this
甚至不是变量。它是一个关键字,如Java Language Specification中所定义:
当用作主表达式时,关键字this表示一个值,该值是对调用实例方法的对象(第15.12节)或对正在构造的对象的引用
所以,这是不可能的,因为无法为while
分配值。
答案 4 :(得分:1)
Java中的this
是语言的一部分,是一个关键词,而不是一个简单的变量。它用于从其中一个方法访问对象,而不是另一个对象。为它分配另一个对象会导致混乱。如果要在对象中保存另一个对象引用,只需创建一个新变量。
原因只是概念性的。 this
用于访问Object本身,例如在方法中返回它。就像我说的那样,如果你要为它分配另一个引用,它会导致混乱。告诉我为什么改变this
会有意义。
答案 5 :(得分:1)
在C ++中分配给(*this)
执行复制操作 - 将对象视为值类型。
Java没有对类使用值类型的概念。对象分配始终是 by-reference 。
要复制对象,就好像它是值类型:How do I copy an object in Java?
用于Java的术语令人困惑:Is Java “pass-by-reference” or “pass-by-value”
答案: Java按值传递引用。(来自here)
换句话说,因为Java从不将非基元视为值类型,所以每个类型变量都是一个引用(实际上是一个指针)。
所以,当我说'"对象分配总是按引用"时,在短语中可能更准确,因为"对象分配始终是的值参考"。
Java 总是所传达的区别的实际含义体现在问题" How do I make my swap function in java?"及其答案:{ {3}}。诸如C和C ++之类的语言能够提供交换功能,因为它们与Java不同,允许您通过使用对该变量的引用从任何变量进行分配 - 从而允许您更改其值(如果non-const)而不改变它先前引用的对象的内容。
它可能让你的头脑旋转,试图一直想到这一点,但这里什么都没有......
- Java类类型变量总是"引用"这是有效的指针。
- Java指针是原始类型。
- Java赋值总是由底层基元的值(在这种情况下为指针)。
- Java简单地没有相当于C / C ++传递引用的机制,它允许你间接修改一个独立的基本类型,它可能是一个"指针"例如
this
。
另外,值得注意的是,C ++实际上有两种不同的语法,用于传递引用。一个基于显式指针,并且继承自C语言。另一个基于C ++ You can't。 [还有C ++ 智能指针形式的参考管理,但这更类似于类似Java的语义 - 其中引用本身是按值传递的。]
注意:在上面的讨论中, assign-by 和 pass-by 通常是可互换的术语。任何赋值的基础是概念运算符函数,它根据传递的右侧对象执行赋值。
所以回到最初的问题:如果您可以在Java中分配给this
,那么这意味着更改this
所持有的引用的值。这实际上相当于在C ++中直接分配给this
,这在该语言中也是不合法的。
在Java和C ++中,this
实际上是一个无法修改的指针。 Java 似乎不同,因为它使用.
运算符取消引用指针 - 如果您习惯使用C ++语法,则会给您留下它不是的印象之一。
你可以,当然,用Java编写类似于C ++ reference-type operator &
的东西,但与C ++不同,没有办法解决实现将会需要根据明确的成员初始化提供。 [在C ++中,你可以避免这种情况,最终只是因为编译器会为你提供赋值运算符的成员实现。]
虽然您可以将this
整体复制到this
的Java限制是有点人为的。你可以通过成员写出来获得完全相同的结果,但是语言没有一种自然的方式来指定在(*this)
上执行这样的操作 - C ++语法,this
在Java中没有模拟。
事实上,Java中没有内置操作可以重新分配任何现有对象的内容 - 即使它不被称为a=b
。 [这样对于基于堆栈的对象,操作可能更重要,例如在C ++中很常见。]
关于执行深层复制的用例:copy constructor。
对于C ++,一种面向价值类型的语言。赋值的语义意图通常是显而易见的。如果我说a
,我通常希望b
成为this
的独立It's complicated in Java,包含相等的值。 C ++会自动执行此操作以进行分配,还有clone可自动执行此过程,也可用于比较。
对于Java和其他面向参考的语言,在一般意义上复制对象具有含糊不清的含义。除了基元之外, Java并不区分值类型和引用类型,因此复制对象必须考虑每个嵌套的类类型成员(包括父类的成员)并决定,如果要复制或仅引用该成员对象,则视具体情况而定。 如果留给默认实施,很有可能结果不是你想要的。 在Java中比较对象是否存在等同于plans。
基于所有这些,基本问题的答案:为什么我无法通过this
上的一些简单的,自动生成的操作来复制对象,就是,从根本上说,Java并不清楚复制对象意味着什么。
最后一点,回答字面问题:
决定不将
this
变为变量的原因背后有什么理由?
这样做毫无意义。 this
的值只是一个已传递给函数的指针,如果您能够更改{{1}}的值,则它无法直接影响用于的任何对象或引用调用该方法。毕竟,Java是按值传递的。
答案 6 :(得分:0)
在C ++中分配给*this
并不等同于在Java中分配this
。分配this
是,并且在任何一种语言中都不合法。