Java学习 String类
1.1 API文档的使用
我们java是开源的,所以又很多类看不懂可以看底层代码。例如:
@Test
public void test1(){
String str = "asdfasdf";
char a = str.charAt(6);
System.out.println(a);
}
此时我们charAt究竟作用是什么,参数代表什么意思 返回值代表什么意思我们无从得之,所以可以ctrl+左键查看代码
/**
* Returns the {@code char} value at the
* specified index. An index ranges from {@code 0} to
* {@code length() - 1}. The first {@code char} value of the sequence
* is at index {@code 0}, the next at index {@code 1},
* and so on, as for array indexing.
*
* <p>If the {@code char} value specified by the index is a
* <a href="Character.html#unicode">surrogate</a>, the surrogate
* value is returned.
*
* @param index the index of the {@code char} value.
* @return the {@code char} value at the specified index of this string.
* The first {@code char} value is at index {@code 0}.
* @exception IndexOutOfBoundsException if the {@code index}
* argument is negative or not less than the length of this
* string.
*/
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
这个方法很慢,所以就有了API(Application Programming Interface,应用程序接口)文档,他有中文版 而且所有类都包含了,我们看起来就方便了
首先打开文档
我们发现其将java所有的类都罗列出来了
java中的常用包: lang java的语言核心包 io java的输入输出流 math 数学工具包
net java的网络包 sql java中数据库操作相关的包 util java的工具包
我们要使用得类是String 所以通过索引搜索String
A 继承关系
public final class String
extends Object
implements Serializable, Comparable<String>, CharSequence
B String的简介
C 构造方法
D 静态方法
E 接口方法
所以实现某个功能可以去百度
1.2 String练习题
1 有一个字符串 "hello world" ,请获取其第三个子字符
2 有一个字符串 "hello world" ,请判断 lo首次出现的索引位置
3 有一个字符串 " hello world " ,请去处其空格
4 有一个字符串 "hello world" , 请将 world 换成 java
5 有一个字符串 "hello world" , 是否包含 ld ?
6 有一个字符串 "hello world" , 请将其转换成全大写
7 有一个字符串 "hello world" , 请获取字符串整体的长度
8 有一个字符串 "hello world" , 判断是否为空
9 有一个字符串 "123,356,5873245" , 从其中将 356 提出出来
10 有一个字符串 "hello world" 请和两一个字符串比较是否完全一致 "hello worLD"
11 有一个 整数20 ,请将其转换成 String类型
12 有一个字符串 "666" 请将其转换成 int类型
public class JavaTest {
@Test
public void test1(){
String str = "hello world";
/*获取指定范围内的子字符 前闭后开*/
String a1 = str.substring(3,4);
System.out.println(a1);
/*获取指定索引位置的子字符 */
char a2 = str.charAt(3);
System.out.println(a2);
}
@Test
public void test2(){
String str = "hello world";
/*判断某个字符串在 指定字符串中首次出现索引位置 如果没有则返回-1*/
int index = str.indexOf("lo");
System.out.println(index);
}
@Test
public void test3(){
String str = " hello world ";
/*去掉首尾空格 返回一个新字符串 老字符串没变*/
String a3 = str.trim();
System.out.println(a3);
System.out.println(str);
}
@Test
public void test4(){
String str = " hello world ";
String a4 = str.replace("world","java");
System.out.println(a4);
}
@Test
public void test5(){
String str = " hello world ";
boolean a5 = str.contains("dl");
System.out.println(a5);
}
@Test
public void test6(){
String str = " hello nihao shijie ";
String a6 = str.toUpperCase();
System.out.println(a6);
}
@Test
public void test7(){
String str = " hello nihao shijie ";
int a6 = str.length();
System.out.println(a6);
}
@Test
public void test8(){
String str = "";
boolean a6 = str.isEmpty();
System.out.println(a6);
}
@Test
public void test9(){
String str = "123,356,5873245";
// [123, 356, 5873245]
String[] arr = str.split("5");
System.out.println(Arrays.toString(arr));
}
@Test
public void test10(){
String str = "123,356,5873245";
String str1 = "hello world";
boolean a6 = str.equals(str1);
System.out.println(a6);
}
@Test
public void test11(){
int a = 20;
/* "20" */
String b = String.valueOf(a);
System.out.println(b);
}
@Test
public void test12(){
String str = "666";
int a = Integer.parseInt(str);
System.out.println(a);
}
}
1.3 String底层原理
要想看清楚一个类的底层原理 就要从他的构造函数开始看起。
String str = new String();
查看其底层
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.value = "".value;
}
所以我们就得到了一个结论 当前类有一个 value的成员变量。所以我们就继续查看value 的真是面貌
/** The value is used for character storage. */
private final char value[];
所以我们得到一个结论: String 的底层就是一个char数组
例如:
我们写代码的时候 String str = "hello";
底层相当于这样写的 char[] value = {'h' , 'e' , 'l' ,'l' , 'o'};
1 当我们调用 char a1 = str.charAt(3);获取指定索引位置的子字符 其实在底层就是 从数组中获取指定索引位置的子字符
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
2 当我们调用 int len = str.length();获取字符串的长度 其实在底层就是 返回value数组的长度
public int length() {
return value.length;
}
3 当我们调用 boolean a2 = str.isEmpty(); 判断字符串是否为kong 其实底层就是 判断数组的长度是否为0
public boolean isEmpty() {
return value.length == 0;
}
4 当我们调用 boolean a4 = str.equals("asd"); 判断俩字符串是否一样 其实底层就是 判断倆数组是否完全一样
public boolean equals(Object anObject) {
// 判断引用地址是否一样 如果一样 则证明就是同一个对象 直接返回true
if (this == anObject) {
return true;
}
// 判断 参数是不是字符串类型 如果不是字符串 返回 false
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
// 判断两个数组的长度是否一致 如果不一致则返回false
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
// 判断每个索引位置的子字符是否一致 如果不一致则返回false
if (v1[i] != v2[i])
return false;
i++;
}
// 如果循环结束还没有return 证明都一样 则返回true
return true;
}
}
return false;
}
1.4 String的面试题
1 String能否被继承?为什么?
2 String有么有length属性?数组有没有length属性?
String只有 length() 函数,数组没有length函数但是有 length属性 arr.length
3 以下代码输出什么?
String temp = "hello";
String a1 = "helloworld";
String a2 = "hello" + "world";
String a3 = temp+"world";
System.out.println(a1 == a2); // true
System.out.println(a1 == a3); // false
底层是这个样子的:
a1 是 "helloworld"; a2 是 "helloworld"; 因为a2的源码是 "hello" + "world"; 编译的时候 编译器一看"hello" + "world"; 那不就是"helloworld"; 所以 a2编译成字节码之后 直接就是 "helloworld"; 所以 a1 == a2 就是 true
a3是temp+"world"; 编译之后 变成了这个样子
String temp = "hello";
String a1 = "helloworld";
String a2 = "helloworld";
String a3 = (new StringBuilder()).append(temp).append("world").toString();
System.out.println(a1 == a2);
System.out.println(a1 == a3);
所以 a1的引用是 helloworld的内存地址 a3的引用是StringBuilder对象的地址 所以 a1 == a3 是false
4 以下代码输出什么? == 和 equals的 区别?
String str1 = new String("123");
String str2 = new String("123");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
== 判断的是引用地址是否相同, equals的情况就不确定了 得看当前类是否重写了equals。如果没有重写 则调用父类Object的equals
public boolean equals(Object obj) {
return (this == obj);
}
Object的equals底层还是用 == 进行判断。但是当前str1 是String类型 String重写了父类的equals 变成了判断内容是否相同
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
5 请问以下代码分别创建了几个对象
String a1 = "123";
String a2 = new String("445");
a1 创建了 1 个或 0 个
因为 a1的形式子字符常量,所以首先先要去常量池中找是否有 123 ,如果有则直接引用,就是创建了0个。如果没有则创建并引用 所以是一个
a2 创建了 1 个或 2 个
因为 a2 是引用堆区的对象 ,new String 肯定要在堆区造一个String对象,再看 445 在常量池中有没有
1.5 可变字符串
String 是一个 不可变字符串,例如 "a"+"b" 需要在内存中创建一个 a 在创建一个 b 再创建一个 ab
所以String在拼接的时候特别耗性能
例如:
public static String toMyString(int[] arr){
String str = "[";
for (int i = 0; i < arr.length; i++) {
str += arr[i];
if(i == arr.length-1){
str += "]";
}else{
str += ",";
}
}
return str;
}
所以我们在拼接的时候需要使用可变字符串
StringBuilder sb = new StringBuilder();
sb.append("123").append("465");
StringBuffer sb = new StringBuffer();
sb.append("123").append("456");
所以Arrays 底层就是用 StringBuilder 拼接
public static String toString(long[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(a[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}