Java编程思想 -- 容器深入理解

可选操作

简单说就是抽象类的的某些派生类实现里,或者接口的某个实现类里面,某个方法可能是无意义的,调用该方法会抛出一个异常。例如在collection的某些实现类里,里面的元素可能都是只读的,那么add这个接口是无意义的,调用会抛出UnspportedOperationException异常。

例子:

代码:

public class UnsupportedTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A B C D E F G H I J".split(" "));
        test("modifiable Copy", new ArrayList<String>(list));
        test("Arrays.asList", list);
        test("ummodifiable Copy", Collections.unmodifiableList(
                new ArrayList<String>(list)));

    }

    static void test(String msg, List<String> list){
        System.out.println("--- " + msg + " ---");
        Collection<String> subList = list.subList(0, list.size() / 2);

        //copy of the sublist
        Collection<String> c = new ArrayList<String>(subList);
        try {
            list.retainAll(c);
        } catch (Exception e) {
            System.out.println("retainAll(): " + e);
        }
        try {
            list.remove(c);
        } catch (Exception e) {
            System.out.println("remove(): " + e);
        }
        try {
            list.clear();
        } catch (Exception e) {
            System.out.println("clear(): " + e);
        }
        try {
            list.add("X");
        } catch (Exception e) {
            System.out.println("add(): " + e);
        }
        try {
            list.addAll(c);
        } catch (Exception e) {
            System.out.println("addAll(): " + e);
        }
        try {
            list.remove(list.get(0));
        } catch (Exception e) {
            System.out.println("remove(): " + e);
        }
        try {
            //Collection接口没有set()方法
            list.set(0, "chuqin");
        } catch (Exception e) {
            System.out.println("set(): " + e);
        }

    }
}

结果

--- modifiable Copy ---
--- Arrays.asList ---
retainAll(): java.lang.UnsupportedOperationException
clear(): java.lang.UnsupportedOperationException
add(): java.lang.UnsupportedOperationException
addAll(): java.lang.UnsupportedOperationException
remove(): java.lang.UnsupportedOperationException
--- ummodifiable Copy ---
retainAll(): java.lang.UnsupportedOperationException
remove(): java.lang.UnsupportedOperationException
clear(): java.lang.UnsupportedOperationException
add(): java.lang.UnsupportedOperationException
addAll(): java.lang.UnsupportedOperationException
remove(): java.lang.UnsupportedOperationException
set(): java.lang.UnsupportedOperationException

总结:
UnsupportedOperationException必须是一种罕见的事件。即,对于大多数类来说,所有操作都可以工作,只有在特例中才会有未获得支持的操作。在Java容器库中确实如此,因为你在99%的时间使用的容器类,如ArrayList,LinkedList,HashSet, HashMap等等,都支持所有的操作。

正确覆盖hashCode()和equals()方法

没有正确覆盖hashCode()和equals()方法,Hash类的容器不能正常工作。

例一,没有正确覆盖hashCode()和equals()方法

代码

public class Test {
    public static void main(String[] args) {
        Set<People> set = new HashSet<People>();
        set.add(new People("chuqin"));
        /*
         * 意图: 为Set容器添加相同的元素,容器不会产生任何变化
         * 结果:People类没有正确覆盖hashCode()和equals()方法,
         * 所以new People("chuqin")产生的对象还是添加到了Set集合,这个不符合逻辑
         */
        set.add(new People("chuqin"));
        set.add(new People("afang"));
        System.out.println(set);
    }
}


class People{
    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public People(String name) {
        super();
        this.name = name;
    }

    public People() {
        super();
    }

    @Override
    public String toString() {
        return "内存地址:" + super.toString() + ", name=" + name;
    }

}

结果:

[内存地址:容器.正确覆盖equal方法.People@7852e922, name=afang, 内存地址:容器.正确覆盖equal方法.People@15db9742, name=chuqin, 内存地址:容器.正确覆盖equal方法.People@6d06d69c, name=chuqin]

例二,正确覆盖hashCode()和equals()方法

代码:

public class Test {
    public static void main(String[] args) {
        Set<People> set = new HashSet<People>();
        set.add(new People("chuqin"));
        set.add(new People("chuqin"));
        set.add(new People("afang"));
        /*
         * People类正确覆盖hashCode()和equals()方法,
         * 所以最终set集合里面只有2个对象。
         */
        System.out.println(set);
    }
}


class People{
    String name;

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        People other = (People) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public People(String name) {
        super();
        this.name = name;
    }

    public People() {
        super();
    }




    @Override
    public String toString() {
        return "内存地址:" + super.toString() + ", name=" + name;
    }

}

结果:

[内存地址:容器.正确覆盖equal方法.People@586bfb4, name=afang, 内存地址:容器.正确覆盖equal方法.People@aee036c5, name=chuqin]

覆盖equals()原则

  • 自反性。对于任何非null的引用值x,x.equals(x)必须返回true
  • 对称性。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
  • 传递性。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)则必须返回true。
  • 一致性。对于任何非null的引用值x、y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一直返回true,或者一致返回false。
  • 对于任何非null的引用值x,x.equals(null)必须返回false

覆盖hashCode()原则

  • 无论何时,对同一个对象调用hashCode()返回值一定相同。
  • 不应该依赖于唯一性的对象信息。尤其是使用this(内存地址)。
  • hashCode()不必返回独一无二的值,更应该注重生成速度。
  • 散列码应该均匀分布,否则hash类的容器速度会变慢。

代码示例

public class Test {
    private byte b;
    private char c;
    private int i;
    private long l;
    private float f;
    private double d;
    private String s;
    private Integer integer;
    private Date date;


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + b;
        result = prime * result + c;
        long temp;
        temp = Double.doubleToLongBits(d);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        result = prime * result + ((date == null) ? 0 : date.hashCode());
        result = prime * result + Float.floatToIntBits(f);
        result = prime * result + i;
        result = prime * result + ((integer == null) ? 0 : integer.hashCode());
        result = prime * result + (int) (l ^ (l >>> 32));
        result = prime * result + ((s == null) ? 0 : s.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Test other = (Test) obj;
        if (b != other.b)
            return false;
        if (c != other.c)
            return false;
        if (Double.doubleToLongBits(d) != Double.doubleToLongBits(other.d))
            return false;
        if (date == null) {
            if (other.date != null)
                return false;
        } else if (!date.equals(other.date))
            return false;
        if (Float.floatToIntBits(f) != Float.floatToIntBits(other.f))
            return false;
        if (i != other.i)
            return false;
        if (integer == null) {
            if (other.integer != null)
                return false;
        } else if (!integer.equals(other.integer))
            return false;
        if (l != other.l)
            return false;
        if (s == null) {
            if (other.s != null)
                return false;
        } else if (!s.equals(other.s))
            return false;
        return true;
    }


}

Map

(1)HashMap
Map基于拉链法实现。元素无序的,但是查询速度最快。
(2)LinkedHashMap
类似于HashMap。但是迭代速度更快。取得“键值对”的顺序是其插入次序或者是最近最少使用(LRU)的次序。只比HashMap慢一点;而在迭代速度更快,因为它使用链表维护内部次序。
(3)TreeMap
基于红黑树的实现。查看“键”或者“键值对”时,他们会被排序(次序有Comparable或者Comparator决定)。TreeMap的特点在于,所得到的结果是进过排序的。TreeMap是以为带有subMap()方法的Map,它返回一个子树。
(4)WeakHashMap
弱键映射,允许释放映射所指向的对象;这是为了解决某类特殊问题而设计的。如果映射之外没有引用指向某个“键”,则此“键”可以被垃圾收集装置回收。
(5)ConcurrentHashMap
一种线程安全的Map,它不涉及同步加锁。
(6)IdentityHashMap
使用==代替equals()对“键”进行散列映射。

Colleactions中的静态方法

生成只读视图

调用容器的unmodifiableXXX方法。

生成同步视图

调用容器的synchronizedXXX方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值