1、Collection和Collections
Collection是接口,所有Java集合类(除实现Map接口的类)都实现了Collection接口。它定义了实现该接口的集合类中数据的操作和行为,所有直接或间接实现该接口的类都应该最少有两个构造函数:其中没有参数的一个用来构造一个空集合,另一个用来构造拥有不同集合类型但元素相同的集合。
Collections是类,包含了许多操作集合类的静态函数。
那么,如何将数组对象转化为List对象呢?可以使用以下代码:
Collections.addAll(arraylist, array);
另外附Java集合类关系图:(注意图中有一点错误:Map接口并没有继承Collection接口)
2、HashMap的遍历
在Java中有多种遍历HashMAp的方法。让我们回顾一下最常见的方法和它们各自的优缺点。由于所有的Map都实现了Map接口,所以接下来方法适用于所有Map(如:HaspMap,TreeMap,LinkedMap,HashTable,etc)
1)使用For-Each迭代entries
这是最常见的方法,并在大多数情况下更可取的。当你在循环中需要使用Map的键和值时,就可以使用这个方法:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(Map.Entry<Integer, Integer> entry : map.entrySet()){
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue())
}
注意:For-Each循环是Java5新引入的,所以只能在Java5以上的版本中使用。如果你遍历的map是null的话,For-Each循环会抛出NullPointerException异常,所以在遍历之前你应该判断是否为空引用。
2)使用For-Each迭代keys和values
如果你只需要用到map的keys或values时,你可以遍历KeySet或者values代替entrySet:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//iterating over keys only
for (Integer key : map.keySet()) {
System.out.println("Key = " + key);
}
//iterating over values only
for (Integer value : map.values()) {
System.out.println("Value = " + value);
}
这个方法比entrySet迭代具有轻微的性能优势(大约快10%)并且代码更简洁。
3)使用Iterator迭代
使用泛型:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
不适用泛型:
Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
Integer key = (Integer)entry.getKey();
Integer value = (Integer)entry.getValue();
System.out.println("Key = " + key + ", Value = " + value);
}
你可以使用同样的技术迭代keyset或者values。
这个似乎有点多余但它具有自己的优势。首先,它是遍历老java版本map的唯一方法。另外一个重要的特性是可以让你在迭代的时候从map中删除entries的(通过调用iterator.remover())唯一方法.如果你试图在For-Each迭代的时候删除entries,你将会得到unpredictable resultes 异常。
从性能方法看,这个方法等价于使用For-Each迭代。
3、如何判断数组中包含指定的值?
1)使用Arrays.asList(...).contains(...);
2)自己写查找逻辑:
a)对于无序数组:
public static boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
b
)有序数组可以用二分查找(Arrays包含数组相关操作):
public static boolean useArraysBinarySearch(String[] arr, String targetValue) {
int a = Arrays.binarySearch(arr, targetValue);
if(a >= 0)
return true;
else
return false;
}
4、从多重循环中跳出(使用break+label)
public class Test {
public static void main(String[] args) {
outerloop:
for (int i=0; i < 5; i++) {
for (int j=0; j < 5; j++) {
if (i * j > 6) {
System.out.println("Breaking");
break outerloop;
}
System.out.println(i + " " + j);
}
}
System.out.println("Done");
}
}
5、分割String字符串
使用String#split方法:
String string = "004-034556";
String[] parts = string.split("-");
String part1 = parts[0]; // 004
String part2 = parts[1]; // 034556
需要注意的是,该方法的参数是个正则表达式,要注意对某些字符做转码。例如,.在正则表达式中表示任意字符,因此,如果你要通过.号做分割,需要这样写,split("\\.")或者split(Pattern.quote("."))。如果只是为了验证字符串中是否包含某个字符,使用String#contains方法就行。注意该方法的参数,不是正则表达式。
6、Java中对比String对象
- 使用“==”:对应的是指针相等,也就是他们是否为同一个对象
- 使用equals()方法:对应的是值相等,也就是逻辑相等
如果想比较String字符串内容是否相同,应该使用equals()方法。
/值是相等的
new String("test").equals("test") // --> true
// ... 值相等,但不是同个对象(指向不同的地址空间)
new String("test") == "test" // --> false
// ... 同上
new String("test") == new String("test") // --> false
// 这个返回true,是因为这种写法属于字符串字面量,编译器会维护一个常量池,相同的字面量,都会指向相同的一个对象
"test" == "test" // --> true
因此, 值的对比,一般都是用equals方法。字符串字面量之间的对比,也可以用==(大家知其所以然即可,但没必要用==)
下面多举个字符串字面量的例子,下面代码中,前四个对比,返回true,最后一个返回false。
public static final String test1 = "test";
public static final String test2 = "test";
@Test
public void test() {
String test3 = "test";
String test = "test";
System.out.println(test3.equals(test));
System.out.println(test3 == test);
System.out.println(test1.equals(test2));
System.out.println(test1 == test2);
System.out.println(test1 == new String("test"));
}
其他:
- 如果你重写了equal方法,记得相对应地修改hashcode方法,否则将会违反这两个方法的对等关系,如果两个对象是相等(equal)的,那么两个对象调用hashCode必须产生相同的整数结果,即:equal为true,hashCode必须为true,equal为false,hashCode也必须为false。
- 如果要忽略大小写进行对比,可以用equalsIgnoreCase()方法。
- Hashtable是同步的,加了synchronized锁,而HashMap不是。没有加synchronized锁的对象,性能通常比加了synchronized锁的对象要更好一些,因此,如果是非多线程程序,不需要考虑锁、同步等问题,那么使用HashMap更好。
- Hashtable不允许空键和空值,而HashMap允许。
- HashMap有个子类叫做LinkedHashMap,迭代时是有序的(按照插入时的顺序)。如果有需要,可以向上塑性转化为HashMap对象,而HashTable不行。
8、最近在研究音频编码格式时,看到许多关于数据大小的编码格式为:倒着写入的十六进制。可以使用以下方式将十六进制数据大小与十进制数据大小相互转换:
- 倒置十六进制转十进制:
int len = ((0xff & header[0]) << 24 |(0xff & header[1]) << 16 | (0xff & header[2]) << 8 | (0xff & header[3]));
- 十进制数据写入头文件(转为倒置十六进制):
int totalDataLen = 1024;
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
9、a = a + b 与 a += b 的区别:
对于同类型的a、b来说,两者没什么区别,但从编译角度看,a += b效率更高。
对于不同类型的a、b来说,由于高精度类型数值赋值给低精度类型时必须进行显示的强制类型转化,所以a = a + b可能会出现编译错误。而a += b中" += "运算符结合了强制类型转化操作,因此不会出现编译错误。