小鲁班今年计算机专业大四了,在学校可学了不少软件开发的东西,也自学了一些JAVA的后台框架,踌躇满志,一心想着找个好单位实习。当投递了无数份简历后,终于收到了一个公司发来的面试通知,小鲁班欣喜若狂。

  到了人家单位后,前台小姐姐给了小鲁班一份笔试题目,要求在一个小时内完成,小鲁班双手接过题目后,粗略的看了一下题目,心里暗喜,嘻嘻这个还不简单。一顿操作猛如虎,做完了感觉也没什么错误。就交卷了,等待片刻后,小姐姐亲切的说需要一周内等通知哦。于是呢,小鲁班就回去耐心的等待了。可是半个月都快过去了,什么消息都没有,小鲁班就纳闷了,明明我做的挺好的呀,为什么连面试的机会都不给我。

  小鲁班于是找到了他表哥鲁班大师,正准备吐槽这件事,并把一些当时面试的题目重现了一些,并把自己对题目的理解也说了遍,鲁班大师一看他填的答案就开始嘲讽他,前5道题目关于String类的判断题可真是完全避开了正确答案呀,而且后边的题目也是大部分都是错了,人家当然不给你机会呀。

  小鲁班你可要虚心学习了,就拿下边最简单的一题来说,你怎么连==对于非基本数据类型是比较引用而不是比较值的都不知道呀 

String str1 = new String("AA");
String str2 = new String("AA");
System.out.println(str1 == str2);
这里的正确答案是false

  鲁班大师:感觉你的JAVA基础不咋地呀,你说说你在学校学习你所掌握的关于String类的知识点,你表哥今天有空帮你恶补一波吧。

  小鲁班垂头丧气的说到:

  • String类有如下这些特点

  1. String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。
  2. String类其实是通过char数组来保存字符串的。
  3. String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象。

  鲁班大师:嗯,不错嘛,那有没有深入一点的理解呢,比如关于字符串常量池

  小鲁班:这个我~~忘记了!

  鲁班大师:没关系,那你得认真听讲了

  小鲁班:emmm

  • 字符串常量池

  1. 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
  2. 字符串池的出现避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。

  String a="AA";

  String b="AA";

  String c=new String("AA");

  a、b和堆中创建的AA都是指向JVM字符串常量池中的"AA"对象,他们指向同一个对象。

  new关键字一定会产生一个对象AA,同时这个对象是存储在堆中。所以String c=new String("AA")这一句应该产生了两个对象:保存在方法区中字符串常量池的AA和保存堆中AA。但是在Java中根本就不存在两个完全一模一样的字符串对象。故堆中的AA应该是引用字符串常量池中AA。所以c、堆AA、池AA的关系应该是:c--->堆AA--->池AA。

  虽然a、b、c是不同的引用,但是从String的内部结构我们是可以理解上面的。String c = new String("AA");虽然c的内容是创建在堆中,但是他的内部value还是指向JVM常量池的AA的value,它构造AA时所用的参数依然是AA字符串常量。所以a==b是ture,因为内存地址是一样的 a==c是false,因为c的内存地址指向是在堆中new的是新的地址,而不是在常量池的地址。

  鲁班大师又问了:我看你还挺懵的,你知道==和equals吗

  小鲁班:这个我知道。

  

  • 对于==,如果作用于基本数据类型的变量(byte,short,char,int,long,float,double,boolean ),则直接比较其存储的"值"是否相等;如果作用于引用类型的变量(String),则比较的是所指向的对象的地址(即是否指向同一个对象)。
  • 对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等。

  鲁班大师:嗯,答的不错,但是要应付一些面试题,你还要知道这些。

  1. 单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
  2. 使用new String("")创建的对象会存储到heap中,是运行期新创建的;
  3. 使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
  4. 使用包含变量(引用)的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
  5. 但是如果s1是被final修饰的话,则s1是属于常量。结果存在String Pool,但是 final修饰的是一个方法返回的值也是在编译器确定。

  好了,这些你都知道了,那你把刚那份题目在做一次看看

  

String str1 = "aaa";
String str2 = "aaa";
System.out.println(str1 == str2);// true 因为String有常量池 String str3 = new String("aaa");
String str4 = new String("aaa");
System.out.println(str3 == str4);// false 可以看出用new的方式是生成不同的对象,比较堆上的 String s0="helloworld";
String s1="helloworld";
String s2="hello"+"world";
System.out.println(s0==s1); //true 可以看出s0跟s1是指向同一个对象
System.out.println(s0==s2); //true 可以看出s0跟s2是指向同一个对象 String st0="helloworld";
String st1=new String("helloworld");
String st2="hello" + new String("world");
System.out.println( st0==st1 ); //false 用new String() 创建的字符串不是常量,不能在编译期就确定
System.out.println( st0==st2 ); //false st2地址存在堆中,不可能相同
System.out.println( st1==st2 ); //false String stri1="abc";
String stri2="def";
String stri3=stri1+stri2;
System.out.println(stri3=="abcdef"); //false 变量相+是在的堆内存中创建 String strin0 = "a1";
String strin1 = "a" + 1; //这种不是变量,是常量
System.out.println((strin0 == strin1)); //result = true String strin2 = "atrue";
String strin3= "a" + "true";
System.out.println((strin2 == strin3)); //result = true String strin4 = "a3.4";
String strin5 = "a" + 3.4;
System.out.println((strin4 == strin5)); //result = true String string0 = "ab";
String string1 = "b";
String string2 = "a" + string1;
System.out.println((string0 == string2)); //result = false 在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的 String test="javalanguagespecification";
String test2="java";
String test3="language";
String test4="specification";
System.out.println(test == "java" + "language" + "specification"); //true 字符串字面量拼接操作是在Java编译器编译期间就执行了
System.out.println(test == test2 + test3 + test4); //false 字符串引用的"+"运算是在Java运行期间执行的 String ss0 = "ab";
final String ss1 = "b";
String ss2 = "a" + ss1;
System.out.println((ss0 == ss2)); //result = true 对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + s1和"a" + "b"效果是一样的 String ss10 = "ab";
final String ss11 = getS1();
String ss12 = "a" + ss11;
System.out.println((ss10 == ss12)); //result = false 这里面虽然将s1用final修饰了,但是由于其赋值是通过方法调用返回的,那么它的值只能在运行期间确定 public static String getS1(){
return "b";
}
String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。
当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),
那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
  1. String s1 = new String("aaa");

  2. String s2 = new String("aaa");

  3. System.out.println(s1 == s2); // false

  4. String s3 = s1.intern();

  5. String s4 = s1.intern();

  6. System.out.println(s3 == s4); // true


  鲁班大师:优秀呀,小鲁班!不过呢我们既然都研究了String,那么关于StringBuffer和StringBuilder也得知道,给你布置个作业,把他们3者的区别写一下自己的见解,发到我的邮箱,今天就到此为止了,表哥得去开黑了。

  小鲁班:谢谢表哥,我一定好好整理的!小鲁班回到家后,立马奋笔疾书。。。

  send to 鲁班大师@qq.com 

  String、StringBuffer、StringBuilder的区别?

  • 可变与不可变:String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象(其内部的字符数组长度可变)。
  • 是否多线程安全:String中的对象是不可变的,也就可以理解为常量,显然线程安全。StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是非线程安全的。
  • String、StringBuilder、StringBuffer三者的执行效率如下:
  • StringBuilder > StringBuffer > String 当然这个是相对的,不一定在所有情况下都是这样。比如String str = "hello"+ "world"的效率就比 StringBuilder st  = new   StringBuilder().append("hello").append("world")要高。因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:
  • 当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
  • 当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。

  好累呀,因为虚心的小鲁班除了整理了这些之外,同时自己继续学习封装类的比较,因为也被其他笔试题坑惨了呀!

1.两个基本类型的只能用 ==
2.基本型和封装型用==,封装型将会自动拆箱变为基本型后再进行比较
3.用==来比较两个封装类的话,比较的是地址。(其中-127到127之间的Integer地址相同,超出这个范围则不同)
4.至少有一个封装型的建议使用.equals。用==对基本型和封装性比较必须保证封装型不为null。如果为null则不能转化为基本型就会报错。
5.两个封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
6.封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,若类型不同返回false,若装箱后类型相同,则比较值,如果值相同,则返回true

  

int a=128;
int a2=127;
Integer b=128;
Integer b2=127;
Integer c=128;
Integer c2=127;
Integer d=new Integer(a);
Integer d2=new Integer(a); Integer b2=57;
Integer c2=57; System.out.println(a==b);//true System.out.println(b==c);//false
System.out.println(b2==c2);//3true System.out.println(a==d);//true
System.out.println(b==d);//false
System.out.println(d==d2);//false //由强类型向弱类型转换需要强制转换,而由弱类型向强类型转换则系统自动转换。
//double 类型相比int类型是属于强类型,则由double类型的数据向int类型数据转换就需要强制转换,反之则自动转换。数据类型的强弱关系如下:
//byte<short=char<int<long<float<double,同级之间相互转换也需要强制转换。
//对于未声明数据类型的整形,其默认类型为int型。
//在浮点类型(float/double)中,对于未声明数据类型的浮点型,默认为double型。
System.out.println(b.equals(128.0));//false
  • new Integer(123) 每次都会新建一个对象;

  • Integer.valueOf(123) 会使用缓存池( -128~127)中的对象,多次调用会取得同一个对象的引用,如果在缓存池没有,则NEW

 

  写完这些后小鲁班,小鲁班关了台灯,合上了电脑,休息一下准备明天的面试~

  

  小鲁班面试回来了,遇到比较坑的一道题

  X a=.....;

  X b=a

  System.out.print(a==b);   要结果是false,X是一个给定类型

  答案:

  float a =0f/0;
  float b=a;
  System.out.println(a==b);

  原理:NaN 不等于任何浮点数值,包括它自身在内;即它与任何数比较均返回false,但是可以用Float.compare()来比较NaN

  延伸:infinity无穷大  float a=3.0f/0;  float b=a+1;

无穷大加上一个数还是无穷大。 System.out.println(a==b);

  

String求求你别秀了的更多相关文章

  1. bnuoj 34985 Elegant String DP+矩阵快速幂

    题目链接:http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=34985 We define a kind of strings as elegant s ...

  2. 95秀-自定义对话框 dialog 合集

    普通的确认对话框 NormalDialog.java import android.app.Dialog; import android.content.Context; import android ...

  3. [LeetCode] Reorganize String 重构字符串

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...

  4. 易企秀H5 json配置文件解密分析

    最近需要参考下易企秀H5的json配置文件,发现已经做了加密,其实前端的加密分析起来只是麻烦点. 抓包分析 先看一个H5: https://h5.eqxiu.com/s/XvEn30op F12可以看 ...

  5. 从C,C++,JAVA和C#看String库的发展(一)----C语言和C++篇

    转自: http://www.cnblogs.com/wenjiang/p/3266305.html 基本上所有主流的编程语言都有String的标准库,因为字符串操作是我们每个程序员几乎每天都要遇到的 ...

  6. CodeForces - 950C Zebras 模拟变脑洞的天秀代码

    题意:给你一个01串,问其是否能拆成若干形如0101010的子串,若能,输出所有子串的0,1 的位置. 题解:一开是暴力,然后瞎找规律, 最后找到一种神奇的线性构造法:扫一遍字符串,若为0就一直竖着往 ...

  7. 牛客网 牛客小白月赛2 C.真真假假-String遍历比较

    C.真真假假 链接:https://www.nowcoder.com/acm/contest/86/C 这个题真的是无敌的水,但是自己写前面的string数组的时候,里面的这些头文件要用双引号(&qu ...

  8. CodeForces 931E Game with String

    Game with String 题意:有一个字符串,可以选择从第K位开始,将[K,len(s)-1]的字符都移到前面去,现在给你一个首字母,你可以再选择一位进行观察,然后猜测这个K的值是多少, 现在 ...

  9. [LeetCode] 767. Reorganize String 重构字符串

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...

随机推荐

  1. Navicat永久激活步骤,激活工具,解决注册码无效的问题

    Navicat for MySQL是一套管理和开发MySQL或MariaDB的理想解决方案,支持单一程序,可同时连接到MySQL和MariaDB.这个功能齐备的前端软件为数据库管理.开发和维护提供了直 ...

  2. Elasticsearch 编程API入门系列---说在前面的话

    前提,是 Eclipse下Maven新建项目.自动打依赖jar包(包含普通项目和Web项目) setting.xml配置文件 如何在Maven官网下载历史版本 HBase 开发环境搭建(Eclipse ...

  3. mysql-索引、关系、范式

    索引 几乎所有的索引都是建立在字段之上 索引:系统根据某种算法,将已有的数据(未来可能新增的数据也算),单独建立一个文件,这个文件能够快速的匹配数据,并且能够快速的找到对应的表中的记录 索引意义 能够 ...

  4. 二叉树,AVL树和红黑树

    为了接下来能更好的学习TreeMap和TreeSet,讲解一下二叉树,AVL树和红黑树. 1. 二叉查找树 2. AVL树 2.1. 树旋转 2.1.1. 左旋和右旋 2.1.2. 左左,右右,左右, ...

  5. 小程序从后台输出的代码为HTML实体字符如何解决?

    最近在做一个小程序的考试系统,从后台调出的数据是这个样子的 那么我遇到这个问题的时候想到的微信小程序的富文本即(wxParse),使用过wxParse的都知道,富文本必须得具体到单个的数据上才能使用, ...

  6. Java并发之Condition

    在使用Lock之前,我们使用的最多的同步方式应该是synchronized关键字来实现同步方式了.配合Object的wait().notify()系列方法可以实现等待/通知模式.Condition接口 ...

  7. Python学习 Part7:类

    Python学习 Part7:类 1. 作用域和命名空间 命名空间(namespace)就是一个从名称到对象的映射. 命名空间的一些实例:内置名称集(函数,像abs(),和内置异常名称),一个模块中的 ...

  8. Python_性能测试

    使用pip安装Python扩展库memory_profiler from memory_profiler import profile @profile #修饰器 def isPrime(n): if ...

  9. 网站开发中使用javascript获取浏览器滚动条宽度

    在网站开发中,有时候需要获取浏览器滚动条的宽度,在武汉蚂蹄软件服务中心的技术人员指导之下,我实现了该需求.记录如下: 首先说明一下原理: ①生成一个div,设置滚动条不可见,记录其宽度: ②将上面的d ...

  10. Netty中如何写大型数据

    因为网络饱和的可能性,如何在异步框架中高效地写大块的数据是一个特殊的问题.由于写操作是非阻塞的,所以即使没有写出所有的数据,写操作也会在完成时返回并通知ChannelFuture.当这种情况发生时,如 ...