@@ -574,14 +574,250 @@ Lazy, Brown, Dog, &, friend]]
574574< ! -- Arrays and Generics -- >
575575## 泛型数组
576576
577+ 一般来说,数组和泛型并不能很好的结合。你不能实例化参数化类型的数组:
578+
579+ ```Java
580+ Peel<Banana > [] peels = new Peel<Banana>[10]; // Illegal
581+ ```
582+
583+ 类型擦除需要删除参数类型信息,而且数组必须知道它们所保存的确切类型,以强制保证类型安全。
584+
585+ 但是,可以参数化数组本身的类型:
586+
587+ ```Java
588+ // arrays/ParameterizedArrayType.java
589+
590+ class ClassParameter <T> {
591+ public T [] f (T [] arg ) { return arg; }
592+ }
593+
594+ class MethodParameter {
595+ public static <T > T [] f (T [] arg ) { return arg; }
596+ }
597+
598+ public class ParameterizedArrayType {
599+ public static void main (String [] args ) {
600+ Integer [] ints = { 1 , 2 , 3 , 4 , 5 };
601+ Double [] doubles = { 1.1 , 2.2 , 3.3 , 4.4 , 5.5 };
602+ Integer [] ints2 =
603+ new ClassParameter<Integer > ().f (ints);
604+ Double [] doubles2 =
605+ new ClassParameter<Double > ().f (doubles);
606+ ints2 = MethodParameter . f(ints);
607+ doubles2 = MethodParameter . f(doubles);
608+ }
609+ }
610+ ```
611+
612+ 比起使用参数化类,使用参数化方法很方便。您不必为应用它的每个不同类型都实例化一个带有参数的类,但是可以使它成为 ** 静态** 的。你不能总是选择使用参数化方法而不用参数化的类,但通常参数化方法是更好的选择。
613+
614+ 你不能创建泛型类型的数组,这种说法并不完全正确。是的,编译器不会让你 * 实例化* 一个泛型的数组。但是,它将允许您创建对此类数组的引用。例如:
615+
616+ ```Java
617+ List<String > [] ls;
618+ ```
619+
620+ 无可争议的,这可以通过编译。尽管不能创建包含泛型的实际数组对象,但是你可以创建一个非泛型的数组并对其进行强制类型转换:
621+
622+ ```Java
623+ // arrays/ArrayOfGenerics.java
624+ import java. util. * ;
625+
626+ public class ArrayOfGenerics {
627+ @SuppressWarnings (" unchecked" )
628+ public static void main (String [] args ) {
629+ List<String > [] ls;
630+ List [] la = new List [10 ];
631+ ls = (List<String > [])la; // Unchecked cast
632+ ls[0 ] = new ArrayList<> ();
633+
634+ // - ls[1] = new ArrayList<Integer>();
635+ // error: incompatible types: ArrayList<Integer>
636+ // cannot be converted to List<String>
637+ // ls[1] = new ArrayList<Integer>();
638+ // ^
639+
640+ // The problem: List<String> is a subtype of Object
641+ Object [] objects = ls; // So assignment is OK
642+ // Compiles and runs without complaint:
643+ objects[1 ] = new ArrayList<> ();
644+
645+ // However, if your needs are straightforward it is
646+ // possible to create an array of generics, albeit
647+ // with an "unchecked cast" warning:
648+ List<BerylliumSphere > [] spheres =
649+ (List<BerylliumSphere > [])new List [10 ];
650+ Arrays . setAll(spheres, n - > new ArrayList<> ());
651+ }
652+ }
653+ ```
654+
655+ 一旦你有了对 ** List<String > []** 的引用 , 你会发现多了一些编译时检查。问题是数组是协变的,所以 ** List<String > []** 也是一个 ** Object []** ,你可以用这来将 ** ArrayList<Integer > ** 分配进你的数组,在编译或者运行时都不会出错。
656+
657+ 如果你知道你不会进行向上类型转换,你的需求相对简单,那么可以创建一个泛型数组,它将提供基本的编译时类型检查。然而,一个泛型 ** Collection ** 实际上是一个比泛型数组更好的选择。
658+
659+ 一般来说,您会发现泛型在类或方法的边界上是有效的。在内部,擦除常常会使泛型不可使用。所以,就像下面的例子,不能创建泛型类型的数组:
660+
661+ ```Java
662+ // arrays/ArrayOfGenericType.java
663+
664+ public class ArrayOfGenericType <T> {
665+ T [] array; // OK
666+ @SuppressWarnings (" unchecked" )
667+ public ArrayOfGenericType (int size ) {
668+ // error: generic array creation:
669+ // - array = new T[size];
670+ array = (T [])new Object [size]; // unchecked cast
671+ }
672+ // error: generic array creation:
673+ // - public <U> U[] makeArray() { return new U[10]; }
674+ }
675+
676+ ```
677+
678+ 擦除再次从中作梗,这个例子试图创建已经擦除的类型数组,因此它们是未知的类型。你可以创建一个 ** 对象** 数组,然后对其进行强制类型转换,但如果没有 ** @SuppressWarnings ** 注释,你将会得到一个 " unchecked" 警告,因为数组实际上不真正支持而且将对类型 ** T ** 动态检查 。这就是说,如果我创建了一个 ** String []** , Java 将在编译时和运行时强制执行,我只能在数组中放置字符串对象。然而,如果我创建一个 ** Object []** ,我可以把除了基元类型外的任何东西放入数组。
679+
680+
577681
578682< ! -- Arrays . fill() -- >
579683## Arrays 的fill方法
580684
685+ 通常情况下,当对数组和程序进行实验时,能够很轻易地生成充满测试数据的数组是很有帮助的。 Java 标准库 ** Arrays ** 类包括一个普通的 ** fill()** 方法,该方法将单个值复制到整个数组,或者在对象数组的情况下,将相同的引用复制到整个数组:
686+
687+ ```Java
688+ // arrays/FillingArrays.java
689+ // Using Arrays.fill()
690+ import java. util. * ;
691+ import static onjava. ArrayShow . * ;
692+
693+ public class FillingArrays {
694+ public static void main (String [] args ) {
695+ int size = 6 ;
696+ boolean [] a1 = new boolean [size];
697+ byte [] a2 = new byte [size];
698+ char [] a3 = new char [size];
699+ short [] a4 = new short [size];
700+ int [] a5 = new int [size];
701+ long [] a6 = new long [size];
702+ float [] a7 = new float [size];
703+ double [] a8 = new double [size];
704+ String [] a9 = new String [size];
705+ Arrays . fill(a1, true );
706+ show(" a1" , a1);
707+ Arrays . fill(a2, (byte )11 );
708+ show(" a2" , a2);
709+ Arrays . fill(a3, ' x' );
710+ show(" a3" , a3);
711+ Arrays . fill(a4, (short )17 );
712+ show(" a4" , a4);
713+ Arrays . fill(a5, 19 );
714+ show(" a5" , a5);
715+ Arrays . fill(a6, 23 );
716+ show(" a6" , a6);
717+ Arrays . fill(a7, 29 );
718+ show(" a7" , a7);
719+ Arrays . fill(a8, 47 );
720+ show(" a8" , a8);
721+ Arrays . fill(a9, " Hello" );
722+ show(" a9" , a9);
723+ // Manipulating ranges:
724+ Arrays . fill(a9, 3 , 5 , " World" );
725+ show(" a9" , a9);
726+ }
727+ }gedan
728+ /* Output:
729+ a1: [true, true, true, true, true, true]
730+ a2: [11, 11, 11, 11, 11, 11]
731+ a3: [x, x, x, x, x, x]
732+ a4: [17, 17, 17, 17, 17, 17]
733+ a5: [19, 19, 19, 19, 19, 19]
734+ a6: [23, 23, 23, 23, 23, 23]
735+ a7: [29.0, 29.0, 29.0, 29.0, 29.0, 29.0]
736+ a8: [47.0, 47.0, 47.0, 47.0, 47.0, 47.0]
737+ a9: [Hello, Hello, Hello, Hello, Hello, Hello]
738+ a9: [Hello, Hello, Hello, World, World, Hello]
739+ */
740+
741+ ```
742+
743+ 你既可以填充整个数组,也可以像最后两个语句所示,填充一系列的元素。但是由于你只能使用单个值调用 ** Arrays . fill()** ,因此结果并非特别有用。
744+
581745
582746< ! -- Arrays . setAll() -- >
583747## Arrays 的setAll方法
584748
749+ 在Java 8 中, 在** RaggedArray . java** 中引入并在 ** ArrayOfGenerics . java. Array . setAll()** 中重用。它使用一个生成器并生成不同的值,可以选择基于数组的索引元素(通过访问当前索引,生成器可以读取数组值并对其进行修改)。 ** static Arrays . setAll()** 的重载签名为:
750+
751+ * ** void setAll(int [] a, IntUnaryOperator gen)**
752+ * ** void setAll(long [] a, IntToLongFunction gen)**
753+ * ** void setAll(double [] a, IntToDoubleFunctiongen )**
754+ * ** < T > void setAll(T [] a, IntFunction<? extendsT> gen)**
755+
756+ 除了 ** int ** , ** long ** , ** double ** 有特殊的版本,其他的一切都由泛型版本处理。生成器不是 ** Supplier ** 因为它们不带参数,并且必须将 ** int ** 数组索引作为参数。
757+
758+ ```java
759+ // arrays/SimpleSetAll.java
760+
761+ import java. util. * ;
762+ import static onjava. ArrayShow . * ;
763+
764+ class Bob {
765+ final int id;
766+ Bob (int n ) { id = n; }
767+ @Override
768+ public String toString () { return " Bob" + id; }
769+ }
770+
771+ public class SimpleSetAll {
772+ public static final int SZ = 8 ;
773+ static int val = 1 ;
774+ static char [] chars = " abcdefghijklmnopqrstuvwxyz"
775+ .toCharArray ();
776+ static char getChar (int n ) { return chars[n]; }
777+ public static void main (String [] args ) {
778+ int [] ia = new int [SZ ];
779+ long [] la = new long [SZ ];
780+ double [] da = new double [SZ ];
781+ Arrays . setAll(ia, n - > n); // [1]
782+ Arrays . setAll(la, n - > n);
783+ Arrays . setAll(da, n - > n);
784+ show(ia);
785+ show(la);
786+ show(da);
787+ Arrays . setAll(ia, n - > val++ ); // [2]
788+ Arrays . setAll(la, n - > val++ );
789+ Arrays . setAll(da, n - > val++ );
790+ show(ia);
791+ show(la);
792+ show(da);
793+
794+ Bob [] ba = new Bob [SZ ];
795+ Arrays . setAll(ba, Bob :: new ); // [3]
796+ show(ba);
797+
798+ Character [] ca = new Character [SZ ];
799+ Arrays . setAll(ca, SimpleSetAll :: getChar); // [4]
800+ show(ca);
801+ }
802+ }
803+ /* Output:
804+ [0, 1, 2, 3, 4, 5, 6, 7]
805+ [0, 1, 2, 3, 4, 5, 6, 7]
806+ [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
807+ [1, 2, 3, 4, 5, 6, 7, 8]
808+ [9, 10, 11, 12, 13, 14, 15, 16]
809+ [17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0]
810+ [Bob0, Bob1, Bob2, Bob3, Bob4, Bob5, Bob6, Bob7]
811+ [a, b, c, d, e, f, g, h]
812+ */
813+
814+ ```
815+
816+ * ** [1 ]** 这里,我们只是将数组索引作为值插入数组。这将自动转化为 ** long ** 和 ** double ** 版本。
817+ * ** [2 ]** 这个函数只需要接受索引就能产生正确结果。这个,我们忽略索引值并且使用 ** val** 生成结果。
818+ * ** [3 ]** 方法引用有效,因为 ** Bob ** 的构造器接收一个 ** int ** 参数。只要我们传递的函数接收一个 ** int ** 参数且能产生正确的结果,就认为它完成了工作。
819+ * ** [4 ]** 为了处理除了 ** int ** ,** long ** ,** double ** 之外的基元类型,请为基元创建包装类的数组。然后使用 ** setAll()** 的泛型版本。请注意,** getChar()** 生成基元类型,因此这是自动装箱到 ** Character ** 。
820+
585821
586822< ! -- Incremental Generators -- >
587823## 增量生成
0 commit comments