第十六章:数组
来源:互联网 发布:windows应用商店打不开 编辑:程序博客网 时间:2024/05/18 11:26
数组
- 数组我相信大家都很熟悉吧。数组的优点就是随机读取速度快,像ArrayList就是使用了数组作为数据存储格式而实现的。但是缺点也很明显,它的大小是固定的。ArrayList之所以能够任意大小,是因为使用了size,扩容的时候拷贝数组到新数组。本章我们就来讨论一下数组的特点和用法。
数组是第一级对象
- 无论使用哪种类型的数组,数组标识符其实只是一个引用,指向堆中创建的一个真实对象,这个(数组)对象用以保存指向其他对象的引用。除了new表达式显式创建数组对象,还可以用一些隐式语法。length是它的唯一一个可以访问的成员属性,并且是只读的。数组的类型既可以是引用类型,也可以是基本类型。如果是基本类型的话,都会有默认值。而引用类型则为null。
多维数组
- 我们这里来说一下粗糙数组。通常我们会这么定义多维数组:
int[][] test = new int[5][5];
- 这样相当于是定义了一个5*5的矩阵。但是如果说,我想定义一个不规则大小的数组怎么办?那么我们就可以这么写:
int[][] test = new int[5][]; test[0] = new int[1]; test[1] = new int[2]; test[2] = new int[3]; test[3] = new int[4]; test[4] = new int[5];
- java允许我们先确定最外层数组的大小,然后再逐步确定里层数组大小。这种写法比较少用,这里就做个笔记。
数组和泛型
- 通常,数组与泛型不能很好的结合。你不能实例化具有参数化类型的数组:
List<String>[] ls = new List<String>[10];//编译错误
- 但是我们可以通过一些人为控制来完成这个数组的创建。我们先来回忆一下泛型的使用。
public class People { public static void main(String args[]) { Holder<Integer> ho1 = new Holder<Integer>(); Holder<String> ho2 = new Holder<String>(); Holder ho11 = ho1; Holder ho22 = ho2; Holder<String> ho111 = ho11; Holder<Integer> ho222 = ho22; ho111.set(new String("1")); ho222.set(new Integer(1)); System.out.println(ho111.get()); System.out.println(ho222.get()); }}class Holder <T> { T obj; T get() { return obj; } void set(T obj) { this.obj = obj; }}----------------运行结果11
- 你也许会以为
new Holder<Integer>()
和new Holder<String>()
是两种不同的类型。但是事实告诉我们,我们试图往前者插入String,不会导致任何错误。这是为什么呢?因为在Holder内部,它只认为泛型是它的擦除边界Object而已。而真正能够限制我们的是ho111认为的泛型类型(在编译期间)。我们当然不会这么写代码,此处也是为了让我们深刻的理解泛型的作用。再次强调,在泛型类内部,所有的泛型类型是擦除边界! - 那么此处我们应该就这样去定义这个数组:
List<String>[] ls = new List[10];
- 你不要觉得
new List[10];
相比于new List<String>[10];
有什么区别,他们本质是没有区别的,这个在上面已经讨论过了。只要我们List<String>[] ls
这么做了,编译器就能够为我们有效检查ls元素的类型。虽然会有警告,但是大家可以放心的这么写。
Arrays实用功能
- 先来讲一下Arrays.equals()和Arrays.deepEquals()。前者是针对一维数组的,会比较其每个元素的equals()方法,后者是针对多维数组的。
import java.util.Arrays;public class People { public static void main(String args[]) throws Exception { int[] a = new int[10]; int[] b = new int[10]; //System.out.println(a.equals(b));//false 比较引用 System.out.println(Arrays.equals(a, b));//true a[0] = 1; System.out.println(Arrays.equals(a, b));//false int[][] c = new int[1][]; int[][] d = new int[1][]; a = new int[1]; b = new int[1]; c[0] = a; d[0] = a; System.out.println(Arrays.equals(c, d));//true System.out.println(Arrays.deepEquals(c, d));//true d[0] = b; System.out.println(Arrays.equals(c, d));//false System.out.println(Arrays.deepEquals(c, d));//true System.out.println(); c[0][0] = 1; System.out.println(Arrays.equals(c, d));//false System.out.println(Arrays.deepEquals(c, d));//false }}
- sort()是用于排序的,binarySearch()是对已经有序的数组进行二分法查询元素。toString()产生数组的字符串表示,fill()用于填充单一元素内容。还有其他用法就不过多介绍了。
复制数组
- System.arraycopy()是一个用于复制(浅拷贝)数组的方法,它的速度比用循环复制要快得多。它需要的参数有:源数组,源数组偏移量,目标数组,目标数组偏移量,复制个数。另外需要注意的是该方法不会执行自动包装和自动拆包,两个数组必须具有相同的确切类型。来看下面的例子:
import java.lang.reflect.Field;import java.util.Arrays;public class People { public static void main(String args[]) throws Exception { int[] a = new int[10]; int[] b = new int[10]; Arrays.fill(a, 1); Arrays.fill(a, 2); System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(b)); //System.arraycopy(a, 5, b, 0, b.length);//a越界会产生异常,切记 //System.arraycopy(a, 0, b, 5, b.length);//b越界会产生异常,切记 System.arraycopy(a, 5, b, 5, b.length - 5); System.out.println(Arrays.toString(b)); Integer[] c = new Integer[10]; Arrays.fill(c, new Integer(3)); System.out.println(Arrays.toString(c)); //System.arraycopy(a, 5, c, 5, c.length - 5);//不会自动包装和拆包,会产生异常,切记 Integer[] d = new Integer[10]; Arrays.fill(d, new Integer(4)); /*for (int i=0; i<d.length; i++) { d[i] = new Integer(4); }*///这种写法针对下面的浅拷贝测试只改变d[0] System.arraycopy(d, 0, c, 5, d.length - 5); System.out.println(Arrays.toString(c)); //为了验证是浅拷贝: //接下来我打算用反射改变d[0]的值,当然也可以使用其他引用类型做测试,我这里就不改了 Field f = Integer.class.getDeclaredField("value"); f.setAccessible(true); f.set(d[0], 520);//因为d[0]到d[9]其实是同一个对象,所以都会改变 System.out.println(Arrays.toString(d)); System.out.println(Arrays.toString(c));//c也变了,说明的确是浅拷贝 //更简单的判断方式: System.out.println(new Integer(520) == new Integer(520));//false System.out.println(d[0] == c[5]);//true }}----------------------------运行结果[2, 2, 2, 2, 2, 2, 2, 2, 2, 2][0, 0, 0, 0, 0, 0, 0, 0, 0, 0][0, 0, 0, 0, 0, 2, 2, 2, 2, 2][3, 3, 3, 3, 3, 3, 3, 3, 3, 3][3, 3, 3, 3, 3, 4, 4, 4, 4, 4][520, 520, 520, 520, 520, 520, 520, 520, 520, 520][3, 3, 3, 3, 3, 520, 520, 520, 520, 520]
sort
- Arrays.sort是一个很常用的方法,直接对int排序或者String排序,我相信大家都会,那如果我要对一个自定义的数组排序,该如何呢?此时我们需要使这个类实现Comparable接口,否则直接调用sort会出现CCE异常(因为其内部使用了Comparable接口的方法)。
import java.util.Arrays;import java.util.Comparator;public class People { public static void main(String args[]) throws Exception { Test[] test = new Test[5]; for (int i = 0; i < test.length; i++) { test[i] = new Test(i, i + "" + i); } System.out.println(Arrays.toString(test)); Arrays.sort(test); System.out.println(Arrays.toString(test)); // 假设我不满意这个排序方式,又无法直接修改Test类: Arrays.sort(test, new Comparator<Test>() { public int compare(Test o1, Test o2) { //实际上String也实现了Comparable return o1.s.compareTo(o2.s); } }); System.out.println(Arrays.toString(test)); }}class Test implements Comparable<Test> { int i; String s; public Test(int i, String s) { this.i = i; this.s = s; } //Comparable 需要实现的方法 public int compareTo(Test o) { return o.i - i;//逆序 } //方便打印输出 public String toString() { return i + "->" + s; }}-------------------执行结果:[0->00, 1->11, 2->22, 3->33, 4->44][4->44, 3->33, 2->22, 1->11, 0->00][0->00, 1->11, 2->22, 3->33, 4->44]
阅读全文
0 0
- 第十六章:数组
- 第十六章:数组
- 《Java 编程思想》--第十六章:数组
- 《java编程思想》第十六章 数组
- java编程思想读书笔记 第十六章 数组
- Thinking in Java——第十六章-数组
- 读书笔记_CLR.via.c#第十六章_数组
- think in java第十六章数组 总结随笔
- 第十六章
- 第十六章
- 第十六章
- 第十六章
- Java编程思想第四版读书笔记——第十六章 数组
- 第十六周上机体验字符/字符串数组
- 第十六周项目一数组的排序
- 第十六周 问题 A: 逆序输出数组
- 第十六周项目1-数组的排序
- 第十六周项目3-逆序输出数组
- 设计模式之适配器模式
- 报“百度未授权使用地图API,可能是因为”原因分析
- JavaScript函数—function()
- 配置Tomcat使用https协议(配置SSL协议)
- C++中的namespace
- 第十六章:数组
- Samsung Galaxy S5(G9006V)刷机降级(Android 6.0.1->Android 4.4.2)
- HDU Fire Net 1045 二分匹配
- Android studio 将library打包成jar包实例
- 贾扬清撰文详解Caffe2:从强大的新能力到入门上手教程
- azkaban调度过程
- 【bfs(广搜)模板】
- JAVA IO常用类总结
- 三种主流数据库区别