【问题标题】:How reference type Identified at run time of Object?Object 运行时如何识别引用类型?
【发布时间】:2019-02-19 16:15:47
【问题描述】:

我对 java 引用类型的创建有一个疑问。

假设我下面有一节课

public class DefaultRepositorySelector
  implements RepositorySelector
{
  final LoggerRepository repository;

  public DefaultRepositorySelector(LoggerRepository repository)
  {
    this.repository = repository;
  }

  public LoggerRepository getLoggerRepository()
  {
    return this.repository;
  }
}

并且在另一个类的某处调用类的构造函数DefaultRepositorySelector,如下所示。

repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());

如您所见,正在初始化一个类new DefaultRepositorySelector(new NOPLoggerRepository()),构造函数接受NOPLoggerRepository 实例,该实例具有LoggerRepository 接口的实现。

我的疑问是,我们在构造函数中直接将new NOPLoggerRepository() 作为参数传递,这是一个实例而不是引用类型,但构造函数持有引用类型LoggerRepository

我无法理解这里的流程,因为根据流程,当我们创建一个实例时,我们传递新对象而不是对该对象的引用,但在类的定义中,构造函数接受该对象的引用类型。

所以在运行时,当我们直接传递一个实例但方法或构造函数接受该实例的引用类型时,它是如何处理的?谁创建了 OR Instance 的第一个引用类型?我认为引用类型,但不确定它是如何在幕后工作的......!

我的问题听起来很傻,但请帮助理解这一点..!

谢谢

【问题讨论】:

    标签: java


    【解决方案1】:

    NOPLoggerRepository 的对象被创建并传递给方法。 这是有效的,因为NOPLoggerRepository 实现了LoggerRepository

    关于对象何时不再可访问(并且可用于垃圾收集)的规则意味着它在被传入之前不会被收集(以防您担心这种奇怪现象)。

    当构造函数完成时,DefaultRespositorySelector 持有对传入对象的引用。但是我们知道(在这种情况下)它的基础类是 NOPLoggerRepository

    一切都好。编译器知道底层类型何时可能不是引用的显式类型,并通过各种机制确保正确的行为。 (对一些实现定义的一大堆东西进行修饰)。

    在 java 中,您永远不会“真正”传递对象,而类变量也不包含“对象”。 它们始终是对象的引用。

    在随意的谈话中,我们都经常说“我将 NOPLoggerRespository 传递给构造函数”,但我们的真正意思是我将 对 NOPLoggerRespository 的引用传递给构造函数。没关系,因为只要我们都明白它是一个很好的速记,它始终是一个参考。

    【讨论】:

      【解决方案2】:

      我不太确定我是否正确理解了您的问题。

      您将创建名称为repositorySelector、类型为DefaultRepositorySelector 的对象。在调用构造函数时,您需要有一个 LoggerRepository 的引用,它是对现有对象的引用(或 null,如果您传递 null)。

      因此,要获得引用,您需要传递 new NOPLoggerRepository()。

      括号中的表达式首先被求值,所以在调用 DefaultRepositorySelector 的构造函数之前,NOPLoggerRepository 将被创建为一个匿名对象。也就是说,对象被创建并且没有给定名称。但是我们有对它的引用,这意味着我们知道它在堆上的位置。

      由于 NOPLoggerRepository 是 LoggerRepository 类型,DefaultRepositorySelector 的构造函数接受引用 - 位于堆上的匿名对象的位置以及名为 repositorySelector 的对象将被创建。

      长话短说,在调用方法(或构造函数)之前,首先评估参数(对象创建、数学计算、调用和评估的其他方法等),然后可以使用评估的参数调用实际方法。

      【讨论】:

        【解决方案3】:

        总体思路

        Java 是按值传递的

        in objects 与 premitive types 有很大不同。

        在您的代码中:

        repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
        

        (new NOPLoggerRepository() 被认为是被调用的代码范围的忽略实例。 这里的事情是当你调用 new DefaultRepositorySelector 它一开始什么也没做,因为首先调用参数,所以在有序序列中

        1. new NOPLoggerRepository() 被调用并在堆上创建了一个没有引用的新实例。
        2. new DefaultRepositorySelector 被调用并请求它的 RepositorySelector 实例,该实例在示例中没有任何引用。
        3. JVM 在您的构造函数中为该对象创建唯一引用,然后在您的类 a 中创建另一个(当您的构造函数弹出时)。

        简而言之。它仍然是参考,但只是在幕后。

        【讨论】:

          【解决方案4】:

          您所指的通常称为dependency injection. 首先,被注入的对象被实例化,然后是依赖对象。 SO answer here.

          【讨论】:

          • 不。这里没有 DI。该对象作为参数传递给构造函数,因此在之前创建!
          • @GyroGearless 我非常不同意,这是 DI 的教科书示例。同样,您可以阅读我链接的帖子,或解释为什么这不是依赖注入。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-21
          • 1970-01-01
          • 2019-07-20
          相关资源
          最近更新 更多