为什么在Java中向匿名类添加公共字段不起作用?

发布于 2024-11-16 21:59:30 字数 348 浏览 3 评论 0原文

我有一个定义如下的示例类:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

对不⑦ 2024-11-23 21:59:30

因为变量 "fooBar"类型FooBar运行时类型该变量中的 object 是实现 FooBar 的匿名类的对象,它也是 FooBar子类型)...

.. .并且类型 FooBar 没有所述成员。因此,出现编译错误。 (请记住,变量 "fooBar" 可以包含任何符合 FooBar 的对象,甚至那些没有 name 的对象,因此编译器会拒绝以下代码:不是类型安全的。)

编辑:对于一种解决方案,请参阅 irreputable 的答案,它使用 本地类声明来创建一个新的命名类型(替换帖子中的匿名类型)。

Java支持这样做的方法(主要是:Java支持不支持有用的类型推理),尽管以下内容确实有效,即使不是很有用:

(new foobar(){
  public String name = null;
  @Override
  void method1(Foo foo){
    ...
  }
}).name = "fred";

快乐编码。


Scala 和 C# 都支持局部变量所需的类型推断,从而支持匿名类型特化。 (尽管 C# 不支持匿名扩展现有类型)。然而,Java 却没有。

Because the type of the variable "fooBar" is FooBar (the run-time type of the object in said variable is that of the anonymous class implementing FooBar which is also a subtype of FooBar)...

...and the type FooBar does not have said member. Hence, a compile error. (Remember, the variable "fooBar" can contain any object conforming to FooBar, even those without name, 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:

(new foobar(){
  public String name = null;
  @Override
  void method1(Foo foo){
    ...
  }
}).name = "fred";

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.

肤浅与狂妄 2024-11-23 21:59:30

一个本地类就可以了

{
    class MyFooBar extends FooBar{
        String name = null;
        ...
    };

    MyFooBar fooBar = new MyFooBar();

    fooBar.name = "Test";
}

A local class would do

{
    class MyFooBar extends FooBar{
        String name = null;
        ...
    };

    MyFooBar fooBar = new MyFooBar();

    fooBar.name = "Test";
}
蓬勃野心 2024-11-23 21:59:30

您正在创建一个 foobar 类型的对象。编译器只知道为类/接口 foobar 定义的成员。

请记住,java 是静态语言,而不是动态语言。它不会在运行时检查对象是否存在,而是在编译时根据类型声明进行检查。

You're creating an object of type foobar. The compiler only knows about the members defined for the class/interface foobar.

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.

木有鱼丸 2024-11-23 21:59:30

试试这个。

@SafeVarargs
public static <T> void runWithObject(T object, Consumer<T>... progs) {
    for (Consumer<T> prog : progs)
        prog.accept(object);
}

runWithObject(
    new FooBar() {
        String name = null;
        @Override
        void method1(Foo foo) {
            System.out.println("name=" + name);
        }
    },
    object -> object.name = "Test",
    object -> object.method1(new Foo())
);

结果:

name=Test

或者您可以在 Java 10 或更高版本中像这样使用 var

var fooBar = new FooBar() {
    public String name = null;

    @Override
    void method1(Foo foo) {
        System.out.println("name=" + name);
    }
};
fooBar.name = "Test";
fooBar.method1(new Foo());

Try this.

@SafeVarargs
public static <T> void runWithObject(T object, Consumer<T>... progs) {
    for (Consumer<T> prog : progs)
        prog.accept(object);
}

and

runWithObject(
    new FooBar() {
        String name = null;
        @Override
        void method1(Foo foo) {
            System.out.println("name=" + name);
        }
    },
    object -> object.name = "Test",
    object -> object.method1(new Foo())
);

result:

name=Test

Or you can use var like this in Java 10 or later.

var fooBar = new FooBar() {
    public String name = null;

    @Override
    void method1(Foo foo) {
        System.out.println("name=" + name);
    }
};
fooBar.name = "Test";
fooBar.method1(new Foo());
丘比特射中我 2024-11-23 21:59:30

fooBar 是对foobar 类型的对象的引用,并且此类对象没有字段name。就这么简单。由于它是匿名类型,因此引用该字段的唯一方法是通过其 this 引用。

fooBar is a reference to an object of type foobar, and such objects do not have a field name. Simple as that. And since it’s an anonymous type, the only way to reference that field is through its this reference.

べ映画 2024-11-23 21:59:30

fooBar 类型是 foobar ,它没有这样的变量,因此代码无法编译。您可以通过反射来访问它。

fooBar type is foobar which has not such variable and therefore the code can not be compiled. You can access it by reflection.

心奴独伤 2024-11-23 21:59:30

正如大家所说,这是由于静态类型和 FooBar 类不包含 name 造成的。所以这是行不通的。

我想指出 Anonymous 类的建议用法。

匿名类(或者接近闭包,可能是 lambda。类似但不相同)来自函数式编程范式,其中状态应该是不可变的。

话虽这么说,为什么你应该使用这样的类呢?当你需要完成一件快速而简短的事情时,这不一定是在一个完整的课程中进行的。示例:

MyTask() //This is a method
{
    new Thread(new Runnable() { //Anonymous class
        public void run()
        {}
    }).start();
}

理解仅将实现封装到函数/类中非常重要。

匿名类(或封闭函数)中定义的变量的作用域只能在匿名类内部使用,不能从其他程序代码访问。

因此,您不应该(并且无论如何不能)设置 fooBar.name = "Test";

As everyone said, this is due to static typing and FooBar class does not contain name. 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:

MyTask() //This is a method
{
    new Thread(new Runnable() { //Anonymous class
        public void run()
        {}
    }).start();
}

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";

南街女流氓 2024-11-23 21:59:30

你也可以这样做

Boolean var= new anonymousClass(){
    private String myVar; //String for example
    @Overriden public Boolean method(int i){
          //use myVar and i
    }
    public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);

You can also do it like this

Boolean var= new anonymousClass(){
    private String myVar; //String for example
    @Overriden public Boolean method(int i){
          //use myVar and i
    }
    public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文