概述
以前是纯粹写一些比较枯燥的技术类博文,虽然干货不少,但是就像吃绿豆糕一样,吃多了就会觉得口好干;所以,后面我将转换文风,用一种文理双贯的风格进行叙述。我一直认为,将文理割舍开来,并不是一种很好的教育方式,文理如阴与阳,是相辅相成的。
文学走到尽头是神学或者说是宗教学,而宗教学走到尽头是哲学,于是乎不凡就直接用哲学的目光去引领自己学习计算机知识乃至编程实践。
一、本质与联系
1、计算机的本质
上过哲学课,活着高中时期思政课稍微认真听讲的,都会明确记得一个问题:世界的本质是什么?同样的问题放到计算机学习中,计算机的本质是什么?
第一个问题,随便找一本哲学相关的书籍,上面都有明确的答案:1、世界的本质是物质;2、世界的本质是意识。这两种不同的答案,将哲学学派划分成了唯物主义和唯心主义。但是,平心而论,从你自己的经历出发,你对于世界的本质是什么这一问题的答案是什么呢?千万别逃避这个问题,你真的得思考思考,因为这将影响到你学习计算机知识是事半功倍还是事倍功半。
如果,你的答案是世界的本质是意识,那么我劝你不要浪费时间继续看我这篇博文了,因为我教不了你在桌子上想出一台实打实的计算机来。反之,你认为世界的本质是物质,很好,这真的很好!至少你已经具备了“一片土地,一片可用于构建计算机科学大厦的土地”。说了这么多,无非就是想明确一点:学习计算机知识,必须坚定地站立在唯物主义的立场上,因为编程过程中遇到的问题即计算机术语中的bug,是要我们自己去动手解决的,而不是靠想着bug消失了就会让自己代码中的缺陷不见了。
延伸到”计算机的本质是什么?“这个问题上来,我可以明确的告诉你,计算机的本质就是人力的延伸、是人进行生产的工具、是人基于数理逻辑和应用物理规则所创造出来的工具,和一只笔、一本书乃止一架航空母舰的本质没有什么区别——人通过劳动制造出来的工具;若要究出个区别,那就是不同的工具的制作背后凝聚了不同的劳动力付出程度,对于一支笔的制作只消个把小时就做到了”无中生有“,而计算机的”无中生有“需要数年光阴甚至更多。但无论是哪一种工具,其问世都是发明者充分发挥了自己的主观能动性作用的成果,所谓”主观能动性“就是人通过劳动积极改造大自然。
计算机作为人充分发挥主观能动性的产物,我们要学习好驾驭这一工具的理论知识即计算机科学知识,也离不开充分发挥主观能动性,尤其是编程学习,更不同与其他计算机知识的学习,是要求很高的实践精神的;看十遍代码不如手动在电脑上实践一遍,如果你只想背,那么你是无法学习好编程的,要知道实际生产过程中的变动因素是非常多的,完全不是你单纯背一份代码就可以解决的,所以学习计算机尤其是编程,一定要勤于实践。
来一段Java代码,主要是 java.util.ArrayDeque 的一些用法
package base.util;
import java.util.ArrayDeque;
public class ArrayDequeLearn {
public static void main(String[] args) {
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(10);
for (int i=1; i<=10; i++){
arrayDeque.add((int) (i+(Math.pow(2,i+(Math.random())))));
}
System.out.println("The size of the ArrayDeque object is:");
System.out.println(arrayDeque.size());
System.out.println("The specific elements of the ArrayDeque as the follow:");
for (Integer next : arrayDeque) {
System.out.print(next);
System.out.print(" ");
}
Integer pop = arrayDeque.pop();
System.out.println("\n Popping a element:" + pop + ", and the new size is: " + arrayDeque.size());
arrayDeque.addLast(100);
System.out.println("Pushing a new element on the last of this arrayDeque: ");
for (Integer next: arrayDeque){
System.out.print(next);
System.out.print(" ");
}
System.out.println("\nEnsuring 6 if contains in this array: " + arrayDeque.contains(6));
arrayDeque.addFirst(46);
System.out.println("The first element is: " + arrayDeque.getFirst());
System.out.println("Before poll option, the size is: " + arrayDeque.size());
Integer pollLast = arrayDeque.pollLast();
System.out.println("The size of array after testing poll option at the last: " +arrayDeque.size() +
",and the element is " + pollLast);
}
}
顺便小结一下:
- 1)学习计算机要坚定地站在唯物主义的立场
- 2)计算机的本质时人充分发挥主观能动性后创造出来的工具
- 3)学习计算机知识和编程知识,也需要充分发挥主观能动性,要多实践
二、联系
1、理论
学生时期,老师经常会说到的一句话就是:举一反三,而这个举一反三,按照哲学思想来解释,就是:世界存在着普遍的联系,也确实如此,不然,马掌钉效应、多米诺骨牌效应以及蝴蝶效应就不会在国家治理、社会治理中被奉为圭臬。
说到这里,也就不得不说现今推行的教育模式的不足:文理分科,我的看法是文理并行,也只有这样才能发展成一个全面的社会主义建设者,因为理可治世、文可治人。
话说回来,考过计算机考研的,以及打算计算机考研的,都应该知道“408”的鼎鼎大名。“408” 里面包括四门计算机基础理论知识课目:计算机组成原理、计算机操作系统、计算机网络和数据结构与算法,后面的计算机理论的发展基本都是建立在这四门理论之上的。对这四门理论,我认为,不仅是打算计算机考研的人要学习,想从事计算机工作,以及想对计算机学习得更深入的,都应该花时间和精力去学习,学习的时候要记得万事万物普遍联系,要将四门理论互相串联起来。举个例子:
数据结构与算法里面,将数据类型划分为两大类:“线性结构与链式结构”,而在操作系统理论中管理存储空间的方式中也有两种方式:“顺序存储和链式存储”,但是在组成原理里面却说到:“存储器都是将存储元器件通过一定的规则连接起来”,也就是说硬件层面所有的存储器基本都是一个样的,并没有区分为所谓顺序存储器和链式存储器,只有到了操作系统层面才有这个区分。操作系统之所以有这两种存储管理方式,是建立在实际需求中的,且思考一下,你是一个招待所的管理者,接到上级的通知说有领导要入住,但是具体多少人并不知道,这个是你该怎么为这一批领导安排房间?是连着一片房间进行安排,还是隔着安排?便于管理,肯定是连着一片房间好,但是有没有可能每次都可以连着安排呢?这是不太可能的,而且在不知道具体多少人的情况下,要连着安排就更难了;隔着安排就不存在这个问题了,来一个安排一个,完全不会浪费房间。而在计算机数据存储中,所面临的情况也是这两种,“连着一片”就是顺序存储方式,“隔着安排”就是链式存储,不同实际生活中的安排房间,计算机操作系列在链式存储数据时需要一些额外的空间用于存储地址信息。具体原因就不在这里展开,想要深入的可以看我另外的博客文章。
2、实践
且先看一段 ArrayList 的使用代码:
package base.util;
import java.util.ArrayList;
import java.util.Arrays;
public class ArrayListLearn {
public static void main(String[] args) {
ArrayList<Integer> arr1 = new ArrayList<Integer>();
ArrayList<Character> arr2 = new ArrayList<>(10);
arr1.add(14);
arr1.add(32);
System.out.println("The element in arr1:");
for (Integer e : arr1){
System.out.print(e+",");
}
System.out.print(" length: " + arr1.size() + "\n");
Character[] c = {'a', 'b', 'c', 'd', 'e'};
arr2.addAll(Arrays.stream(c).toList());
System.out.println("The element in arr2:");
for (Character e : arr2){
System.out.print(e+",");
}
System.out.print(" length: " + arr2.size());
}
}
不仅是 ArrayList 允许声明对象的时候不指定空间大小,像前面的 ArrayDeque 也是如此。这是为什么呢?这是因为我们并不是每次都知道数据大小。而且虽然构造方法有两种,但实际上的实现,其实是一样的:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
而 EMPTY_ELEMENTDATA 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的声明如下:
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
都是声明成一个空 Object 数组。需要提醒的是:如果你查看 ArrayList 的源代码时,发现 EMPTY_ELEMENTDATA 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的声明形式和我上面的不一样,请不要惊慌,这是因为你和我用的JDK版本不一样、操作系统不一样,我在写本篇博文所用的系统为 Mac 系统,JDK 为 17
3、思考
为了让大家形成思考和主动学习的习惯,这里留下两个问题:
- 1)我使用 ArrayList 时,明明声明成 Integer 和 Character 对象类型的 ArrayList,可 ArrayList 在实际实现过程中却是用 Object 类型去实现?
- 2)使用指定初识空间的 ArrayList 构造方法时,如果所传形式参数大于 Integer.MAX_VALUE 会怎么样?