面试中,关于字符串问题,出现几率比较高的两个问题 第一个问题: public static void main(String[] args) { String s = new String("abc"); //执行到这一行时,创建了几个对象? String s1 = "abc"; //执行到这一行时,创建了几个对象? String s2 = new String("abc"); //执行到这一行时,创建了几个对象? System.out.println(s == s1); //输出结果是什么? System.out.println(s == s2); //输出结果是什么? System.out.println(s2 == s1); //输出结果是什么? } 解答: (1) 执行第一行的时候创建两个对象。为什么是两个对象,我们先来分析下。应为String类型是一个特殊类型,因为是final 来存储字符串对象。所以一旦创建String类型的字符串,就不能更改。关于用常量来声明字符串对象就要不得不说String pool 的概念(关于String pool 的概念,我在下一章进行详细介绍,这里不多说了。)。在这里记住一点凡是""声明的字符串对象都存储在String pool池中。 那么在执行第一句中("abc")声明的对象就存储在String pool中,这是声明第一个对象。 当new Strring时,又产生一个对象,只不过这个对象是存放在内存heap(堆中)。还要记住一点只要有new 关键字就会产生一个新的对象,这是声明的第二个对象。 答案:执行第一行产生2个对象。 (2)当执行第二行的时候,我说过凡是用""声明的字符串对象就会存储到String pool池中。 但这里需要记住的是String pool池中,不会存储相同的字符串对象,每当用""声明字符串对象前,都会先检查String pool池中,是否存在相同的字符串对象。如果存在相同的字符串对象,则返回该对象。如果没有该字符串对象,则把该对象加入String pool池中。因为执行第一行时,已经把"abc"字符串放到String pool池中,所以当执行String s1="abc";已经发现String pool池中有abc字符串,则不会创建,而是直接返回该对象。所以这行并没有创建对象 答案:执行第二行产生0个对象。 (3)执行第三行时,我说过"abc"对象已经存在String pool池中,则不会创建。记住String pool池中不会存储相同字符串对象。只要有new 的地方就会在heap(堆)中产生一个新的对象。 答案:执行第三行产生1个对象。 (4)因为s引用的对象是存储在String pool池中,而s1引用的对象是存储在heap(堆)中,引用的不是同一个对象。所以执行System.out.println(s == s1); 答案:结果为false。 (5)因为s引用的对象是存储在String pool池中,而s2引用的对象是存储在heap(堆)中,引用的不是同一个对象。所以执行System.out.println(s == s2); 答案:结果为false。 (6)虽然s1和s2引用的对象都存储在heap(堆)中,但他们的内存地址不相同,所以不是同一个对象,这是因为使用new 关键字创建对象时,会新开辟一块内存空间来存放对象。所以用new 创建同一个对象,永远都不会相同。所以执行System.out.println(s2 == s1); 答案:结果为false。 ----------------------------------------------------------------------------- 下面是一个关于字符串的机试问题: 编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4,应该截为“我AB”,输入“我ABC汉DEF”,6,应该输出为“我ABC”而不是“我ABC+汉的半个”。 样例: /* * 按照指定字节,截取子字符串函数 * @param str 要截取的字符串 * @param len 要截取的字节数 * @return String 截取后子字符串 */ public static String splitString(String str,int len) { if(str==null||str.equals("")) { return ""; } byte[] b=str.getBytes(); String subString=null; if(b.length<len || len<0) { return str; } if(len>1) { if(b[len]<0) { subString=new String(b,0,--len); } else { subString=new String(b,0,len); } } else { if(len==1) { if(b[len]<0) { subString=new String(b,0,++len); } else { subString=new String(b,0,len); } } } return subString; } 下面提供两个按照指定编码截取字符串 第一种按照:Unicode 编码方式来产生字节数组 String str="我爱java"; String s=str.getBytes("Unicode"); 这种方式产生的字节数组,字节数组的前两个字节为标志位,如byte[0]=-1,byte[1]=-2。从第三位开始才是真正的字符串。在Unicode 编码下,汉字、英文、数字都是两个字节。而英文和数字,第一个字节是相应的ASCII码,第二个字节是0.而汉字两个字节都大于0. 这种方法每个字符都是两个字节: /* * 按照双字节,截取指定函数 * @param str 要截取的字符串 * @param len 要截取的长度 * @return string 截取后的字符串 */ public static String mySubString(String str,int len) throws UnsupportedEncodingException { /*首先把目标字符串分解成Unicode编码的字节数组, * 这样的目的是每个字符都变成两个字节,在根据 * 英文和数字字符在Unicode编码下,第一个字节 * 是相应的ASCII码,第二个字节为0的特征,来进行 * 计算 */ int pos=len+1; byte[] b=str.getBytes("Unicode"); if(b[len]==0) { return new String(b,0,len+1,"Unicode"); } if(b[len]!=0) { if(b[len+1]!=0) { if((len%2!=0)) { return new String(b,0,len+1,"Unicode"); } else { return new String(b,0,len+2,"Unicode"); } } else { return new String(b,0,len+2,"Unicode"); } } return null; } ------------------------------------------------------------------------------- 第二种按照:GBK编码方式产生字节数组 String str="我爱java"; String s=str.getBytes("GBK"); 这种方式产生的字节数组,汉字是两个字节,英文和数字是一个字节。而汉字两个字节都小于0.而英文和数字产生的字节都是相对应的ASCII码。如 a 对应 97。 样例: /* * 目标字符串中截取指定字节函数 * @param str 要截取的字符串 * @param len 要截取的长度 * @return string 截取后的字符串 */ public static String mySubString(String str,int len,String symbol) throws UnsupportedEncodingException { if(str==null||str.equals("")) { return ""; } int count=0; byte[] b=str.getBytes("GBK"); if(b.length<len) return str; for(int i=0;i<b.length;i++) { if(b<0) { count++; } } if(count%2==0) { return new String(b,0,len,"GBK")+symbol; } else { return new String(b,0,len-1,"GBK")+symbol; } }