• 二十一、数组(2)


    本章概要

    • 多维数组
    • 泛型数组
    • Arrays的fill方法

    多维数组

    要创建多维的基元数组,你要用大括号来界定数组中的向量:

    import java.util.*;
    
    public class MultidimensionalPrimitiveArray {
        public static void main(String[] args) {
            int[][] a = {
                    {1, 2, 3,},
                    {4, 5, 6,},
            };
            System.out.println(Arrays.deepToString(a));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    每个嵌套的大括号都代表了数组的一个维度。

    这个例子使用 Arrays.deepToString() 方法,将多维数组转换成 String 类型,就像输出中显示的那样。

    你也可以使用 new 分配数组。这是一个使用 new 表达式分配的三维数组:

    import java.util.*;
    
    public class ThreeDWithNew {
        public static void main(String[] args) {
            // 3-D array with fixed length:
            int[][][] a = new int[2][2][4];
            System.out.println(Arrays.deepToString(a));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    倘若你不对基元数组进行显式的初始化,它的值会自动初始化。而对象数组将被初始化为 null

    组成矩阵的数组中每一个向量都可以是任意长度的(这叫做不规则数组):

    import java.util.*;
    
    public class RaggedArray {
        static int val = 1;
    
        public static void main(String[] args) {
            SplittableRandom rand = new SplittableRandom(47);
            // 3-D array with varied-length vectors:
            int[][][] a = new int[rand.nextInt(7)][][];
            for (int i = 0; i < a.length; i++) {
                a[i] = new int[rand.nextInt(5)][];
                for (int j = 0; j < a[i].length; j++) {
                    a[i][j] = new int[rand.nextInt(5)];
                    Arrays.setAll(a[i][j], n -> val++); // [1]
                }
            }
            System.out.println(Arrays.deepToString(a));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    第一个 new 创建了一个数组,这个数组首元素长度随机,其余的则不确定。第二个 new 在 for 循环中给数组填充了第二个元素,第三个 new 为数组的最后一个索引填充元素。

    • [1] Java 8 增加了 Arrays.setAll() 方法,其使用生成器来生成插入数组中的值。此生成器符合函数式接口 IntUnaryOperator ,只使用一个非 默认 的方法 ApplyAsint(int操作数)Arrays.setAll() 传递当前数组索引作为操作数,因此一个选项是提供 n -> n 的 lambda 表达式来显示数组的索引(在上面的代码中很容易尝试)。这里,我们忽略索引,只是插入递增计数器的值。

    非基元的对象数组也可以定义为不规则数组。这里,我们收集了许多使用大括号的 new 表达式:

    MultidimensionalObjectArrays.java

    import java.util.*;
    
    public class MultidimensionalObjectArrays {
        public static void main(String[] args) {
            BerylliumSphere[][] spheres = {
                    {new BerylliumSphere(), new BerylliumSphere()},
                    {new BerylliumSphere(), new BerylliumSphere(),
                            new BerylliumSphere(), new BerylliumSphere()},
                    {new BerylliumSphere(), new BerylliumSphere(),
                            new BerylliumSphere(), new BerylliumSphere(),
                            new BerylliumSphere(), new BerylliumSphere(),
                            new BerylliumSphere(), new BerylliumSphere()},
            };
            System.out.println(Arrays.deepToString(spheres));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    CollectionComparison.java

    import java.util.*;
    import static com.example.test.ArrayShow.show;
    
    class BerylliumSphere {
        private static long counter;
        private final long id = counter++;
    
        @Override
        public String toString() {
            return "Sphere " + id;
        }
    }
    
    public class CollectionComparison {
        public static void main(String[] args) {
            BerylliumSphere[] spheres =
                    new BerylliumSphere[10];
            for (int i = 0; i < 5; i++) {
                spheres[i] = new BerylliumSphere();
            }
            show(spheres);
            System.out.println(spheres[4]);
    
            List<BerylliumSphere> sphereList = Suppliers.create(
                    ArrayList::new, BerylliumSphere::new, 5);
            System.out.println(sphereList);
            System.out.println(sphereList.get(4));
    
            int[] integers = {0, 1, 2, 3, 4, 5};
            show(integers);
            System.out.println(integers[4]);
    
            List<Integer> intList = new ArrayList<>(
                    Arrays.asList(0, 1, 2, 3, 4, 5));
            intList.add(97);
            System.out.println(intList);
            System.out.println(intList.get(4));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Suppliers.java

    import java.util.Collection;
    import java.util.function.BiConsumer;
    import java.util.function.Supplier;
    import java.util.stream.Stream;
    
    public class Suppliers {
        // Create a collection and fill it:
        public static <T, C extends Collection<T>> C
        create(Supplier<C> factory, Supplier<T> gen, int n) {
            return Stream.generate(gen)
                    .limit(n)
                    .collect(factory, C::add, C::addAll);
        }
    
        // Fill an existing collection:
        public static <T, C extends Collection<T>>
        C fill(C coll, Supplier<T> gen, int n) {
            Stream.generate(gen)
                    .limit(n)
                    .forEach(coll::add);
            return coll;
        }
    
        // Use an unbound method reference to
        // produce a more general method:
        public static <H, A> H fill(H holder,
                                    BiConsumer<H, A> adder, Supplier<A> gen, int n) {
            Stream.generate(gen)
                    .limit(n)
                    .forEach(a -> adder.accept(holder, a));
            return holder;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    ArrayShow.java

    import java.util.*;
    
    public interface ArrayShow {
        static void show(Object[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(boolean[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(byte[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(char[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(short[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(int[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(long[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(float[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        static void show(double[] a) {
            System.out.println(Arrays.toString(a));
        }
    
        // Start with a description:
        static void show(String info, Object[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, boolean[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, byte[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, char[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, short[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, int[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, long[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, float[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    
        static void show(String info, double[] a) {
            System.out.print(info + ": ");
            show(a);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    数组初始化时使用自动装箱技术:

    import java.util.*;
    
    public class AutoboxingArrays {
        public static void main(String[] args) {
            Integer[][] a = { // Autoboxing:
                    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
                    {21, 22, 23, 24, 25, 26, 27, 28, 29, 30},
                    {51, 52, 53, 54, 55, 56, 57, 58, 59, 60},
                    {71, 72, 73, 74, 75, 76, 77, 78, 79, 80},
            };
            System.out.println(Arrays.deepToString(a));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    以下是如何逐个构建非基元的对象数组:

    import java.util.*;
    
    public class AssemblingMultidimensionalArrays {
        public static void main(String[] args) {
            Integer[][] a;
            a = new Integer[3][];
            for (int i = 0; i < a.length; i++) {
                a[i] = new Integer[3];
                for (int j = 0; j < a[i].length; j++) {
                    a[i][j] = i * j; // Autoboxing
                }
            }
            System.out.println(Arrays.deepToString(a));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    a[i][j] 在这里只是为了向 Integer 中添加有趣的值。

    Arrays.deepToString() 方法同时适用于基元数组和对象数组:

    import java.util.*;
    
    public class MultiDimWrapperArray {
        public static void main(String[] args) {
            Integer[][] a1 = { // Autoboxing
                    {1, 2, 3,},
                    {4, 5, 6,},
            };
            Double[][][] a2 = { // Autoboxing
                    {{1.1, 2.2}, {3.3, 4.4}},
                    {{5.5, 6.6}, {7.7, 8.8}},
                    {{9.9, 1.2}, {2.3, 3.4}},
            };
            String[][] a3 = {
                    {"The", "Quick", "Sly", "Fox"},
                    {"Jumped", "Over"},
                    {"The", "Lazy", "Brown", "Dog", "&", "friend"},
            };
            System.out.println(
                    "a1: " + Arrays.deepToString(a1));
            System.out.println(
                    "a2: " + Arrays.deepToString(a2));
            System.out.println(
                    "a3: " + Arrays.deepToString(a3));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    同样的,在 IntegerDouble 数组中,自动装箱可为你创建包装器对象。

    泛型数组

    一般来说,数组和泛型并不能很好的结合。你不能实例化参数化类型的数组:

    Peel<Banana>[] peels = new Peel<Banana>[10]; // Illegal
    
    • 1

    类型擦除需要删除参数类型信息,而且数组必须知道它们所保存的确切类型,以强制保证类型安全。

    但是,可以参数化数组本身的类型:

    class ClassParameter<T> {
        public T[] f(T[] arg) {
            return arg;
        }
    }
    
    class MethodParameter {
        public static <T> T[] f(T[] arg) {
            return arg;
        }
    }
    
    public class ParameterizedArrayType {
        public static void main(String[] args) {
            Integer[] ints = {1, 2, 3, 4, 5};
            Double[] doubles = {1.1, 2.2, 3.3, 4.4, 5.5};
            Integer[] ints2 =
                    new ClassParameter<Integer>().f(ints);
            Double[] doubles2 =
                    new ClassParameter<Double>().f(doubles);
            ints2 = MethodParameter.f(ints);
            doubles2 = MethodParameter.f(doubles);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    比起使用参数化类,使用参数化方法很方便。您不必为应用它的每个不同类型都实例化一个带有参数的类,但是可以使它成为 静态 的。你不能总是选择使用参数化方法而不用参数化的类,但通常参数化方法是更好的选择。

    你不能创建泛型类型的数组,这种说法并不完全正确。是的,编译器不会让你 实例化 一个泛型的数组。但是,它将允许您创建对此类数组的引用。例如:

    List<String>[] ls;
    
    • 1

    无可争议的,这可以通过编译。尽管不能创建包含泛型的实际数组对象,但是你可以创建一个非泛型的数组并对其进行强制类型转换:

    import java.util.*;
    
    public class ArrayOfGenerics {
        @SuppressWarnings("unchecked")
        public static void main(String[] args) {
            List<String>[] ls;
            List[] la = new List[10];
            ls = (List<String>[]) la; // Unchecked cast
            ls[0] = new ArrayList<>();
    
            //- ls[1] = new ArrayList();
            // error: incompatible types: ArrayList
            // cannot be converted to List
            //     ls[1] = new ArrayList();
            //             ^
    
            // The problem: List is a subtype of Object
            Object[] objects = ls; // So assignment is OK
            // Compiles and runs without complaint:
            objects[1] = new ArrayList<>();
    
            // However, if your needs are straightforward it is
            // possible to create an array of generics, albeit
            // with an "unchecked cast" warning:
            List<BerylliumSphere>[] spheres =
                    (List<BerylliumSphere>[]) new List[10];
            Arrays.setAll(spheres, n -> new ArrayList<>());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    一旦你有了对 List[] 的引用 , 你会发现多了一些编译时检查。问题是数组是协变的,所以 List[] 也是一个 Object[] ,你可以用这来将 **ArrayList ** 分配进你的数组,在编译或者运行时都不会出错。

    如果你知道你不会进行向上类型转换,你的需求相对简单,那么可以创建一个泛型数组,它将提供基本的编译时类型检查。然而,一个泛型 Collection 实际上是一个比泛型数组更好的选择。

    一般来说,您会发现泛型在类或方法的边界上是有效的。在内部,擦除常常会使泛型不可使用。所以,就像下面的例子,不能创建泛型类型的数组:

    public class ArrayOfGenericType<T> {
        T[] array; // OK
    
        @SuppressWarnings("unchecked")
        public ArrayOfGenericType(int size) {
            // error: generic array creation:
            //- array = new T[size];
            array = (T[]) new Object[size]; // unchecked cast
        }
        // error: generic array creation:
        //- public  U[] makeArray() { return new U[10]; }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    擦除再次从中作梗,这个例子试图创建已经擦除的类型数组,因此它们是未知的类型。你可以创建一个 对象 数组,然后对其进行强制类型转换,但如果没有 **@SuppressWarnings ** 注释,你将会得到一个 “unchecked” 警告,因为数组实际上不真正支持而且将对类型 T 动态检查 。

    这就是说,如果我创建了一个 String[] , Java将在编译时和运行时强制执行,我只能在数组中放置字符串对象。然而,如果我创建一个 Object[] ,我可以把除了基元类型外的任何东西放入数组。

    Arrays的fill方法

    通常情况下,当对数组和程序进行实验时,能够很轻易地生成充满测试数据的数组是很有帮助的。 Java 标准库 Arrays 类包括一个普通的 fill() 方法,该方法将单个值复制到整个数组,或者在对象数组的情况下,将相同的引用复制到整个数组:

    import java.util.*;
    
    import static com.example.test.ArrayShow.show;
    
    public class FillingArrays {
        public static void main(String[] args) {
            int size = 6;
            boolean[] a1 = new boolean[size];
            byte[] a2 = new byte[size];
            char[] a3 = new char[size];
            short[] a4 = new short[size];
            int[] a5 = new int[size];
            long[] a6 = new long[size];
            float[] a7 = new float[size];
            double[] a8 = new double[size];
            String[] a9 = new String[size];
            Arrays.fill(a1, true);
            show("a1", a1);
            Arrays.fill(a2, (byte) 11);
            show("a2", a2);
            Arrays.fill(a3, 'x');
            show("a3", a3);
            Arrays.fill(a4, (short) 17);
            show("a4", a4);
            Arrays.fill(a5, 19);
            show("a5", a5);
            Arrays.fill(a6, 23);
            show("a6", a6);
            Arrays.fill(a7, 29);
            show("a7", a7);
            Arrays.fill(a8, 47);
            show("a8", a8);
            Arrays.fill(a9, "Hello");
            show("a9", a9);
            // Manipulating ranges:
            Arrays.fill(a9, 3, 5, "World");
            show("a9", a9);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述

    你既可以填充整个数组,也可以像最后两个语句所示,填充一系列的元素。但是由于你只能使用单个值调用 Arrays.fill() ,因此结果并非特别有用。

  • 相关阅读:
    java-net-php-python-jsp音像店租赁录像计算机毕业设计程序
    python采集天气数据 并做数据可视化 (含完整源代码)
    产品经理基础--07用户端产品设计
    Vue超详宝典(第二部)--万字长文硬核发布
    基于复杂环境下的雷达目标检测技术(Matlab代码实现)
    利用结构体完成图书新增交互
    mysql基于SSM的自习室管理系统毕业设计源码201524
    C/S架构学习之基于UDP的本地通信(服务器)
    【C进阶】之多文件编程
    旋转验证码分析 rotatecaptcha
  • 原文地址:https://blog.csdn.net/GXL_1012/article/details/134516528