字符串 面试题
1. String 属于基础数据类型吗?
答:String 不是基础数据类型,它是从堆上分配来的。基础数据类型有 8 个,分别为:boolean、byte、short、int、long、float、double、char。
java 中String 是个对象,是引用类型 ,基础类型与引用类型的区别是,基础类型只表示简单的字符或数字,引用类型可以是任何复杂的数据结构 ,基本类型仅表示简单的数据类型,引用类型可以表示复杂的数据类型,还可以操作这种数据类型的行为 。
java虚拟机处理基础类型与引用类型的方式是不一样的,对于基本类型,java虚拟机会为其分配数据类型实际占用的内存空间,而对于引用类型变量,他仅仅是一个指向堆区中某个实例的指针。
(1)首先给出数据类型的分类
(2)Java数据类型在内存中的存储:
1)基本数据类型的存储原理:所有的简单数据类型不存在“引用”的概念,基本数据类型都是直接存储在内存中的内存栈上的,数据本身的值就是存储在栈空间里面,而Java语言里面八种数据类型是这种存储模型;
2)引用类型的存储原理:引用类型继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储,简单地讲,“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的;
区别:基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的(需要java中的栈、堆概念),
(3)那Java中字符串string属于什么数据类型?
Java中的字符串String属于引用数据类型。因为String是一个类。
2. 以下可以正确获取字符串长度的是?
A:str.length
B:str.size
C:str.length()
D:str.size()
答:C
题目解析:字符串没有 length 属性,只有 length() 方法。
数组求长度用length属性
字符串求长度用length()方法
集合求长度用size()方法
3. 以下代码输出的结果是?
String str = “laowang”;
str.substring(0,1);
System.out.println(str);
A:l
B:a
C:la
D:laowang
答:D
题目解析:因为 String 的 substring() 方法不会修改原字符串内容,所以结果还是 laowang。
String 类型提供的三个方便而又非常相似的截取方法:
- slice()
- substr()
- substring()
它们的相似体现在两个方面:
功能:都是截取字符串,并且都返回一个新的字符串
参数:都支持接受两个参数,第一个参数都是代表截取的开始位置。第二个参数除了 substr() ,其他两个 slice() 和 substring() 都是代表截取的结束位置
都只接收一个参数的情况下,都是从起始位置一致截取到末尾
接下来是区别:
slice() 两个参数分别代表着截取的开头和结尾,而 substr() 的第二个参数则代表着截取的位数(即长度),substring() 先对两个参数进行大小对比,再确定截取区域
三个方法如果截取到末尾,便会停止截取,无论参数约定的结束位置、或约定的长度有多大。
当参数为负数的情况:slice() 会把负数与字符串的长度相加,得到的正数再执行代码。substr() 第一个参数也是把负数与字符串的长度相加得到正数,第二个参数则会把负数转为 0。substring() 则会把所有负数参数转为 0
字符串操作方法中的concat、slice、substring、substr都不会破坏原数组,会自动返回操作后新的数组。
concat用于连接两个或多个字符串字符串,支持链式操作,但一般情况下使用加号运算符更简便快捷。
slice、substring、substr都支持一个或两个参数,第一个参数是截取子字符串开始位置的索引,如果只包含一个参数表示从此位置开始(包含此位置)截取至字符串结尾;
slice、substring的第二个参数都表示结束截取字符后面的位置(不包含此位置),那这两个方法有什么不同的地方?不的地方在于当我们传入一个负值时:slice会将传入的负值与字符串的长度相加,返回结果值的子字符串。而substring只要传入负值都会转换成0,返回完整的字符串。
substr传入一个负值时和slice一样的效果,也有传入一个两个参数其中一个是负值的情况,但我觉得并没有实际的用处,反而不容易记忆,就不做记录。
4. 以下 String 传值修改后执行的结果是什么?
public static void main(String[] args) {
String str = new String("laowang");
change(str);
System.out.println(str);
}
public static void change(String str) {
str = "xiaowang";
}
答:laowang
String 为不可变类型,在方法内对 String 修改的时候,相当修改传递过来的是一个 String 副本,所以 String 本身的值是不会被修改的。
String 不可变的技术实现
打开JDK的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
//other codes
}
String 类由关键字 final 修饰,说明该类不可继承
char value[] 属性也被 final 所修饰,说明 value 的引用在创建之后,就不能被改变
以上两点并不能完全实现 String 不可变 ,原因在于:
final int[] value={1,2,3}
int[] another={4,5,6};
value=another; // 编译器报错,final不可变
value 被 final 修饰,只能保证引用不被改变,但是 value 所指向的堆中的数组,才是真实的数据,只要能够操作堆中的数组,依旧能改变数据。【解释:String实际上是可变的】
final int[] value={1,2,3};
value[2]=100; //这时候数组里已经是{1,2,100}
所有的成员属性均被 private 关键字所修饰
为了实现 String 不可变,关键在于Java的开发者在设计和开发 String 的过程中,没有暴露任何的内部成员,与此同时 API 的设计是均没有操作 value 的值 , 而是采用 new String() 的方式返回新的字符串,保证了 String 的不可变。
JDK String API 源码:
public static String valueOf(char c) {
char data[] = {c};
return new String(data, true); //采用 new String() 的方式返回新的字符串
}
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true); //采用 new String() 的方式返回新的字符串
}
整个String设成final禁止继承,避免被其他人继承后破坏。所以String是不可变的关键都在底层的实现,而不是一个final。考验的是工程师构造数据类型,封装数据的功力。
5.判定字符串是否为空,有几种方式?
答:常用的方式有以下两种。
str.equals("")
str.length()==0
一、基本知识
String str1 = null;
str1引用为空,它没有地址,它是一个没有被实例化的对象
String str2 = "";
str2引用为空字符串,它有地址,它是被实例化的对象,值为空而已。
二、判断是否为空
1、如果是string对象是null,用 == 来判断,否则会抛出异常
java.lang.NullPointerException
2、如果是空字符串,用来equals() 判断,
str.equals("")
“ == ”操作在对String这种引用数据类型来说,比较的是地址
“equals()"判断的是内容
3、综合来说,判断字符串是否为空
if (context != null && !context.trim().equals(""))
trim():返回一个去掉前后空格之后的 字符串(leading and trailing whitespace)
三、判断是否相等
str1.equals(str2)
“ == ”操作在对String这种引用数据类型来说,比较的是地址
“equals()"判断的是内容
比较的是内容