java之toString()详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_41282486/article/details/83963186

1.在java中每个类都默认继承Object类,该类除非声明继承其它类。Object类中有一个toString的方法。该方法返回的是该Java对象的内存地址经过哈希算法得出的int类型的值转换成十六进制。

接下来讲解一下String的hashCode()方法:

String类的hashcode值(哈希值)是如何计算得到的?具体实现?为了方便阅读,我来进行分步说明

static void hashcodeTest(){
	
	String str = "yangcq";
	
	// 第一步 = (int)'y'
	// 第二步 = (31 * (int)'y') + (int)'a'
	// 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'
	// 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'
	// 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'
	// 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'
	
	// 上面的过程,也可以用下面的方式表示
	
	// 第一步 = (int)'y'
	// 第二步 = 31 * (第一步的计算结果) + (int)'a'
	// 第三步 = 31 * (第二步的计算结果) + (int)'n'
	// 第四步 = 31 * (第三步的计算结果) + (int)'g'
	// 第五步 = 31 * (第四步的计算结果) + (int)'c'
	// 第六步 = 31 * (第五步的计算结果) + (int)'q'
	
	int hashcode = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q';
	System.out.println("yangcq的hashcode = " + hashcode);        // yangcq的hashcode = -737879313
	System.out.println("yangcq的hashcode = " + str.hashCode());  // yangcq的hashcode = -737879313
	
}

--------------------- 
作者:春秋战国程序猿 
来源:CSDN 
原文:https://blog.csdn.net/reggergdsg/article/details/53819293 
版权声明:本文为博主原创文章,转载请附上博文链接!

相关资料出自:https://blog.csdn.net/reggergdsg/article/details/53819293

以下是java的string的hashCode()源码:(注:hash默认初始值为0, /** Cache the hash code for the string */
    private int hash; // Default to 0 。value为字符串)

    /**
     * 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.
     */
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
 
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

注意那个狗血的31这个系数为什么总是在里面乘来乘去?为什么不适用32或者其他数字?
   大家都知道,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31原因是因为31是一个素数!

所谓素数:
   质数又称素数。指在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。

   在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”。如果使用相同hash地址的数据过多,那么这些数据所组成的hash链就更长,从而降低了查询效率!所以在选择系数的时候要选择尽量长(31 = 11111[2])的系数并且让乘法尽量不要溢出(如果选择大于11111的数,很容易溢出)的系数,因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。

   31的乘法可以由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化,使用31的原因可能是为了更好的分配hash地址,并且31只占用5bits!

   在java乘法中如果数字相乘过大会导致溢出的问题,从而导致数据的丢失.
   而31则是素数(质数)而且不是很长的数字,最终它被选择为相乘的系数的原因不过与此!

我们再来开String中的hash计算:

 h = 31 * h + val[i];

此句是将i位的值赋予一个算子,算子是由31的权重而来

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }

相关资料:https://blog.csdn.net/myspacedemen/article/details/53353480

以下是toString的源码:

 /**
     * Returns a string representation of the object. In general, the 
     * <code>toString</code> method returns a string that 
     * "textually represents" this object. The result should 
     * be a concise but informative representation that is easy for a 
     * person to read.
     * It is recommended that all subclasses override this method.
     * <p>
     * The <code>toString</code> method for class <code>Object</code> 
     * returns a string consisting of the name of the class of which the 
     * object is an instance, the at-sign character `<code>@</code>', and 
     * the unsigned hexadecimal representation of the hash code of the 
     * object. In other words, this method returns a string equal to the 
     * value of:
     * <blockquote>
     * <pre>
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * </pre></blockquote>
     *
     * @return  a string representation of the object.
     */
    public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

Object类中有一个叫做toString的方法。该方法返回的是该Java对象的内存地址经过哈希算法得出的int类型的值在转换成十六进制。这个输出的结果可以等同的看作Java对象在堆中的内存地址。

package com.cal.toString;
 
public class Test1 {
	public static void main(String[] args){
		Object o1 = new Object();
		System.out.println(o1.toString());
	}
}
结果:java.lang.Object@7852e922

2.如果我们定义一个实体类,返回的结果又会是什么呢?

package com.cal.toString;
 
public class Test1 {
	public static void main(String[] args){
		Person p1 = new Person("king", 20);
		System.out.println(p1.toString());
		
	}
}
 
class Person{
	String name;
	int age;
	
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
}
结果:com.cal.toString.Person@4e25154f很显然业务逻辑不太合适,不应该是一串看不懂的数字,而应该是符合逻辑的东西

3.这就表示Object中的toString方法已经不够用了。所以Object中的toString方法就是要被重写。

package com.cal.toString;
 
public class Test1 {
	public static void main(String[] args){
		Person p1 = new Person("king", 20);
		System.out.println(p1.toString());
		
	}
}
 
class Person{
	String name;
	int age;
	
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	public String toString(){
		return "Person[name="+name+", age="+age+"]";
	}
}

这里就把toString方法重新写了,注意toString的返回值是String,结果明显就很符合逻辑了

结果:Person[name=king, age=20]

猜你喜欢

转载自blog.csdn.net/weixin_41282486/article/details/83963186
今日推荐