Answers:
他们可能想从最准确地表示计算机工作方式的数据结构入手,因此在他们开始引入更简单的列表之类的更高级抽象之前,您应该熟悉基础知识。否则,您将无法理解为什么某些结构或算法对于某些操作而不是其他某些操作速度慢/快。如果计算机内存实际上是由链表制成的,那么世界将是一个截然不同的地方。
出于同样的原因,我在大学的第一门编程课是C语言,其余的课程全部是C ++,Java和其他语言。并不是说C会变得更好或更简单,而是C(和数组)对您没有任何隐藏。
上面的答案很棒,但是我有另一个想法。Java的main()
方法意味着学生很早就遇到基础数组,通常是在上课的第一天。为什么?
public static void main(String[] args)
编写《 Hello World及更高版本》是您要做的第一件事。(我看过一些课程首先使用了诸如BlueJ这样的教学IDE,它允许您点击并运行任意方法,但我们将其搁置一旁...)尽管值得一提的是,这些关键字有一段时间了,大多数老师迟早会想对它们进行解释。实际上,一个经典的初学者水平的测试问题是要求学生在基本的Hello World程序中给出每个关键字的含义。作为主要方法签名的一部分,我们能找到什么?数组(其原因部分是历史原因。Java1.0中不存在ArrayList)。数组是该基础知识集的一部分。清单不是。
就是说,类在稍后的课程中引入ArrayList的情况并不少见,特别是在对象和它们的用途被覆盖之后。即使是Java的AP计算机科学课程,也包括ArrayList(我知道它曾经用过,Google似乎表明它仍然这样做),尽管它忽略了ArrayList实现List和其余Collections Framework的事实。
最后,根据我的经验,大学的CS程序使用Java作为探索CS和编程概念的方法,而不是教学生如何成为优秀的Java开发人员。有些程序可能更着重于培养专业的开发人员,而另一些程序则更着重于理论,但无论哪种情况,都有很多关于如何在实际的专业工作中使用Java的知识,这在大多数大学课程中都不会讲到。范围从有效Java中的设计模式和技术到Spring,Hibernate或JUnit等框架,甚至更常见的JSP或JDBC。考虑到这一原理,在更常用的ArrayList上强调数组会更有意义。
第一年编程班使用数组的一个原因是传统的:这是教授们在我们开始使用带有动态列表的标准库之前最初学到的方法。使用原始数据类型也更普遍:数组几乎存在于任何计算机中阳光下的语言(可以在少数汇编说明中实现)。当我第一次学习编程时,实现链接列表是其中的一项任务。
从第一原理开始,然后说“这是基本结构。这种语言(或其库)为您提供了可以执行所有操作的高级数据结构,但是却为您提供了x,y和z,”就是说:“这就是这些高级数据结构,现在就在这里。” 学习确定是否使用LinkedList与ArrayList(或HashSet与TreeSet)通常是第二年或第三年的算法课程。列表和映射具有相同的接口,并提供相同的结果,但是在任何大小的应用程序中,它们的行为都可能截然不同。一旦您退出了编程101,就无法保证编程102将使用相同的语言。如果您从数组的概念入手,您可以说“
在入门课程中,更喜欢“数组”而不是“列表”的另一个原因是数组从根本上很容易理解:bytes
20个数组占用20个字节(加上一对来表示数组的结尾或长度,具体取决于实现方式) )。
“列表”是完全不同的鱼,可以通过许多不同的方式(ArrayList,LinkedList,以及我可能忘记的几个方式)来实现,并且具有根本不同的性能特征。如果不了解List类的不同之处,就无法对何时应使用List foo = new ArrayList()
vs 进行有意义的讨论List foo = new LinkedList()
。如果您尝试让学生使用List实现,那么有人会问您为什么使用ArrayList而不是其他实现之一。而且“ ArrayList”包含单词“ Array”,并由一个单词支持,因此从“ array”到“ ArrayList”的逻辑跳跃并不是很大。
与流行的看法相反,在某些情况下,在列表上使用数组是有意义的,尤其是在处理静态大小的列表时。这是一对:
foo[n]
取消引用,并做一些幕后的指针运算,而foo.get(n)
有取消引用,做一个方法调用,做了第二次提领,然后也许做指针运算(如果您使用的是ArrayList,则LinkedLists可能需要遍历List的每个元素)。int[] foo = new int[]{1, 2, 3, 4, 5}
与另一个StackOverflow问题中的建议相比perm
是具有int[256]
排列的a,则可以很容易地用一个数组将其取反:int[] inv = new int[256]; for (int i=0; i<256; i++) inv[perm[i]]=i;
我认为用a可以写的任何东西ArrayList<>
都不会那么干净。
ArrayList
可以很容易地得到一个构造函数,该构造函数创建一个特定大小的默认初始化列表。
get
,并set
没有得到联。
get
并且set
可以内联,类似的myList.set(23,myList.get(23)+1)
效率也远不及myArray[23]+=1
。此外,即使对于不需要装箱的类型,如果任何JITter都能将等同for (i=0; i<1000; i++) myList2.set(i+2000,myList2.get(i+3000));
于其性能的任何东西都令我感到惊讶,那么System.arrayCopy(myArray1,3000,myArray2,2000,1000);
框架的动态数组类型没有理由不应该提供快速的复制范围操作,但是Java没有。
Java允许将任何类型的变量存储到数组中。相反,ArrayList
仅允许存储引用。因此,在ArrayList
不首先讨论自动装箱如何将原语转换为引用类型以及自动拆箱有时将参考类型转换为原语的情况下,可能没有用的讨论:
for (int i=10; i<=10000; i*=10)
{
ArrayList<Integer> l = new ArrayList<Integer>();
l.add(i);
l.add(i);
l.add(l.get(0));
System.out.print("i=" + i);
System.out.print(" #0==i:" + (l.get(0)==i));
System.out.print(" #1==i:" + (l.get(1)==i));
System.out.print(" #2==i:" + (l.get(2)==i));
System.out.print(" #0=#1:" + (l.get(0)==l.get(1)));
System.out.print(" #1=#2:" + (l.get(1)==l.get(2)));
System.out.println(" #0=#2:" + (l.get(0)==l.get(2)));
}
如果代码使用int[3]
而不是ArrayList
,就不会感到惊讶。所有这三个元素将相互比较i
。ArrayList
但是,即使使用list的所有三个元素总是比较等于i
,并且第一个和第三个元素始终总是比较相等,使用,即使前者在1、10 i
或100 时也只会彼此相等,但是(在大多数实现中)不是i
1000或10000。
Integer
该类具有嵌套的类,该类IntegerCache
包含Integer
用于一系列通常扩展为-128..127的值的预初始化对象;对超出该范围的值进行装箱将需要创建一个新的对象,但是对在缓存范围内的值进行装箱将仅返回对存储在中的预初始化对象之一的引用IntegerCache.cache
。任何优秀的Java程序员都需要意识到,Integer
封装相同值的两种类型的变量可能比较或不相等,但是过早引入该思想可能会使学生惊恐万状。
==
。考虑到自动拆箱的可能性,我倾向于完全禁止它使用,但是它的行为==
尤其可怕。该==
运营商还表现在严重的情况下一样16777217==16777216f
[报告真],而对于隐式转换long v=Math.Round(123456789), w=Math.Round(123456789012345)
都容易出现意想不到的[你能猜出这些表达式将产生?]
IntegerCache
,有时候它可以帮助提高性能,但是它经常会导致代码出现类错误。在某些方面,我希望有一种装箱方式,该装箱方式将准随机地从两个整数缓存中返回对象,并用新的准随机方式替换缓存项,以便依赖于值-128..127的装箱行为的代码将是不可能长期成功。
由于ArrayList
内部使用数组,因此我认为先教数组的用法是有意义的。的ArrayList
类有称为成员变量elementData
这是一个Object
数组。
从JDK ArrayList
源代码:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
当您从中添加,更新,检索或删除元素时,ArrayList
它会使用此内部数组执行这些操作。正如用户Ixrec所指出的那样- ArrayList
只是一个更高级别的抽象,通常更易于使用。
Java
-这是在问为什么通常在您可以使用时教导数组ArrayList
。Java没有指针。对与错,我认为C / C ++是比Java更适合入门的语言。通过了解C / C ++,可以更好地理解编程中的许多主题。
这是因为在学术教育中最关键的事情是教您使用正确的术语来描述您所做的事情。
列表是那个数组以外的东西。而且您不能java.util.List
在Java中使用它,因为它是一个接口。通常使用java.util.ArrayList
哪个是List实现,而不是列表,而是动态数组周围的对象包装。因此,您说使用“列表”,但使用数组。
跳过术语混乱并仅使用数组来学习学生什么是数组是非常合理的。如果在Java中使用数组,则至少要使用数组。
坦白地说,这也是为什么使用Java进行编程教学不是一个好主意的观点。很难正确学习编程的基本概念。
您实际上根本没有看过或使用过任何数组吗?除了列表,我们一直都在使用它们。我们通常不使用Java,但是我们使用许多其他具有明显相似性的语言。
在数组和列表之间,一个人的重量更轻,而且指向更多点,而另一个人的功能更多。作为编程的一般规则,当基本上有两种相似的类型沿这些线划分时,应该选择重量较轻的类型,除非您实际上需要更高级的一种。除了减少开销外,这实际上还有助于处理程序,尤其是其代码中的混乱情况和状态。如果在测试过程中出现问题,则可以减少寻找的地方。更重要的是,在使用数组与列表的情况下,人们可以更好地了解您实际使用它并尝试使用它的范围有限。
是的,从学术的角度来看,还有其他向学生教授基础知识的原因。但是,这会更深一些。数组和列表是体积较大的类型的一个很好的例子,体积较大的类型通常只是建立在轻量级类型的基础实例之上,并且通常只是包裹在基础实例的周围。即使List没有底层数组,它们也会像它们一样向外表现。教别人什么是列表的一部分就是教他们什么是数组。
我可以看到,这在像C ++这样的语言中可能会失控,在这种语言中,数组的精简基本上不能比其精简得多,但是在高级语言中,它们几乎是自己列出的。如果它们在给定的情况下完全适合您的需求,为什么还要使用其他东西?
T[]
将立即准备就绪,可以按任何顺序接受项目,而则ArrayList<T>
需要按顺序添加项目,然后才能对其进行修改。A T[]
可以T[]
相对较快地ArrayList<T>
将任意范围的项目复制到另一个大小相似的范围内,而这又需要从一个列表中逐个读取项目并将它们存储到另一个列表中-这要慢得多,也不太方便。