记录Java的常用技巧

Top

  1. Java中没有逗号运算符
  2. new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

关于char

C语言里面,char类型是1个字节的,用来表示ASCII字符,ASCII字符有128个,这样7个bit就能表示了,最高位被空了出来,可以将其做为符号位,这样设计的char就是带符号的(相当与1字节的int),当然也可以设计成不带符号的,即最高位空为0,或做其他用途,这是由编译器设计决定的,有的编译器会提供选项,选择char的具体实现

目前测试了GCCVS2010上都默认是signed char

以前都没在意,Java的字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。其中一个char类型固定2Bytes(16bits)。

为了兼容ASCII编码,将所有ASCII字符都按顺序放在了[0-127]之间

内部匿名类

不用显式地声明,而是直接构造一个类,并生成一个该类的对象,这样类就称为匿名类

匿名类没有定义名字,构造后不能再被调用,所以在构造的时候就生成一个该类的对象

匿名类须要‘基于’其他已有的非final的类或接口,如使用java.util.Comparator接口构造内部类对象:

new java.util.Comparator<Integer>(){
    @Override
    public int compare(Integer o1, Integer o2) {
        // TODO Auto-generated method stub
        return 0;
    }
};

使用java.lang.Runnable接口的例子:

Runnable r = new Runnable(){
    @Override
    public void run() {
        // TODO Auto-generated method stub
    }
};
r.run();

小心java中的‘引用传递’

最近写递归程序经常要回朔变量的状态,这时候,如果变量不是Immutable的,就一定要注意要构建新对象

public void tranverse(TreeNode root, int sum, 
    ArrayList<Integer> cur, ArrayList<ArrayList<Integer>> res){
    if(root!=null){
        sum -= root.val;
        cur.add(root.val);
        if(root.left==null && root.right==null && sum==0){
            // find one path
            res.add(new ArrayList<Integer>(cur)); // WARN: remeber to construct new object
        } else {
            tranverse(root.left, sum, cur, res);
            tranverse(root.right, sum, cur, res);
        }
        cur.remove(cur.size()-1); // WARN: 回朔对象状态
    }
}

自动装箱技术和容器类

先看测试代码

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(2); // 自动装箱
// list.remove(2); //出错 
list.remove(new Integer(2)); // OK

ArrayList中的remove方法有两个重载方法

//Removes the first occurrence of the specified element from this list, if it is present.
public boolean remove(Object o);

//Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).
public E remove(int index);

还有一点更像是java的陷阱:

java中有很多final和immutable类(关键是重写了equals方法),使用ArrayList的remove(object)方法时很容易弄错,还是看测试代码:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(2));
list.add(new Integer(1));
list.add(new Integer(2));
list.remove(new Integer(2)); // 假设你想删除刚add进去的2时,结果会令你意外的 ==!
System.out.println(list); // result: 1 2

测试代码中用的是Integer类,其他primitive类型的封装类也是如此,还有字符串String也有问题

问题的根源在于remove(object)方法是从头遍历,找到第一个和目标对象相同的删掉,其中比较用的对象的equals方法,Integer类的equals方法如下:

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue(); //可以看出比较的只是‘数值’
    }
    return false;
}

equals方法继承于Object类中,在Object类中,equals方法比较的是两个对象的引用的‘地址’,当且仅当两个引用只向同一个对象或都为空,该函数返回true

public boolean equals(Object obj) {
    return (this == obj);
}

额,又引用了大量源码。。。

容器排序

List

Java中没有排序的List,因为List本来就是有序了,如LinkedList是按照插入顺序排的,ArrayList固定了顺序,如果想改变顺序可以使用collections.sort(…)方法;

如果有动态排序需求,可以使用优先队列PriorityQueue,如果要求容器大小固定,可以使用TreeSet来手动实现,如果还需要元素可以重复,可以考虑使用Guava包中的相关实现

Map

eclipse中调用java的命令一般是:

/usr/local/java/jre1.7.0_07/bin/java -Xmx1500m -Dfile.encoding=UTF-8 -classpath /media/Ubuntu/wksp/eclipse_wksp/BaiduReco/bin:/media/Ubuntu/wksp/eclipse_wksp/BaiduReco/lib/commons-collections-3.2.1.jar:/media/Ubuntu/wksp/eclipse_wksp/BaiduReco/lib/commons-configuration-1.7.jar:/media/Ubuntu/wksp/eclipse_wksp/BaiduReco/lib/log4j-1.2.16.jar baidu.zjl.train.ZjlTrain

传值vs传引用

java中参数传递都可以看成值传递,primivte的参数就不用说了,一般对象引用参数的传递,相当与传递了这个引用的拷贝 备忘

public class Swap {  
  public static void main(String[] args) {  
      ObjectSample o1 = new ObjectSample("hello");  
      ObjectSample o2 = new ObjectSample("你好");  
      System.out.println("before swap o1:"+o1.getTitle()+" o2:"+o2.getTitle());  
      Swap.swapObject(o1, o2);  
      System.out.println("after swap o1:"+o1.getTitle()+" o2:"+o2.getTitle());  
  }  
  static void swapObject(ObjectSample o1, ObjectSample o2){  
      ObjectSample temp = new ObjectSample("temp");  
      temp = o1;  
      o1 = o2;  
      o2 = temp;  
  }  
}  

class ObjectSample{  
  private String title;  
    
  ObjectSample(String title){  
      this.title = title;  
  }  
    
  public String getTitle(){  
      return title;  
  }  
} 

判断中文字符

private static final boolean isChinese(char c) {
    Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
    if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
        || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
        || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
        || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
        || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
        return true;
    }
    return false;
    }

    public static final boolean containChinese(String strName) {
    char[] ch = strName.toCharArray();
    for (int i = 0; i < ch.length; i++) {
        char c = ch[i];
        if (isChinese(c)) {
        return true;
        }
    }
    return false;
}
TOP