首页 > 解决方案 > 为什么从线程调用类函数在 Java 中有效?

问题描述

所以我得到了这个奇怪的场景,它工作得很好,但对它为什么工作没有任何意义。根据我在 C++ 方面的经验,我非常确定这根本行不通,并且会在编译期间引发错误。

public class Practice {

    private void testFunction() {
        System.out.println("working fine");
        System.out.println("testFunc: " + this);
    }

    public void start() {
        System.out.println("start: " + this);

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("run: " + this);
                testFunction();
            }
        }).start();
    }
}

// Inside main
Practice practice = new Practice();
practice.start()

输出

start: com.company.Practice@5e2de80c
run: com.company.Practice$1@6720b744
working fine
testFunc: com.company.Practice@5e2de80c

为什么!?为什么这行得通?我如何testFunction()从 Runnable 调用?我不应该创建一个新实例然后调用该函数Practice p = new Practice(); p.testFunction()吗?Java如何知道它testFunction()Practice类的一部分而不是Runnable

而且,为什么thisin的值与testFunction()相同start()?不应该是一样的run()吗?

标签: javamultithreadingobjectthread-safetyinstance

解决方案


您在这里有一个“内部班级”。

内部类的实例(Runnable 的匿名子类)将包含对它们创建的外部类的引用(这里是 Practice 的实例),并且可以在这些外部实例上调用方法。

testFunction();被编译成类似的东西this.$myOuterInstance.testFunction();

Java 怎么知道 testFunction() 是 Practice 类的一部分而不是 Runnable?

编译器通过首先查看内部类然后转到外部范围来解决这个问题,外部范围不仅包括包含类,而且还包括您在该start方法中可能拥有的任何有效的最终局部变量。

这也类似于变量和字段的解析方式(当您有名称冲突时使用一些隐藏规则)。

还有,这个 in 的值怎么和testFunction()一样start()?不应该是一样的run()吗?

No.在(as is )testFunction的实例上调用。Practicestart

run在 Runnable 的实例上调用Practice$1


推荐阅读