>  기사  >  Java  >  자바 개선 장(19) -----배열 2

자바 개선 장(19) -----배열 2

黄舟
黄舟원래의
2017-02-10 11:51:331011검색

이전 섹션에서는 주로 배열의 기본 개념을 소개했으며, 이번 블로그 게시물에서는 주로 배열의 다른 측면을 소개합니다.

3. 실적? 배열을 우선으로 해주세요

자바에서 일련의 데이터를 저장하는 방법은 여러 가지가 있는데, 배열보다 조작이 훨씬 편리한가요? 그런데 왜 배열을 교체하는 대신 배열을 사용해야 할까요? 배열은 효율성, 유형, 기본 유형을 유지하는 능력이라는 세 가지 영역에서 다른 종류의 컨테이너와 다릅니다. Java에서 배열은 일련의 객체 참조를 저장하고 무작위로 액세스하는 가장 효율적인 방법입니다.

프로젝트 설계에서 배열은 점점 덜 사용되며 실제로 List 및 Set만큼 사용하기 편리하지 않습니다. 배열은 속도와 같은 일부 측면에서 여전히 몇 가지 장점을 갖고 있으며 컬렉션 클래스의 최하위 계층도 배열을 통해 구현됩니다.

--------这是ArrayList的add()------
    public boolean add(E e) {
    ensureCapacity(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
    }

배열과 목록을 사용하여 비교 작업을 수행해 보겠습니다.

1.합


으으으


위의 시간 소모로 볼 때 기본형 배열의 합 계산 속도는 집합의 약 5배 정도입니다. 실제로 목록 컬렉션에는 합계에 치명적인 작업인 list.get(i)이 있습니다. 이 작업은 unboxing 작업입니다. Integer 개체는 intValue 메서드를 통해 자동으로 int 기본 유형으로 변환되므로 불필요한 성능 소모가 발생합니다.

                                                                        그러니 제발 성능 요구 사항이 더 높은 시나리오에서는 어레이에 우선 순위를 부여합니다.

 4. 가변 길이 배열?

 배열은 길이가 고정되어 있고 초기화 및 선언 후에는 길이를 변경할 수 없습니다. 이는 실제 개발에서는 매우 불편한 일입니다. 우리가 똑똑하다면 분명히 이를 달성할 수 있는 방법을 찾을 수 있습니다. Java가 다중 상속을 구현할 수 없는 것처럼 내부 클래스와 인터페이스를 사용하여 이를 구현할 수도 있습니다(Java 개선 장(9) ----- 다중 상속 구현 참조).

 그럼 가변 길이 배열은 어떻게 구현하나요? 구현을 시뮬레이션하기 위해 List 컬렉션 add 메소드의 확장 아이디어를 사용할 수 있습니다. 다음은 ArrayList의 확장 방법입니다.

Long time1 = System.currentTimeMillis();
        for(int i = 0 ; i < 100000000 ;i++){
            sum += arrays[i%10];
        }
        Long time2 = System.currentTimeMillis();
        System.out.println("数组求和所花费时间:" + (time2 - time1) + "毫秒");
        Long time3 = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            sum  += list.get(i%10);
        }
        Long time4 = System.currentTimeMillis();
        System.out.println("List求和所花费时间:" + (time4 - time3) + "毫秒");
--------------Output:
数组求和所花费时间:696毫秒
List求和所花费时间:3498毫秒

 이 코드에서 유용한 부분은 if 문은 나중에. 아이디어는 원래 배열을 새 배열에 복사하는 것이며, 새 배열은 원래 배열 길이의 1.5배입니다. 따라서 시뮬레이션된 배열 확장 코드는 다음과 같습니다.

public void ensureCapacity(int minCapacity) {
        modCount++;  
        int oldCapacity = elementData.length;
        /**
         * 若当前需要的长度超过数组长度时进行扩容处理
         */
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;    
            int newCapacity = (oldCapacity * 3) / 2 + 1;    //扩容
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            //拷贝数组,生成新的数组
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

이 우회 방식을 통해 배열을 얻을 수 있습니다. 확장 확장. 따라서 프로젝트에 가변 길이 데이터 세트가 꼭 필요한 경우 배열도 고려 대상에 포함됩니다. 왜냐하면 고정 길이이기 때문입니다.

5. 배열 복사 문제

하나씩 복사하기가 너무 귀찮아서 그냥 List.toArray()를 사용합니다. 배열로 변환한 후 Arrays.copyOf를 통해 복사하는 방법입니다. 컬렉션으로 변환한 후 개인적으로 매우 편리하다고 생각하지만 함정에 빠졌는지 모르겠습니다. 배열 요소가 객체인 경우 배열의 데이터는 객체 참조

public class ArrayUtils {
    /**
     * @desc 对数组进行扩容
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param newLen 扩容大小
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas,int newLen){
        newLen = newLen < 0 ? datas.length :datas.length + newLen;   
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }
    
    /**
     * @desc 对数组进行扩容处理,1.5倍
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas  原始数组
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas){
        int newLen = (datas.length * 3) / 2;      //扩容原始数组的1.5倍
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }
    
    /**
     * @desc 对数组进行扩容处理,
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param mulitiple 扩容的倍数
     * @return T[]
     */
    public static <T> T[] expandCapacityMul(T[] datas,int mulitiple){
        mulitiple = mulitiple < 0 ? 1 : mulitiple;
        int newLen = datas.length * mulitiple;
        return Arrays.copyOf(datas,newLen );
    }
}

  결과를 ​​보면 person1의 값도 변경된 것을 볼 수 있는데, 이는 전형적인 얕은 복사 문제이다. 따라서 Arrays.copyOf() 메서드에 의해 생성된 배열은 얕은 복사본입니다. 동시에 배열의 clone() 메소드도 동일하고 컬렉션의 clone() 메소드도 동일하므로 복사 메소드를 사용할 때 얕은 복사 문제에 주의해야 합니다.

       有关于深浅拷贝的博文,参考:

      渐析java的浅拷贝和深拷贝:http://www.php.cn/

      使用序列化实现对象的拷贝:http://www.php.cn/

       六、数组转换为List注意地方

       我们经常需要使用到Arrays这个工具的asList()方法将其转换成列表。方便是方便,但是有时候会出现莫名其妙的问题。如下:

public static void main(String[] args) {
        int[] datas = new int[]{1,2,3,4,5};
        List list = Arrays.asList(datas);
        System.out.println(list.size());
    }
------------Output:
1

       结果是1,是的你没有看错, 结果就是1。但是为什么会是1而不是5呢?先看asList()的源码

public static <T> List<T> asList(T... a) {
        return new ArrayList<T>(a);
    }

       注意这个参数:T…a,这个参数是一个泛型的变长参数,我们知道基本数据类型是不可能泛型化的,也是就说8个基本数据类型是不可作为泛型参数的,但是为什么编译器没有报错呢?这是因为在java中,数组会当做一个对象来处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型,所以在转换之后List中就只会存在一个类型为int数组的元素了。所以我们这样的程序System.out.println(datas.equals(list.get(0)));输出结果肯定是true。当然如果将int改为Integer,则长度就会变成5了。

       我们在看下面程序:

enum Week{Sum,Mon,Tue,Web,Thu,Fri,Sat}
    public static void main(String[] args) {
        Week[] weeks = {Week.Sum,Week.Mon,Week.Tue,Week.Web,Week.Thu,Week.Fri};
        List<Week> list = Arrays.asList(weeks);
        list.add(Week.Sat);
    }

       这个程序非常简单,就是讲一个数组转换成list,然后改变集合中值,但是运行呢?

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:131)
    at java.util.AbstractList.add(AbstractList.java:91)
    at com.array.Test.main(Test.java:18)

       编译没错,但是运行竟然出现了异常错误!UnsupportedOperationException ,当不支持请求的操作时,就会抛出该异常。从某种程度上来说就是不支持add方法,我们知道这是不可能的!什么原因引起这个异常呢?先看asList()的源代码:

public static <T> List<T> asList(T... a) {
        return new ArrayList<T>(a);
    }

       这里是直接返回一个ArrayList对象返回,但是注意这个ArrayList并不是java.util.ArrayList,而是Arrays工具类的一个内之类:

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;
    }
       /** 省略方法 **/
    }

       但是这个内部类并没有提供add()方法,那么查看父类:

public boolean add(E e) {
    add(size(), e);
    return true;
    }
    public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }

       这里父类仅仅只是提供了方法,方法的具体实现却没有,所以具体的实现需要子类自己来提供,但是非常遗憾

这个内部类ArrayList并没有提高add的实现方法。在ArrayList中,它主要提供了如下几个方法:

       1、size:元素数量

       2、toArray:转换为数组,实现了数组的浅拷贝。

       3、get:获得指定元素。

       4、contains:是否包含某元素。

요약하자면 asList는 길이가 불변인 목록을 반환합니다. 배열의 길이와 변환된 목록의 길이는 얼마입니까? 추가 또는 제거를 통해 길이를 늘리거나 줄일 수 없습니다.

위 내용은 Java 개선 장(19)------Array 2의 내용입니다. PHP 중국어 웹사이트(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.