摘自《疯狂java讲义》
BigDecimal问题
当使用new BigDecimal(double val)构造器时会有计算不准确问题,如果使用BigDecimal(String val)构造器结果是可预知的,如果必须使用double浮点数作为BigDecimal构造器的参数们可以使用BigDecimal.valueOf(double value)
静态方法来创建BigDecimal对象。
BigDecimal.valueOf(double value)
源码
public static BigDecimal valueOf(double val) {
if (Double.isInfinite(val) || Double.isNaN(val)) {
throw new NumberFormatException("Infinity or NaN: " + val);
}
return new BigDecimal(Double.toString(val));
}
最后还是调用的 new BigDecimal(String value)
foreach该循环中迭代的变量不是集合元素本身,系统只是依次把集合元素的值赋给迭代变量
HashSet判断两个元素相等的机制
HashSet判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等
当把一个对象放入HashSet中时,如果需要重写该对象对应类的equals方法,则也应该重写hashCode方法,规则是:如果两个对象都通过equals方法比较返回true,则这两个hashCode值也相同
若两个对象的hashCode方法返回的值相同,但是通过equals方法比较返回的是false。由于hashCode值相同,HashSet将试图把他保存在同一个位置,但不行,所以实际上会在这个位置用链式结构来保存多个对象,而HashSet访问集合元素时,也是根据元素的hashCode值来快速定位的,如果HashSet中两个以上元素具有相同的HashCode值,将会导致性能下降
如果向HashSet中添加一个可变对象,后面的程序修改了该可变对象的实例变量,则可能导致他与集合中的其他元素相同(即两个对象的equals方法返回true,两个hashCode相等)
eg
public class Test{
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new R(5));
hs.add(new R(-3));
hs.add(new R(9));
hs.add(new R(-2));
System.out.println(hs);
Iterator it = hs.iterator();
R first = (R) it.next();
first.count = -3;
System.out.println(hs);
hs.remove(new R(-3));
System.out.println(hs);
System.out.println(hs.contains(new R(-3)));
System.out.println(hs.contains(new R(-2)));
}
static class R{
int count;
public R(int count){
this.count = count;
}
@Override
public String toString() {
return count+"";
}
@Override
public boolean equals(Object obj) {
if(obj == this){
return true;
}
if(obj != null && obj.getClass() == R.class){
return this.count == count;
}
return false;
}
@Override
public int hashCode() {
return count;
}
}
}
输出结果:
[-2, -3, 5, 9]
[-3, -3, 5, 9]
[-3, 5, 9]
false
true
本例当试图删除count=-3的R对象时,HashSet会计算出该对象的equals方法进行比较,如果相等则删除该对象(HashSet实际上只有第二个元素满足条件,第一个元素实际上保存在count=-2的位置上),所以删除第二个元素。
TreeSet
自然排序,TreeSet会调用集合元素的compareTo方法来比较元素之间的大小关系,然后将集合元素按升序排序。
向TreeSet集合中添加元素时,只有第一个元素无需实现Comparable接口,后面添加的所有元素必须实现Comparable接口
如果向往TreeSet能够正常工作,TreeSet只能添加同一种类型的对象
当需要把一个对象放入TreeSet中,重写该对象对应的类的equals方法时,应保证该方法与compareTo方法有一致的结果
eg
public class Test{
public static void main(String[] args)
{
TreeSet hs = new TreeSet();
hs.add(new R(5));
hs.add(new R(-3));
hs.add(new R(9));
hs.add(new R(-2));
System.out.println(hs);
Iterator it = hs.iterator();
R first = (R) it.next();
first.count = 20;
R last = (R) hs.last();
last.count = -2;
System.out.println(hs);
System.out.println(hs.remove(new R(-2)));
System.out.println(hs);
System.out.println(hs.remove(new R(5)));
System.out.println(hs);
System.out.println(hs.remove(new R(-2)));
System.out.println(hs);
System.out.println(hs.remove(new R(-2)));
System.out.println(hs);
}
static class R implements Comparable{
int count;
public R(int count){
this.count = count;
}
@Override
public String toString() {
return count+"";
}
@Override
public boolean equals(Object obj) {
if(obj == this){
return true;
}
if(obj != null && obj.getClass() == R.class){
return this.count == count;
}
return false;
}
@Override
public int hashCode() {
return count;
}
@Override
public int compareTo(Object o) {
R r = (R) o;
return count > r.count?1:count<r.count?-1:0;
}
}
}
输出结果:
[-3, -2, 5, 9]
[20, -2, 5, -2]
false
[20, -2, 5, -2]
true
[20, -2, -2]
true
[20, -2]
true
[20]
一旦改变了TreeSet集合里的可变元素的实例变量,当再试删除该对象时,TreeSet也会删除失败(甚至集合中原有的,实例变量没有修改后元素相等的元素也无法删除)
当执行完hs.remove(new R(5))
后,TreeSet会对集合中的元素重新索引(不是重新排序),接下来就可以删除TreeSet中的所有元素了,包括那些被修改过的实例变量元素
TreeSet判断两个元素相等的标准是:通过comparator比较两个元素返回了0;
List删除机制
public class Test{
public static void main(String[] args)
{
List list = new ArrayList();
list.add("1111");
list.add("22222");
list.add("3333");
System.out.println(list);
list.remove(new A());
System.out.println(list);
list.remove(new A());
System.out.println(list);
}
static class A{
@Override
public boolean equals(Object obj) {
return true;
}
}
}
输出结果:
[1111, 22222, 3333]
[22222, 3333]
[3333]
由上述可知,List将会调用该A对象的equals方法依次与集合元素进行比较,如果该equals方法以某个集合元素为参数时返回true,List将会删除该元素
固定长度List
Arrays工具类中的asList(Object…a)方法,该方法可以把一个数组或者指定个数的对象换成一个List集合,这个List集合既不是ArrayList实现类,也不是Vector实现类,而是Arrays的内部类ArrayList的实例,其实一个固定长度的List集合,程序只能遍历访问集合里的元素,不可增加删除元素
Map
Map的Key不允许重复,即同一个Map对象的任何两个Key通过equals方法比较总是返回false
HashMap的可以是null,但是还能存在一个
eg:
public class Test{
public static void main(String[] args)
{
HashMap hm = new HashMap();
hm.put(null,null);
System.out.print(hm);
}
}
输出结果:
{null=null}
与HashSet类似,如果使用可变对象作为HashMap的key,并且程序修改了key对象则会出现与HashSet类似额问题