浅谈对String的了解

本文深入探讨了 Java 中 String 类的设计原理,特别是其不可变性的实现及其带来的效率和安全性优势。通过具体的代码示例,详细解释了字符串常量池的工作机制,以及不同字符串创建方式在 JVM 内存中的表现。

String定义

 public final class String
 implements java.io.Serializable, Comparable<String>, CharSequence {} 

final修饰,不可变。String设计为不可变类主要考虑到:效率和安全。

效率:缓存hashcode,String不可变,所以hashcode不变,这样缓存才有意义,不必重新计算。
安全:String常被作为网络连接,文件操作等参数类型,倘若可改变,会出现意想不到的结果。

测试

 public static void main(String[] args) {
 String str1 = "HelloFlyapi";
 String str2 = "HelloFlyapi";
 String str3 = new String("HelloFlyapi");
 String str4 = "Hello";
 String str5 = "Flyapi";
 String str6 = "Hello" + "Flyapi";
 String str7 = str4 + str5;
 System.out.println("str1 == str2 result: " + (str1 == str2));
 System.out.println("str1 == str3 result: " + (str1 == str3));
 System.out.println("str1 == str6 result: " + (str1 == str6));
 System.out.println("str1 == str7 result: " + (str1 == str7));
 System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern()));
 System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern()));
 }

要理解String,那么要了解JVM内存中的栈(stack)、堆(heap)和方法区。简要图如下:在这里插入图片描述

第一个

 String str1 = "HelloFlyapi";
 String str2 = "HelloFlyapi";
 System.out.println(str1 == str2); // true

当执行第一句时,JVM会先去常量池中查找是否存在HelloFlyapi,当存在时直接返回常量池里的引用;当不存在时,会在字符创常量池中创建一个对象并返回引用。
当执行第二句时,同样的道理,由于第一句已经在常量池中创建了,所以直接返回上句创建的对象的引用。

第二个

 String str1 = "HelloFlyapi";
 String str3 = new String("HelloFlyapi");
 System.out.println(str1 == str3); // false

执行第一句,同上第一句。
执行第二句时,会在堆(heap)中创建一个对象,当字符创常量池中没有‘HelloFlyapi’时,会在常量池中也创建一个对象;当常量池中已经存在了,就不会创建新的了。

第三个

 String str1 = "HelloFlyapi";
 String str6 = "Hello" + "Flyapi";
 System.out.println(str1 == str6); // true

由于”Hello”和”Flyapi”都是常量,编译时,第二句会被自动编译为‘String str6 = “HelloFlyapi”;

第四个

 String str1 = "HelloFlyapi";
 String str4 = "Hello";
 String str5 = "Flyapi";
 String str7 = str4 + str5;
 System.out.println(str1 == str7); // false

其中前三句变量存储的是常量池中的引用地址。
第四句执行时,JVM会在堆(heap)中创建一个以str4为基础的一个StringBuilder对象,然后调用StringBuilder的append()方法完成与str5的合并,之后会调用toString()方法在堆(heap)中创建一个String对象,并把这个String对象的引用赋给str7。

后面两个

 String str1 = "HelloFlyapi";//在常量池中创建
 String str2 = "HelloFlyapi";//在常量池中创建
 String str3 = new String("HelloFlyapi");//在堆上创建
 String str4 = "Hello";
 String str5 = "Flyapi";
 String str7 = str4 + str5;//返回常量池中常量HelloFlyapi
 System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern()));//true
 System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern()));//false

String.intern()分析:
判断这个常量是否存在于常量池。
  如果存在
   判断存在内容是引用还是常量,
    如果是引用,
     返回引用地址指向堆空间对象,
    如果是常量,
     直接返回常量池常量
  如果不存在,
   将当前对象引用复制到常量池,并且返回的是当前对象的引用

具体分析可参考

https://blog.youkuaiyun.com/u013366617/article/details/83618361

文章摘自

https://zhuanlan.zhihu.com/p/60643031

<think>好的,我现在需要帮助用户了解如何使用Android DataBinding。根据用户提供的引用内容,我需要整理一个结构清晰的教程。首先,我要确定DataBinding的基本配置步骤,因为这是开始使用的前提。然后,布局文件的修改是关键,需要解释如何将传统布局转换为DataBinding支持的格式。接下来,数据绑定的部分,用户可能需要知道如何创建数据模型并将其与UI绑定,引用中的User类示例和BindingAdapter的使用都是重点。此外,用户可能对在Activity和Fragment中的不同用法感兴趣,比如在Activity中使用DataBindingUtil.setContentView,而在Fragment中使用inflate方法。我还需要提到数据绑定的优势,比如减少样板代码,以及处理复杂数据的方法,比如使用@BindingAdapter自定义属性。最后,生成相关问题可以帮助用户深入理解,比如性能优化或与LiveData的结合。需要确保所有步骤都符合引用内容,并且语法正确,使用中文回答,行内公式用$...$,独立公式用$$...$$,不过在这个问题中可能公式较少,但要注意LaTeX的正确使用。检查是否有遗漏的步骤,例如启用DataBinding的Gradle配置,绑定变量的设置,以及事件处理的方法。确保每个部分都有对应的引用标注,比如在Activity和Fragment中的用法分别引用[^2]和[^1]。最后,生成的相关问题要覆盖用户可能感兴趣的扩展方向,如性能、优化、应用场景等。</think>### Android DataBinding 使用教程 #### 1. **启用DataBinding** 在模块的$build.gradle$文件中添加配置: ```groovy android { ... dataBinding { enabled = true } } ``` 同步项目后,系统会自动生成与布局文件对应的绑定类。 #### 2. **修改布局文件** 将传统XML转换为DataBinding格式: ```xml <!-- activity_main.xml --> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User" /> </data> <LinearLayout...> <TextView android:text="@{user.name}" // 直接绑定变量 .../> <ImageView app:imageUrl="@{user.avatarUrl}" // 自定义属性绑定 .../> </LinearLayout> </layout> ``` 布局根标签需改为$<layout>$,并通过$<data>$定义变量[^3]。 #### 3. **数据绑定实现** - **数据模型类**(例如$User$)需使用可观察机制(如$BaseObservable$或$LiveData$): ```java public class User extends BaseObservable { private String name; @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); // 触发UI更新 } } ``` - **在Activity中绑定数据**: ```java ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); User user = new User(); user.setName("John Doe"); binding.setUser(user); // 关键绑定语句 ``` - **在Fragment/Adapter中使用**: ```java ListItemBinding binding = DataBindingUtil.inflate( LayoutInflater.from(context), R.layout.list_item, parent, false ); binding.setVariable(BR.item, dataItem); // BR.item对应布局中定义的变量名[^1] ``` #### 4. **处理复杂绑定** - **自定义属性**:通过$@BindingAdapter$实现网络图片加载等逻辑: ```java @BindingAdapter("imageUrl") public static void bindImageUrl(ImageView view, String url) { Glide.with(view).load(url).into(view); // 使用第三方库加载图片[^4] } ``` - **事件绑定**:在布局中直接绑定点击事件: ```xml <Button android:onClick="@{() -> viewModel.onButtonClick()}" .../> ``` #### 5. **优势与注意事项** - **优势**:减少$findViewById$调用,UI更新自动化,代码可读性提升[^3] - **注意**:避免在布局中编写复杂逻辑,建议与ViewModel或Presenter模式结合
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值