【问题标题】:How try...finally works internally尝试...最终如何在内部工作
【发布时间】:2024-01-20 17:48:01
【问题描述】:

目前我正在优化代码,我正在使用 try.. finally 块来尊重我的对象。

但是我很困惑,当我在 finally 块中创建对对象的空引用时如何管理返回对象。 ??

在 try 块中返回对象时,它会在编译期间创建预编译语句吗?还是在返回语句时在堆中创建新的引用?还是只返回一个对象的当前引用?

以下是我的研究代码。

public class testingFinally{
    public static String getMessage(){
        String str = "";
        try{
            str = "Hello world";
            System.out.println("Inside Try Block");
            System.out.println("Hash code of str : "+str.hashCode());
            return str;
        }
        finally {
            System.out.println("in finally block before");
            str = null;
            System.out.println("in finally block after");
        }
    }

    public static void main(String a[]){
        String message = getMessage();
        System.out.println("Message : "+message);
        System.out.println("Hash code of message : "+message.hashCode());
    }
}

输出是:

尝试块内部
str 的哈希码:-832992604
终于在 bolck 之前
在 finally 块之后
消息:你好世界
消息哈希码:-832992604

当我看到返回对象和调用对象都具有相同的哈希码时,我感到非常惊讶。 所以我对对象引用感到困惑。

请帮助我清除这个基础。

【问题讨论】:

  • 哈希码是根据内容创建的,而不是参考地址或其他东西。那么有什么困惑呢?
  • 感谢您的及时回复。我的困惑是我在 finally 块中使我的对象为空。那么返回对象在哪里以及如何??
  • JLS-14.20.2. Execution of try-finally and try-catch-finally 可能有助于消除您对finally 的困惑。需要注意的是,Java String 是不可变的。因此,您已经返回了该值的副本,您无法在 finally 中修改返回的实例。如果您返回 StringBuilder 并在 finally 中调用 setLength(0),那么您将在调用者中获得零长度 StringBuilder
  • @prattpratt - 要返回的内容已经在 try 块中决定了。因此,除非您在 finally 块中执行 return str(在这种情况下,要返回的当前值将从堆栈顶部弹出并替换为更新的值,即 null),返回的值将是"Hello World".
  • @TheLostMind - 感谢您的帮助。它将帮助我了解详细的基础知识。

标签: java try-catch try-catch-finally


【解决方案1】:

该方法并不完全返回一个对象。它返回对对象的引用。该对象 引用指的是在方法调用的内部和外部保持不变。因为是同一个对象, 哈希码将是相同的。

strreturn str 时的值是对字符串“Hello World”的引用。回报 语句读取str的值并保存为方法的返回值。

然后运行 ​​finally 块,它有机会通过包含自己的来更改返回值 返回声明。在 finally 块中更改 str 的值不会更改已设置 返回值,只有另一个返回语句会。

由于将str 设置为null 无效,因此您可以删除这样的语句。无论如何,只要方法返回,它就会超出范围,因此它对垃圾收集没有帮助。

【讨论】:

  • 它对我真的很有帮助。非常感谢。我怀疑将对象设为 null 无助于垃圾收集???。方法中的此类对象在堆空间中没有更多引用??
  • @prattpratt 当方法返回时,里面的变量就不存在了,所以它们的值不再重要。它们不会算作对对象的引用,因此只要不存在其他引用,就可以收集它们所引用的对象。
  • @prattpratt - 将有一个返回地址槽(堆栈顶部),必须在其上推送要返回的引用。因此,当遇到 try 的返回时,“Hello World”的引用被推送到那里。因此,无论接下来发生什么(重新分配对 null 的引用),都不会更改 returned 值。如果您在finally 中调用return str,则str 的值将从堆栈中弹出,并在其位置更新null。所以null会被返回。
  • 非常感谢我的答案现在对我来说很清楚了。再次非常感谢。
  • 您对 hashCode() 的解释具有误导性。 HashCode 基于字符串的值,而不是对象引用。两个具有相同值的单独字符串将返回相同的 hashCode。
【解决方案2】:

基于JLS 14.20.2 Execution of try-catch-finally

If execution of the try block completes normally, then the finally block is executed, and then there is a choice:    
    If the finally block completes normally, then the try statement completes normally.
    If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S.

希望得到帮助:)

【讨论】:

  • @Downvoter 我的回答有什么问题吗? :)
  • 不是 downVoter,但这并不能回答 OP 的问题。
  • @TheLostMind 基于他尝试的代码和他在帖子下的评论。 Thanks for your prompt reply. my confusion is i am making my object null in my finally block. so where return object is reside and how??我想我没有误解他:)
  • 在这种情况下,finallytry正常完成。 OP 在问 为什么我没有得到 null
【解决方案3】:

Hashcode() 不是为了显示参考。相反,哈希码用于检查 2 个字符串是否彼此相等。请参考http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#hashCode()

返回此字符串的哈希码。 String 对象的哈希码计算为 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

由于两个String的值相同,hashcode当然是相同的。

【讨论】:

  • 即便如此,提问者仍希望 str 为空,因此应该抛出 NullPointerException
  • 否 - Java 传递值而不是引用。最后返回的值和最终改变的值有不同的引用。
  • 是的,这就是答案。那是OP不明白的。不是如何计算哈希码。
最近更新 更多