String用法详解(equal源码 ==和equal的解释、字面赋值和new赋值效率、重写了hashcode的方法解释)

本文详细解析了 Java 中 String 对象的创建方式及其内部运作机制,包括字符串池的概念、对象池的区别、equals 方法与 hashCode 的实现原理等核心知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String  a = “abc”;//在字符串池中找abc,如果有,就直接返回地址,如果没有就加值abc然后再返回地址(此方式的值是存放在字符串池中)

String  b =  “abc”;

String  c  =   new String("abc");//在字符串池中找abc,如果有,就不管,如果没有就在对象池中加个abc,然后在堆中建一个对象abc,返回地址(此方式值存放在堆中的)

String  d  =   new String("abc");

 

a ==b    true

a.equal(b)   true

 

b==c     false;

b.equal(c)   true;

 

c==d  false;

c.equal(d)  true;

 

equals方法说明

如果是String对象就调用string的equals,就比较他的值

如果是其他对象,默认调用Object的equals,比较是不是同一个引用和==相同,

如果是其他对象,而且自己实现了equals方式,就按照他自己的equals对象的比较方式。

 

 

 

Object equal方法的源代码

public boolean equals(Object obj) {

         return (this == obj);// 判断调用对象和传入对象的地址是不是一样的

}

 

 

Stirng equal 方法的源代码

public boolean equals(Object anObject) {

         // 自己跟自己比

if (this == anObject) {

             return true;

         }

         if (anObject instanceof String) {// 判断是 String 的实例

             String anotherString = (String)anObject;// 强制转化 , 以防父类用子类的方法用不到

             // 一个字符一个字符的比较

             int n = count;

             if (n == anotherString.count) {

                   char v1[] = value;

                   char v2[] = anotherString.value;

                   int i = offset;

                   int j = anotherString.offset;

                   while (n-- != 0) {

                       if (v1[i++] != v2[j++])

                            return false;

                   }

                   return true;

             }

         }

         return false;

     }

 

 

java String 的字面赋值方式 


public String intern()
Returns a canonical (标准)representation for the string object.
A pool of strings, initially empty, is maintained(维护) privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined(决定) by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal(字面) strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of the Java Language Specification
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

Lexical Structure >Literals >String Literals
The Java Language Specification (所有虚拟机都必须要实现的东西)


字符串池里面是不会丢的, 而堆里面是会被回收的,使用字面建string效率会高.


string的hashcode的源码
/**
* Returns a hash code for this string. The hash code for a
* <code>String</code> object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using <code>int</code> arithmetic, where <code>s[i]</code> is the
* <i>i</i>th character of the string, <code>n</code> is the length of
* the string, and <code>^</code> indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
//就是按s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]公式来生成int序列
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;

for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}


 

<think>好的,我需要回答用户关于何时需要重写Java HashMap中的hashCodeequals方法的问题。首先,我得回忆一下HashMap的工作原理。HashMap通过键的哈希码来存储检索值,所以当用户自定义对象作为键时,默认的hashCodeequals可能不符合需求。 用户提供的引用中有几个关键点。引用[1][2]提到,Object类的默认equals比较的是内存地址,而hashCode生成的是内存地址相关的值。如果两个逻辑上相等的对象因为地址不同而被视为不同,就会导致HashMap无法正确工作。比如,用户自定义的Key类如果没有重写这两个方法,即使id相同,HashMap也会认为它们是不同的键,导致重复插入,如引用[3]的例子。 接着,引用[4][5]强调,重写hashCode需要确保相等的对象有相同的哈希值,而equals则用于处理哈希冲突时的精确比较。如果只重写其中一个,HashMap可能出现无法检索到已存在的键或者存储重复键的情况。 现在需要将这些点整理成用户容易理解的回答。首先说明默认方法的局限性,然后解释何时需要重写:当自定义对象作为键,并且希望逻辑相等而非地址相等时。还要提到集合框架的使用场景,比如HashSet内部也依赖HashMap,同样需要重写这些方法。 还要注意示例代码引用的正确性。比如引用[3]中的例子,虽然Key类重写hashCode,但没重写equals,导致containsKey检查失败,最终导致内存泄漏。这个例子很好地说明了问题。 最后,生成相关问题时要覆盖重写的原因、不重写的后果、方法之间的关系,以及实际应用中的例子。确保问题能帮助用户深入理解主题。</think>### 何时需要重写HashMap中的hashCodeequals方法? 在Java中,当**自定义对象作为HashMap的键**时,必须重写`hashCode``equals`方法以确保逻辑正确性。以下是具体场景原因: --- #### 1. **默认方法的局限性** - **默认行为**: Object类的`equals`方法比较对象内存地址(`this == obj`),而`hashCode`生成与内存地址相关的哈希值[^1]。 - **问题**: 若两个对象逻辑相等但内存地址不同(例如两个`Key(id=5)`实例),默认方法会将其视为不同键,导致HashMap无法正确检索或覆盖值[^2]。 --- #### 2. **需要重写的场景** - **自定义对象作为键**: 例如,用`Student(id, name)`类作为键存储学生成绩。若需通过`id`判断相等性,则需重写`hashCode``equals`。 - **集合框架的使用**: `HashSet`、`HashMap`等依赖哈希表的集合,要求逻辑相等的对象必须具有相同的哈希值[^4]。 --- #### 3. **不重写的后果** - **哈希冲突导致数据重复**: 若仅重写`hashCode`而不重写`equals`,哈希冲突时可能无法正确比较对象(如引用[3]中的`Key`类),导致重复存储相同逻辑的键。 - **内存泄漏或性能问题**: 如引用[3]的示例中,未重写`equals`导致`containsKey`检查失败,HashMap会不断插入新键,最终内存溢出。 --- #### 4. **重写原则** - **一致性**: 若`a.equals(b)`为`true`,则`a.hashCode() == b.hashCode()`必须成立[^4]。 - **哈希分布均匀性**: `hashCode`应尽量减少哈希冲突,提升HashMap性能[^5]。 - **覆盖equals的逻辑**: 例如,通过对象的属性(如`id`或`name`)判断相等性。 --- #### 示例代码 ```java class Student { private int id; private String name; @Override public int hashCode() { return Objects.hash(id, name); // 基于属性生成哈希值 } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Student other = (Student) obj; return id == other.id && Objects.equals(name, other.name); // 属性比较 } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值