微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用新运算符 用例

如何解决使用新运算符 用例

使用 new 运算符创建了多少字符串。

假设我正在使用 new 运算符创建一个字符串。

String str = new String("Cat")

它是否会创建 2 个字符串,一个在堆中,另一个在字符串池中?

如果它也在 string poll 中创建字符串,那么字符串 intern 方法的目的是什么?

解决方法

有多少对象?

它是否会创建 2 个字符串,一个在堆中,另一个在字符串池中?

当您编写 "Cat" 时,您最终会用 Cat 填充池,并且 "Cat" 调用从池中加载此对象。这通常在编译时就已经发生了。然后 new String(...) 将创建一个新的字符串对象,完全忽略池。

所以这个片段导致了两个对象的创建。为了消除您的困惑,请考虑以下示例:

String first = "Cat";
String second = "Cat";
String third = "Cat";
String fourth = new String("Cat");

这里也创建了两个对象。所有 "Cat" 调用都会从池中加载字符串,因此 first == second == thirdfourth 将是它自己的对象,因为它使用了 new,这总是导致创建一个新对象,绕过任何类型的缓存机制。

对象是在堆上还是在栈上创建并没有真正定义。内存管理完全取决于 JVM。


字符串池详细信息

对于大多数 Java 实现,字符串池已在编译期间创建和填充。当您编写 "Cat" 时,编译器会将表示 Cat 的字符串对象放入此池中,并且代码中的 "Cat" 将通过从池中加载此对象来替换。当您反汇编编译的程序时,您可以很容易地看到这一点。例如源代码:

public class Test {
    public static void main(String[] args) {
        String foo = "Hello World";
    }
}

反汇编(javap -v):

Classfile /C:/Users/Zabuza/Desktop/Test.class
  Last modified 30.03.2021; size 277 bytes
  SHA-256 checksum 83de8a7326af14fc95fb499af090f9b3377c56f79f2e78b34e447d66b645a285
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 59
  flags: (0x0021) ACC_PUBLIC,ACC_SUPER
  this_class: #9                          // Test
  super_class: #2                         // java/lang/Object
  interfaces: 0,fields: 0,methods: 2,attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = String             #8             // Hello World
   #8 = Utf8               Hello World
   #9 = Class              #10            // Test
  #10 = Utf8               Test
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               main
  #14 = Utf8               ([Ljava/lang/String;)V
  #15 = Utf8               SourceFile
  #16 = Utf8               Test.java
{
  public Test();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1,locals=1,args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC,ACC_STATIC
    Code:
      stack=1,locals=2,args_size=1
         0: ldc           #7                  // String Hello World
         2: astore_1
         3: return
      LineNumberTable:
        line 3: 0
        line 4: 3
}
SourceFile: "Test.java"

如你所见,有

#7 = String             #8             // Hello World
#8 = Utf8               Hello World

并且方法中的部分被替换为

0: ldc           #7

从字符串池中加载 Hello World


字符串实习

字符串实习生方法的目的是什么?

好吧,它使您可以根据池中的版本交换字符串。并用您的字符串填充池,以防它之前不存在。例如:

String first = "hello"; // from pool
String second = new String("hello"); // new object
String third = second.intern(); // from pool,same as first

System.out.println(first == second); // false
System.out.println(first == third); // true

用例

不过,我还没有看到这个功能的真实世界应用程序。

但是,我可以想到一个用例,您可以在应用程序中动态创建长字符串,并且您知道它们稍后会再次出现。然后,您可以将字符串放入池中,以便在稍后再次出现时减少内存占用。

假设您从 HTTP 响应中收到一些长字符串,并且您知道这些响应在大多数情况下完全相同,并且您还想将它们收集在 List 中:

private List<String> responses = new ArrayList<>();

...

public void receiveResponse(String response) {
    ...
    responses.add(response);
}

如果没有实习,您最终会在您的记忆中保留每个字符串实例,包括重复项。但是,如果您实习,则内存中不会有重复的字符串对象:

public void receiveResponse(String response) {
    ...
    String responseFromPool = response.intern();
    responses.add(responseFromPool);
}

当然,这有点做作,因为您也可以在这里使用 Set 代替。

,

<asp:Panel ID="pnlOrders" runat="server"> <asp:Image ID="LiveOrders" alt="Live Gif" runat="server" class="extrasButton" ImageUrl="~/files/images/liveOrders.gif" /> <asp:SqlDataSource ID="DSOrders" runat="server" ConnectionString="<%$ ConnectionStrings:DBConnectionString %>" SelectCommand="SELECT TOP (100) PERCENT tblOrders.OrderID,tblOrders.stallmessage,tblOrders.price,tblAccounts.city,tblAccounts.postcode,tblOrders.phoneNo,tblOrders.tblNo,tblOrders.info,tblOrders.orderDate,tblOrders.orderStatus,tblOrders.type,tblOrders.timeFor,tblOrders.paid,tblOrders.tblNo FROM tblOrders INNER JOIN tblAccounts ON tblOrders.accountID = tblAccounts.AccountID WHERE tblOrders.orderStatus='Completed' ORDER BY tblOrders.timeFor ASC"> </asp:SqlDataSource> <asp:GridView ID="gdvOrders" width="100%" runat="server" style="font-size:1.5em" ShowHeaderWhenEmpty="True" EmptyDataText="No orders" AllowPaging="True" AutoGenerateColumns="False" CssClass="mGrid" DataKeyNames="orderID" DataSourceID="DSOrders" PageSize="20" AllowSorting="True"> <AlternatingRowStyle CssClass="alt" /> <Columns> <asp:TemplateField HeaderText="Order"> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("stallMessage") %>' /> </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="price" HeaderText="Price" /> <asp:BoundField DataField="phoneNo" HeaderText="Phone No" /> <asp:TemplateField HeaderText="Address/Table No."> <ItemTemplate> <asp:Label ID="Label2" runat="server" Text='<%# Eval("tblNo") %>' /> </ItemTemplate> </asp:TemplateField> <asp:TemplateField ItemStyle-ForeColor="Red" HeaderText="Note"> <ItemTemplate> <asp:HyperLink ID="hypNote" style="Font-Size:20px; color:Red;" runat="server" NavigateUrl='<%# "~/editNote.aspx?note=" & Eval("info").ToString & "&orderID=" & Eval("orderID").ToString %>' ><%# Eval("info") %></asp:HyperLink> </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="type" HeaderText="Type" /> <asp:BoundField DataField="orderDate" DataFormatString="{0: H:mm:ss}" HeaderText="Order Time" SortExpression="orderDate" /> <asp:BoundField DataField="timeFor" DataFormatString="{0: H:mm:ss}" HeaderText="Time For" SortExpression="timeFor" /> <asp:BoundField DataField="paid" HeaderText="Paid" /> <asp:TemplateField ShowHeader="True"> <ItemTemplate> <asp:ImageButton visible="true" ID="lnkSent" runat="server" CausesValidation="False" onclientclick="return confirm('Mark As Sent?');" ImageUrl="~/files/images/icons/sendIcon.png" onclick="lnkSent_Click"></asp:ImageButton> <asp:HiddenField ID="hidnOrderID" runat="server" Value='<%# Eval("orderID") %>' /> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> </asp:Panel> Protected Sub gdvOrders_RowDataBound(ByVal sender As Object,ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gdvOrders.RowDataBound For Each r As GridViewRow in gdvOrders.Rows If r.RowType = DataControlRowType.DataRow Then Dim hypNote As Hyperlink hypNote = r.Cells(4).FindControl("hypNote") If hypNote.text = "" Then hypNote.text = "Add Note" End If End If Next r End Sub 运算符只创建一个 new 实例。

在某个时间点创建了第二个 String 实例,以表示传递给 String 构造函数的字符串文字参数。但是我们不能肯定地说它是在我们执行该语句时创建的。 (它可能已经被创建。)

我们可以肯定地说:

  1. 在调用 String(String) 运算符之前创建表示文字的对象。
  2. 在应用程序的生命周期内创建一次1

有趣的是,我们不能绝对肯定地说涉及“字符串池”,或者在任何时候都使用了 new。 Java 15 JLS 在 section 3.10.5 中说明了这一点:

“此外,字符串字面量始终指代 String 类的同一个实例。这是因为字符串字面量 - 或者更一般地说,作为常量表达式(第 15.29 节)的值的字符串 - 是“内嵌的”以便共享唯一实例,就好像通过执行方法 String.intern(第 12.5 节)一样。”

好像”的用语表明运行时系统必须出现以特定方式运行......但它不需要实际上 以这种方式实现。如果有一个可行的替代方法来在字符串文字上调用 String.intern 使 String.intern 对象具有正确的唯一性属性,那么这也是一个可以接受的实现。根据 JLS!

(实际上,所有 Hotspot JVMdo 使用字符串池,do 使用 String。但这是一个“实现细节”。)


1 - 除非多次加载包含该语句的类。

,

当我们创建一个字符串对象 String s1=new String("hello"); 时,字符串字面量 "hello" 存储在字符串常量池中,引用存储在堆内存中,s1 指向该引用。 String s2="hello"; 在这种情况下,字符串文字存储在字符串常量池中,s2 被直接引用到该地址。String s3=s1.intern(); 如果您尝试这样做,您将获得 s3 点到存储在字符串常量池中的字符串文字的相同地址。

String s1=new String("hello");  
String s2="hello";  
String s3=s1.intern();//returns string from pool,now it will be same as s2  
System.out.println(s1==s2);//false because reference variables are pointing to different instance  
System.out.println(s2==s3);//true because reference variables are pointing to same instance  

希望对你有帮助,如有问题请留言。

,

我们可以使用 intern() 方法将其放入池中或从字符串池中引用另一个具有相同值的 String 对象。

如上一行,将创建 1 或 2 个字符串。

如果池中已经存在字符串字面量“Cat”,则池中只会创建一个字符串“str”。如果池中没有字符串字面量“Cat”,那么会先在池中创建,然后在堆空间中创建,所以一共创建了2个字符串对象。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?