为什么在Java中向匿名类添加公共字段不起作用?
我有一个定义如下的示例类:
public class FooBar {
void method1(Foo foo){ // Should be overwritten
...
}
}
后来,当我尝试这样做时:
FooBar fooBar = new FooBar(){
public String name = null;
@Override
void method1(Foo foo){
...
}
};
fooBar.name = "Test";
我收到一条错误消息,指出名称字段不存在。为什么?
I have an example class defined like below:
public class FooBar {
void method1(Foo foo){ // Should be overwritten
...
}
}
Later, when I try this:
FooBar fooBar = new FooBar(){
public String name = null;
@Override
void method1(Foo foo){
...
}
};
fooBar.name = "Test";
I get an error saying that the name field does not exist. Why?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
因为变量
"fooBar"
的类型是FooBar
(运行时类型该变量中的 object 是实现FooBar
的匿名类的对象,它也是FooBar
的子类型)..... .并且类型
FooBar
没有所述成员。因此,出现编译错误。 (请记住,变量"fooBar"
可以包含任何符合FooBar
的对象,甚至那些没有name
的对象,因此编译器会拒绝以下代码:不是类型安全的。)编辑:对于一种解决方案,请参阅 irreputable 的答案,它使用 本地类声明来创建一个新的命名类型(替换帖子中的匿名类型)。
Java不支持这样做的方法(主要是:Java支持不支持有用的类型推理),尽管以下内容确实有效,即使不是很有用:
快乐编码。
Scala 和 C# 都支持局部变量所需的类型推断,从而支持匿名类型特化。 (尽管 C# 不支持匿名扩展现有类型)。然而,Java 却没有。
Because the type of the variable
"fooBar"
isFooBar
(the run-time type of the object in said variable is that of the anonymous class implementingFooBar
which is also a subtype ofFooBar
)......and the type
FooBar
does not have said member. Hence, a compile error. (Remember, the variable"fooBar"
can contain any object conforming toFooBar
, even those withoutname
, and thus the compiler rejects the code which is not type-safe.)Edit: For one solution, see irreputable's answer which uses a Local Class Declaration to create a new named type (to replace the anonymous type in the post).
Java does not support a way to do this (mainly: Java does not support useful type inference), although the following does work, even if not very useful:
Happy coding.
Both Scala and C# support the required type inference, and thus anonymous type specializations, of local variables. (Although C# does not support extending existing types anonymously). Java, however, does not.
一个本地类就可以了
A local class would do
您正在创建一个
foobar
类型的对象。编译器只知道为类/接口foobar
定义的成员。请记住,java 是静态语言,而不是动态语言。它不会在运行时检查对象是否存在,而是在编译时根据类型声明进行检查。
You're creating an object of type
foobar
. The compiler only knows about the members defined for the class/interfacefoobar
.Remember, java is a static language, not dynamic. It doesn't check the object at runtime for what exists, it checks at compile time based on the type declaration.
试试这个。
和
结果:
或者您可以在 Java 10 或更高版本中像这样使用
var
。Try this.
and
result:
Or you can use
var
like this in Java 10 or later.fooBar
是对foobar
类型的对象的引用,并且此类对象没有字段name
。就这么简单。由于它是匿名类型,因此引用该字段的唯一方法是通过其this
引用。fooBar
is a reference to an object of typefoobar
, and such objects do not have a fieldname
. Simple as that. And since it’s an anonymous type, the only way to reference that field is through itsthis
reference.fooBar
类型是foobar
,它没有这样的变量,因此代码无法编译。您可以通过反射来访问它。fooBar
type isfoobar
which has not such variable and therefore the code can not be compiled. You can access it by reflection.正如大家所说,这是由于静态类型和
FooBar
类不包含name
造成的。所以这是行不通的。我想指出 Anonymous 类的建议用法。
匿名类(或者接近闭包,可能是 lambda。类似但不相同)来自函数式编程范式,其中状态应该是不可变的。
话虽这么说,为什么你应该使用这样的类呢?当你需要完成一件快速而简短的事情时,这不一定是在一个完整的课程中进行的。示例:
理解仅将实现封装到函数/类中非常重要。
匿名类(或封闭函数)中定义的变量的作用域只能在匿名类内部使用,不能从其他程序代码访问。
因此,您不应该(并且无论如何不能)设置
fooBar.name = "Test";
As everyone said, this is due to static typing and
FooBar
class does not containname
. So it won't work.I wanted to point out the suggested usage of Anonymous class.
Anonymous class (or close to Closures, maybe lambdas. Similar but not same) come from functional programming paradigm, where the states should be immutable.
That being said, why should you user such classes? When you need a quick and short thing to be done which should not necessarily go in a complete class. Example:
The understanding of enclosing your implementation only to a function/class is important.
The
scope of the variables defined in the Anonymous class (or closed-over function) should only be used inside the Anonymous class
, it cannot be accessed from other program code.Therefore, you should not (and anyway cannot) set
fooBar.name = "Test";
你也可以这样做
You can also do it like this