首页 > 代码库 > java集合(一)

java集合(一)

 

 1、关于hashCodeequals的处理

 1.1为什么在重写了equals()方法之后也必须重写hashCode()方法

 java中,所有的对象都是继承于object类,object类有两个方法equals,hashCode.

 1)在没有重写equals方法,我们的类是继承了object的equals方法,object比较的                       是两个对象的内存地址,如果new了两个对象内存地址肯定不一样:

     对于值对象,== 比较的是两个对象的值

     对于引用对象,比较的是两个对象的地址

 2)hashcode主要为散列表

  如果一个对象的equals没有被改写,那么在执行时无论调用多少次hashCode()总是   返回相同的值(对象的内部地址转化为该数值)。

如果两个对象相等(equals相等),那么对应的hashCode也相等。

两个对象不相等(equals不相等),其对应的hashCode也不相等,这种规范不是必须的(亦即两个对象不相等,其对应的hashCode可能相等)。延伸理解,hashCode相等的两个对象不一定相等(equals相等)。但是建议遵守为两个不同对象返回不同的散列码的规范(比如重写时,但是Object.hashCode()确实为不同的对象返回不同的hashCode), 这种可以提升hash tables的性能。

  

2.一般如果使用java中的map对象进行存储的时候,他会自动调用hashcode方法来比较两个对象是否相等。

1)重写equals方法时需要重写hashCode方法,主要是针对Map、Set等集合类型的使用;

   a: Map、Set等集合类型存放的对象必须是唯一的;

   b: 集合类判断两个对象是否相等,是先判断HashCode返回值是否ture,在判断equals是否返回TRUE,只有两者都返回ture,才认为该两个对象是相等的。

 2)、由于Object的hashCode返回的是对象的hash值,所以即使equals返回TRUE,集合也可能判定两个对象不等,所以必须重写hashCode方法,以保证当equals返回TRUE时,hashCode也返回Ture,这样才能使得集合中存放的对象唯一。

2.ArrayListsubList结果不可强制转换成ArrayList.

//ArrayList数组表的subList()方法截取的是同内存一个片段,

//在截取后返回新的ArrayList数组表增加、删减、排序,都会对原数组表产生影响!

//下面是源码

//    SubList(AbstractList<E> parent,

//            int offset, int fromIndex, int toIndex) {

//        this.parent = parent;

//        this.parentOffset = fromIndex;

//        this.offset = offset + fromIndex;

//        this.size = toIndex - fromIndex;

//        this.modCount = ArrayList.this.modCount;

//    }

//  public void add(int index, E e) {

//         rangeCheckForAdd(index);

//         checkForComodification();

//         parent.add(parentOffset + index, e);

//         this.modCount = parent.modCount;

//         this.size++;

//     }

//

//     public E remove(int index) {

//         rangeCheck(index);

//         checkForComodification();

//         E result = parent.remove(parentOffset + index);

//         this.modCount = parent.modCount;

//         this.size--;

//         return result;

//     }

 

    public static void main(String[] args){

        List<String> list = new ArrayList<String>();

        list.add("fei");

        list.add("long");

        list.add("feiong");

        list.add("飞天奔月");

        List<String> listSub = list.subList(1, 3);

        System.out.println("listSub"+listSub);//listSub[long, feiong]

        System.out.println("list :"+list);//list :[fei, long, feiong, 飞天奔月]

        listSub.add("hhhaahha");

        System.out.println("listSub"+listSub);//listSub[long, feiong, hhhaahha]

        System.out.println("list :"+list);//list :[fei, long, feiong, hhhaahha, 飞天奔 ]

        //listSub的第一个删除了

        //list中的同样的元素也删除了

        listSub.remove(0);

        System.out.println("listSub"+listSub);//listSub[feiong, hhhaahha]

        System.out.println("list :"+list);//list :[fei, feiong, hhhaahha, 飞天奔月]

        

        

       //父列表不能删除SubList中的首个元素了--因为offset不能更改

        //list.remove(0);

        list.remove(3);

        System.out.println("listSub"+listSub);//报出异常

}

3.使用集合转数组时,必须集合的toArray(T[] array) 传入的是类型完全一样的数组大小

    

   @Test

public void test(){

Long[] a = {1L, 2L, 3L, 4L};

 

        List<Long> list = new ArrayList<Long>();

        list.add(4L);

        list.add(5L);

        System.out.println("a" + a);//a[Ljava.lang.Long;@4ee00c09

        //当入参的a.size > list.length,在a上面修改,并且在a[list.size] == null

        a = list.toArray(a);

        System.out.println("a" + a);//a[Ljava.lang.Long;@4ee00c09

       

 

        Long[] b = {1L};

 

        //当入参的a.size < list.length,返回值是新建的一个数组

        list.toArray(b);

        System.out.println("b" + b);//b[Ljava.lang.Long;@68111f9b

        b=list.toArray(b);

        System.out.println("b" + b);//b [Ljava.lang.Long;@3c322e7d

 

}

4.使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法 (根据源码得知asList返回的是内部定义的ArrayList,它并没有实现增删改查方法)

   @SafeVarargs

    public static <T> List<T> asList(T... a) {

        return new ArrayList<>(a);

    }

 

    /**

     * @serial include

     */

    private static class ArrayList<E> extends AbstractList<E>

        implements RandomAccess, java.io.Serializable

    {

        private static final long serialVersionUID = -2764017481108945198L;

        private final E[] a;

 

        ArrayList(E[] array) {

            if (array==null)

                throw new NullPointerException();

            a = array;

        }

 

        public int size() {

            return a.length;

        }

 

        public Object[] toArray() {

            return a.clone();

        }

 

        public <T> T[] toArray(T[] a) {

            int size = size();

            if (a.length < size)

                return Arrays.copyOf(this.a, size,

                                     (Class<? extends T[]>) a.getClass());

            System.arraycopy(this.a, 0, a, 0, size);

            if (a.length > size)

                a[size] = null;

            return a;

        }

 

        public E get(int index) {

            return a[index];

        }

 

        public E set(int index, E element) {

            E oldValue = http://www.mamicode.com/a[index];

            a[index] = element;

            return oldValue;

        }

 

        public int indexOf(Object o) {

            if (o==null) {

                for (int i=0; i<a.length; i++)

                    if (a[i]==null)

                        return i;

            } else {

                for (int i=0; i<a.length; i++)

                    if (o.equals(a[i]))

                        return i;

            }

            return -1;

        }

 

        public boolean contains(Object o) {

            return indexOf(o) != -1;

        }

}

5.java 集合中泛型通配符 用了之后就不能添加 元素了 为什么?

//通配符只能出现在引用的定义中,而不能出现在创建对象中。例如:new ArrayList<?>(),这是不可以的。ArrayList<?> list = null,这是可以的。

public static  void fun(List<?> list){

//list.add(list.get(0)); 编译不通过

System.out.println("已经打印了"+list);

}

    

//1.通配符的上届: Anilmal,Cat,dog

//   

//   public static void act(List<? extends Anilmal> list) {

//    for (Anilmal anilmal : list) {

//     animal.eat();

//          list.add(new Animal("animal")); //编译不通过

//          list.add(new Bird("bird"));//编译不通过

//          list.add(new Cat("cat"));//编译不通过

//     }

//“? extends Animal”则表示通配符“?”的上界为Animal,换句话说就是,“? extends Animal”可以代表Animal或其子类,可代表不了Animal的父类(如Object),因为通配符的上界是Animal

//三个“add”操作都可能引发类型不兼容问题,而传入的参数是未知的,所以java为了保护其类型一致,禁止向List<? extends Animal>添加任意对象,不过却可以添加null,即list.add(null)是可行的  

//2.通配符的下届

//既然有了通配符的上界,自然有着通配符的下界。可以如此定义通配符的下界 List<? super Bird>,其中”Bird“就是通配符的下界   

//为了保护类型的一致性,因为“? super Bird”可以是Animal,也可以是Object或其他Bird的父类,//因无法确定其类型,也就不能往List<? super Bird>添加Bird的任意父类对象。

// 既然法无确定其父类对象,那该如何遍历List<? super Bird> ? 因为Object是所有类的根类,所//以可以用Object来遍历

 

6.for循环删除(ArrayList.remove

 

for循环的时候是不允许删除list对象的。

因为ArrayList的父类AbstractList里有个modCount的字段记录着List的总数,for循环的时候如果增加或者删除了元素,(修改不会影响),此字段会变化,那么在下次for循环的时候检查到跟之前的长度不同,此时会报ConcurrentModificationException异常。

解决办法是一般用Iterator遍历

 

java集合(一)