5 字符串与数组
5.1 字符串创建与存储机制
字符串的声明与初始化有两种方式:
1)String s1 = new String(“abc”) 使用new关键字生成新对象并赋值,使用new关键字会在堆中生成新的对象,所以地址不会相同。(下一章节会仔细讲解)
2)String s2 = “abc” String的实现采用了Flyweight的设计模式,,当创建一个字符串常量时,会首先在字符串常量池去查找是否已经被定义过了,如果被定义过了就直接获取对其引用,如果没被定义,就先创建一个对象将其放入字符串池,然后再对其进行引用。由于String是不可变类,所以一旦被创建好就不能被修改。
引申:s == null 是否与 s == " " 相同?
s == null 是一个字符串类型的引用,它不指向任何一个字符串。
s == " " 是一个字符串类型的引用,它指向一个空的字符串,因此二者不同。
public class Main {
public static void main(String[] args) {
String s = null;
String x = " ";
System.out.println(s == x);
System.out.println(s.equals(x));
}
}
结果:
false
Exception in thread “main” java.lang.NullPointerException
5.2 ==、equals 和 hashCode
1)==:运算符用来比较两个值是否相等。该运算符用于比较变量对应内存中所存储的数值是否相同。要比较两个基本类型或两个引用变量是否相等只能用 “ == ” 运算符。
如果是两个基本数据类型,可以用“ == ”来直接比较值是否相等。如果是两个引用类型,那么“ == ”此时比较的是它们的内存地址是否相同
2)equals:比较的是两个对象内容是否相同。equals方法可以被覆盖。
public class Main {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "ab" + "c";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2);//true
System.out.println(s1.equals(s2));//true
System.out.println(s1 == s3);//false
System.out.println(s1.equals(s3));//true
System.out.println(s1 == s4);//false
System.out.println(s1.equals(s4));//true
System.out.println(s2 == s3);//false
System.out.println(s2.equals(s3));//true
System.out.println(s2 == s4);//false
System.out.println(s2.equals(s4));//true
System.out.println(s3 == s4);//false
System.out.println(s3.equals(s4));//true
}
}
3)hashCode:hashCode() 方法是从Object类中继承过来的,也是比较两个对象是否相等的。它会将对象在内存中的地址转换为 int 值后再返回。如果不重写hashCode() 方法,那么任何对象的hashCode都不相等。
注:当重写 equals() 方法时也要重写 hashCode() 方法,否则就违背了 Object.hashCode 的通用规定,从而导致该类无法与所有基于散列值的集合类结合在一起正常使用。
5.3 String、StingBuffer、StringBuilder
String:String 是不可变类,底层是被 final 修饰 private final char[ ] value ,所以String一旦创建,其值就不可改变。线程安全
StringBuffer与StringBuilder:是可变的,都是继承自 AbstractStringBuilder 底层是 char[ ] value。
StringBuffer:与StringBuilder相比线程是安全的的,但是性能较低。
StringBuilder:线程不安全,但是性能较高
对于三者使用的总结:
1.操作少量的数据: 适用 String
2.单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
3.多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer
5.4 数组初始化方式
一维数组声明方式:
1)type arrayName[ ] 例: int arrayList1[] = {1, 2, 3, 4, 5};
2)type[ ] arrayName 例: int[] arrayList2 = {1, 2, 3, 4, 5};
type既可以是基本类型,也可以是类。 arrayNmae表示数组名称 [ ]表示变量类型为一维数组
数组创建后会根据数组存放的数据类型初始化成对应的值。如:int类型初始化为0,对象会初始化为null
一维数初始化的方式:
int[] a1 = new int[5];//动态创建一个包含五个整型值的数组,默认值为0
int[] a2 = {1, 2, 3, 4, 5};//声明一个数组类型并初始化
二维数组声明方式:
1)type arrayName[ ][ ] 例: int arrayList1[][] = {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}};
2)type[ ][ ] arrayName 例: int[][] arrayList2 = {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}};
3)type[ ] arrayName[ ] 例: int[] arrayList3[] = {{1, 2, 3, 4, 5}, {1, 2, 3, 4, 5}};
在声明二维数组时 [ ] 必须为空!、
二维数初始化的方式:
type arrayName[ ][ ] = {{c1,c2,c3},{d1,d2,d3,d4,d5}};
type arrayName[ ][ ] = new [ 行数 ][ 列数 ]
5.5 length属性和length() 方法
当调用一个方法传递数组时,就必须同时传递数组长度,因为在方法调用时传递的参数为数组首地址,而对数组的实际长度却无法获知,这样会导致在对数组进行访问时可能产生越界。而在Java语言中,数组提供了length属性来获取数组的长度
在Java语言中 length() 方法是针对字符串的,String 够提供了 length() 方法来计算字符串长度。
例:
public class Main {
public static void testArray(int[] arr) {
System.out.println("数组长度" + arr.length);
}
public static void testString(String s ) {
System.out.println("字符串长度" + s.length());
}
public static void main(String[] args) {
int[] arr = {1,2,3,4};
String s = "hello";
testArray(arr);
testString(s);
}
}
结果:
数组长度4
字符串长度5
除了 length 和 length() 方法外,Java还有一个计算对象大小的方法——size() 方法。该方法是针对泛型集合的,用于查看泛型中有多少个元素。
注:
此文来源于《Java程序员面试笔试宝典》一书
仅作为本人学习过程的记录
填写原创是因为找不到相关链接
如有不妥请联系本人,会立即删除
此书对于我这种小白来说非常有用,讲解详细,知识点全面,目前正在根据此书学习,陆续会记录更多知识点。