字符串创建于存储机制
字符串的声明和初始化的两种情形:
1. str1 = “abc”; str2 = “abc”;在JVM中存在着一个常量池,其中保存着很多的String对象,并且这些对象可以共享。因此此处的str1和str2是引用同一个常量池中的对象。由于String是不可变类,因此这种共享并不会造成混乱。
2. str1 = new String(“abc”); str2 = new String(“abc”); ,创建两个内容相同的字符串对象,他们的地址是不同的,因为new一定会创建对象。
无论是使用new还是直接赋值的创建String对象,其过程都是先检查常量池中是否已经有了这个字符串常量。对于第一种方法,如果常量池中存在,那么直接将其引用返回即可;对于第二种形式,如果存在,那么在堆中申请个内存并创建一个新的对象,如果不存在,那么先会在常量池中创建一个对象,然后再new一个对象(也就是String str = new String(“hello”); 实际上可能创建一个对象,也可能创建了两个对象)。
== 与equals以及hashCode的对比
- == 比较的是两个变量对应的内存中存储的值是否相等。因此对于基本类型,比如int型,那么就相当于值得比较,而对于引用类型,比较的实际效果就相当于是比较两个变量所引用的对象是否是同一个对象(因此也会出现两个不同对象,但是其值是相同的,但是 == 返回false)而不考虑两个变量所引用对象的内容是否是相等的,如果呀比较引用类型变量的内容是否是相等的,还需要使用equals方法,并且是重载后的equals方法。
- equals方法是Object提供的方法,默认返回的是两个对象 == 后的结果,所以一般该方法需要进行重载,否则是没有什么意义的。通过覆盖来实现比较两个引用对象的内容是否是相等的。
- hashCode()方法也是继承自Object,通常也是用来比较两个对象是否相等。Object的hashCode()方法是一个native方法,该方法返回的是i对象在内存中地址转换为的一个int值。
一般在覆盖equals()方法的时候也是建议覆盖hashCode()方法的,否则可能导致所建立的类在基于散列的集合类(hashMap hashSet等)之间不能正常运行。
equals和hashCode的重载约定如下:
1. 如果x.equals(y)返回true,那么x和y的hashCode方法的返回值必须是一样的。
2. 如果x.equals(y)返回false,那么x和y的hashCode方法的返回值可能相等也可能不相等
3. 如果x和y的hashCode返回值不相等,那么其equals必定不相等
4. 如果x和y的hashCode返回值相等,那么其equals可能相等也可能不相等
对于第一条最为重要,也很容易被忽略,对于equals和hashCode都是默认的情况下,因为前者是比较内存值,而后者是直接返回内存地址相关的一个int值,因此默认情况下,是一定满足规则1的。被忽略的倾向常常表现在重写了equals()但是却没有重写hashCode()或者hashCode()设计的不满足1.因此在新建一个类,如果重写equals,那么一定记得重写满足1的hashCode()。
String StringBuffer StringBuilder StringTokenizer
Java 中常用的对字符串进行操作的类就是Character String StringBuffer StringBuilder和StringTokenizer。Character对单个字符操作,String对字符串操作的不可变类,StringBuffer和StringBuilder是对字符串操作的可变类。
StringBuilder和StringBuffer类似,但是区别在于StringBuffer是线程安全的,而StringBuilder不是线程安全的。效率上面StringBuilder是最高的,其次是线程安全的StringBuffer,最后是String类。应该根据自己的实际使用场景选择合适的类型。
Java中的数组及初始化方法
Java中除了基本数据类型之外,其他都可以看做是对象,那么数组是不是对象呢?在Java中的数组,不仅具有自己的属性,也具有自己的方法。这些特点符合对象的标准,因此在Java中数组可以看做是对象,还可以使用instanceof进行类型的判断。
例如:String[] ss = {“ac” , “bc”}; if(ss instanceof String[]) {}
数组的初始化方法:
对于一维数组,声明方式:
1. type array[];
2. type[] array;
注意:1.Java中数组被创建的时候会根据其数据类型进行值得初始化; 2.Java中在定义数组的时候并不会为其分配空间,因此[]中不需要指定长度,因此在使用前需要指定长度,如array = new type[5];
初始化方法:
1. int[] array = new type[5];
2. int[] array = {1, 2, 3};
或者:
1. int[] array; array = new int[5]; // 申请空间并初始化为0
2. int array[]; array = new int[]{1, 2, 3, 4, 5};
二维数组的声明和初始化:
1. type arrays[][];
2. type[][] arrays;
3. type[] array[];
列表化的初始化: type arrays[][] = {{a11, a12, a13}, {a21, a22, a23}, {a31, a32, a33}};
new关键字申请空间: type arrays[][] = new type[row][col];
注意:
Java语言中,二维数组的第二维可以不相等。例如:
1. int array[][] = {{1, 2}, {3, 4, 5}};
2. int array[][] = new int[2][]; array[0] = new int[2]; array[1] = new int[3];
之所以这么任性是因为在遍历二维数组的时候,可以不根据固定的行列下标,而是根据维度的length属性来实现遍历的。注意length属性和length()方法是不一样的,前者是数组的维数属性,后者多是字符串的长度获取方法