string类总结第二部分实战练习
Posted gollong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了string类总结第二部分实战练习相关的知识,希望对你有一定的参考价值。
第二部门:实战练习
昨天由于时间原因,这个部分应该在同一个文章中的,无奈只能今天再开一个了,今天主要是讲一些面试题
一:equals和==的区别
最简单的面试题,也是最基础的,我估计每个学习java的人都在网上看到过该问题,答案一额很简单:equals是方法,当然只能对象来调用,所以equals只能用来比较引用类型,若该类型重写了equals方法,那比较的就是内容,比如说String类就是比较的每一对对应的字符,==既能比较基本类型,也能比较引用类型,基本类型比较的是值,引用类型比较的是地址值,总之==比较的是栈内存空间中存放的数值。
二:hashCode方法返回的是什么,有什么用
首先看几行代码,对于没重写hashCode方法的类的对象,返回的是该对象在堆内存空间的内存地址。也就是和System.identityHashCode方法返回的一样,System.indetityHashCode返回的就是地址值。
Student stu = new Student(); System.out.println(stu.hashCode());//1554874502 System.out.println(System.identityHashCode(stu));//1554874502
对于重写hashCode方法的类,我们拿String来举例,每个自字符串的哈希码其实是通过一个表达式来计算的s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],s[0]是指下标为0的字符的二进制数的十进制表示,对于a来说就是97(ASCII码表可查)
System.out.println("a".hashCode());//97 97=97*31^0 System.out.println("aa".hashCode());//3104 3104=97+97*31^1 System.out.println("aaa".hashCode());//96321 96321=3104+97*31^2 System.out.println("aaaa".hashCode());//2986048 。。。 System.out.println("aaaaa".hashCode());//92567585 。。。 System.out.println("aaaaaa".hashCode());//-1425372064 因为返回的是int类型,这里越界了,所有事负数 System.out.println("aaaaaaa".hashCode());//-1236860927 System.out.println("aaaaaaaa".hashCode());//312017024 System.out.println("aaaaaaaaa".hashCode());//1082593249
所有,我们现在明白了重写hashCode是通过某个表达式,来规定一个哈希码,这个值在很大程度上保证了唯一性,但是因为越界有可能存在俩个不同的字符串但却有相同的哈希码,所以hashCode的作用是在哈希表数据结构中(比如hashTable,hashMap)来判断俩个元素是否相等的第一个条件,若不相等,那么这两个元素的内容肯定不相等(因为他们都是通过某个同样的表达式对属性进行操作得到的),若相等,则再进行equals的比较。
特此声明:对于将要往哈希表数据结构中存放的类型必须重写hashCode方法,因为如果不重写,hashCode返回的就是地址值,那每两个new出来的对象的地址值一定不相等,但是他们的内容却一样,这不乱套了么
String s1 = "gollong"; String s2 = new String(s1); System.out.println(s1.hashCode());//204502272 System.out.println(s2.hashCode());//204502272 System.out.println(s1==s2);//false System.out.println(System.identityHashCode(s1));//1554874502 System.out.println(System.identityHashCode(s2));//1846274136
例如:由于不重写hashCode,set集合当中存入了两个一样的对象
HashSet<Student> set = new HashSet<Student>(); Student s1 = new Student("gol", 1.0, 1); Student s2 = new Student("gol", 1.0, 1); System.out.println(s1.hashCode());//1554874502 System.out.println(s2.hashCode());//1846274136 set.add(s1); set.add(s2); System.out.println(set); //[Student [name=gol, scaly=1.0, age=1], Student [name=gol, scaly=1.0, age=1]]
三:intern方法的作用
我相信知道这个方法的人很少,明白它是做什么的更少,这就涉及到昨天的那个String s = new String("gollong")创建了几个对象,答案在下图中
现在存在两个对象,一个在堆中,一个在常量池中,我们知道现在的这个s引用指向的是堆内存中的这个"gollong",而intern方法的作用就是将这个引用的指向直接改到常量池中的"gollong"上,也就是变成这样:
所以在下面的代码中,s1和s2.intern的地址值是一样的,本来s2是指向堆内存中的。现在指向了常量池中。
String s1 = "gollong"; String s2 = new String(s1); System.out.println(s1.hashCode());//204502272 System.out.println(s2.hashCode());//204502272 System.out.println(s1==s2);//false System.out.println(System.identityHashCode(s1));//1554874502 System.out.println(System.identityHashCode(s2));//1846274136 System.out.println(s1==s2.intern());//true System.out.println(System.identityHashCode(s1));//1554874502 System.out.println(System.identityHashCode(s2.intern()));//1554874502
四:s = "" 和 s = new String("")有什么区别
这个问题,咋一看你觉得自己不知道,其实他俩和s = "gollong" ,s = new String(""gollong)没有任何区别,都有对象的引用,字符串(虽然书空的)也分别存放在堆中和常量池中,详情见下面代码中的地址值。空字符串的哈下面默认为0.
String s3 = ""; String s4 = new String(); System.out.println(s3==s4);//false System.out.println(s3.hashCode());//0 System.out.println(s4.hashCode());//0 System.out.println(System.identityHashCode(s3));//1554874502 System.out.println(System.identityHashCode(s4));//1846274136
五:String对象的初始化时机:
我们都知道java程序是需要通过先编译生成class文件再执行的,那么在编译的时候其实是对一些代码进行转换到,比如说下面的代码同样是+号链接俩个字符串对象,为什么s3==s4是true
String s1 = "gol"; String s2 = "long"; String s3 = "gollong"; String s4 = "gol"+"long"; String s5 = s1+s2; String s6 = s1+"long"; String s7 = "gol"+s2; System.out.println(s3==s4);//true System.out.println(s3==s5);//false System.out.println(s3==s6);//false System.out.println(s3==s7);//false
下面是通过反编译器的到的class文件代码
String s1 = "gol"; String s2 = "long"; String s3 = "gollong"; String s4 = "gollong"; String s5 = (new StringBuilder(String.valueOf(s1))).append(s2).toString(); String s6 = (new StringBuilder(String.valueOf(s1))).append("long").toString(); String s7 = (new StringBuilder("gol")).append(s2).toString(); System.out.println(s3 == s4); System.out.println(s3 == s5); System.out.println(s3 == s6); System.out.println(s3 == s7);
我们很清楚的看到了虽然都是+号,但是是有区别的,当编译器识别到左右两端都是常量时,将直接在常量池中创建该对象,然后直接赋值,而对于变量名s1或s2由于编译器并不不知道他们的值是多少,其实得到的是一个在堆中的String对象,其地址值当然和常量池中的不一样了!
以上是关于string类总结第二部分实战练习的主要内容,如果未能解决你的问题,请参考以下文章
python爬虫--scrapy框架的学习和使用⭐---第二部分
自学总结redis第二部分(redis常用命令高级命令特性以及与java代码的结合)