- 第一年
这时候,作为刚刚加入“码农”行列的您,还是有几点是必须要搞定的:Java语法、行业代码规范(类、方法、变量等的命名规范)、计算机基本的运行原理、Java程序运行的基本原理。我这里说的“搞定”的更加准确的含义指的是:要很掌握的很熟练。因为这就像是楼梯的第一个台阶、高楼大厦的地基一样,它直接影响你后续阶段的发展。
您别小瞧这几点,以为在学校里就早早地对Java语法很了解了;不止您在成长,Java本身也在发展中,所以Java的不同版本之间可能也会有或大或小、或多或少的差异,忽略这一点的童鞋可能会被“绊脚石”磕碰的很惨。
程序是运行在计算机上的,为了以后的发展,可以说对计算机的原理研究的不管多么深入都是很有必要的。但现在,你至少要对CPU、内存、硬盘、网卡等大部件的性能参数有所了解。
而Java呢,是需要编译为class文件(而不是机器码),然后在虚拟机(JVM)上运行的。这一点,决定了Java是跨平台(Linux、Windows等)的,也决定了它可能会比C语言要运行的慢一点。它的内存管理机制,又决定了Java是比较耗内存的——虽然所占用的内存并不是时时刻刻都需要的。
以上三点相对来说都是比较范范的东西,下面我来说一下对于初出茅庐的Java程序员们有哪些技能是必须掌握的,换句话说说,掌握了下面的内容你就可以轻松应对一些面试了:
- Java接口、类(抽象)的概念
接口可以理解为是一种规范、标准、协议,而并不关心具体实现过程。接口中的方法只能使用public、abstract来修饰,而属性只能是用public、static、final来修饰。换句话说,在接口中即使不添加任何修饰符也可以,因为它只能添加那些修饰符——方法必然是public abstract的,而属性一定是public static final的。根据接口中属性的特点,我们可以推断,在申明属性变量时必须给赋初始值,而且不能被修改。
如果有人要问,在接口的方法上添加abstract或者不添加有没有区别的话,从上文就可以推断出——是一样的。对应的属性也是这个道理。
普通类中,所有的方法必须要有方法体——也就是说必须要有实现,同样的方法不可以使用abstract来修饰。类只允许继承一个类,但是可以实现多个接口。类A实现类B,可以理解为类A也是一种B;而类A实现接口B、C,则可以理解为类A有B和C的特性(特点)。
而抽象类,就像是接口和普通类的结合体,方法既可以有抽象的(abstract)的,也可以没有。对属性则没有任何限制。另外,由于抽象类中有可能有抽象方法,所以是无法直接进行实例化的。
- Java的集合(Collection)体系
这是必须要弄明白的,在日常工作中跟它打交道的次数太多了。首先是java.util.Collection这个接口,它是集合的顶层接口,另外要留心它所在的包(package)是java.util。它的子接口包括List、Set,List的实现类包括:ArrayList、LinkedList、Vector。Set的实现类包括:HashSet、LinkedHashSet、TreeSet。
ArrayList的内部是用动态数组(普通数组的容量必须在初始化时给定)实现的,根据数组下标来对元素进行操作,具有访问快速、修改较慢的特点,这些是由于ArrayList的存储结构导致的。如果调用无参构造函数的话,会把内部数组elementData赋值一个空数组;如果调用的是带有一个int类型参数(容量capacity)的构造函数的话,会创建一个指定大小的数组。在调用add方法时,会先检查当前数组是否可以在容纳一个元素(这时候,保证至少会有10的容量),如果不够的话就准备扩容(最大容量为Integer.MAX_VALUE)——先是创建一个新容量的数组,然后把之前的元素拷贝过去,最后把要添加的元素加入新的数组中。
根据以上ArrayList类的特点,我们可以总结出一些ArrayList的使用技巧:如果您估计ArrayList中要添加的元素个数超过10个的话,最好调用有int参数的构造函数给定一个初始容量,这样能有效地避免频繁扩容导致的频繁申请内存(堆),甚至能避免一些不必要的gc事件;ArrayList适合读取和修改操作较多的场合,而不适合于添加或者删除较多的场合;ArrayList并没有实现了多线程之间的同步,所以是线程不安全的。
LinkedList<E>实现的是双向链表(Doubly-linked),另外还实现了接口java.util.Deque<E>。它有add、addFirst、addLast、addAll等方法,add等同于addLast,set方法可以添加到指定位置。调用get方法时,它会从所有的元素中遍历查找。所以,LinkedList和ArrayList相反,插入、新增速度快,查找速度慢。另外,它也是线程不安全的。
Vector<E>除了实现了List接口外还实现了java.util.RandomAccess接口,默认的容量为10,内部也是用数组的形式实现的。它的add以及其他操作元素的方法使用了关键字synchronized,因此是线程安全的,也可以认为Vector是线程安全版本的ArrayList。
TreeSet<E>内部是利用TreeMap实现的,调用add方法时其实就是向map中添加一条key,value的值统一都是Object类。
HashSet<E>内部是利用HashMap实现的。add方法实现过程与TreeSet类似。
Java集合体系中的java.util.Map比较特殊,和Collection不是一类,它本身就是顶层接口。它的实现类包括:HashMap、Hashtable。
HashMap<K,V>默认的构造函数会初始化一个容量(应该是2的倍数,最大容量为Integer.MAX_VALUE / 2 + 1,或者为1 << 30)为10、因子(load factor)为0.75的集合,之后调用init方法(默认为空实现,是让子类来扩展的)。
HashMap第一次调用put方法时,内部会调用方法inflateTable来初始化,所以说如果只是申明了一个Map对象后并不会占用任何空间。从这里可以看到HashMap内部也是通过数组实现的,数组的元素类型为HashMap.Entry;而Entry类包含了key、value、下一个Entry的引用、hash值。而当key为null时,则内部会调用方法putForNullKey,把key为null的Entry会放到数组的第一个。这时候会通过hash方法来计算key的hash值,hash方法会先调用key对象的hashCode,然后再进行一些hash运算。之后利用hash值和数组的长度计算出来一个数组下标值,如果数组中的该下标(index)中已经有了Entry对象,则从Entry链中通过hash查找是否已经存在了相同的key,有的话更新;没有的话,则新增一个Entry放到数组的该下标中,然后该Entry指向之前的Entry,形成一个Entry链。
从上面对HashMap的分析,可以得出一些结论。它内部是由多个元素类型为HashMap.Entry的数组实现,因此占用的内存空间还是比较大的。key可以为null。它从Java1.6开始出现,是非线程安全的。
Hashtable实现了抽象类Dictionary<K,V>。它从Java1.0开始出现。它的初始化过程和HashMap类似,但初始容量(capacity)为11,因子(load factor)为0.75f。
Hashtable的put方法使用关键字(synchronized)保证了线程间的同步,当key或者value为空(null)时会抛出空指针异常。
TreeMap<K,V>实现了接口NavigableMap<K,V>。该集合和HashMap实现的过程类似,只是在调用put方法时就会先对key进行排序。这个排序就要求key实现接口Comparator<? super K>,或者是在实例化TreeMap时给定一个Comparator。
NavigableMap<K,V>该接口继承了接口SortedMap<K,V>,从Java1.6开始出现。
- Java流(Stream)体系
- Java异常(Exception)体系
Java的异常体系的根类是java.lang.Throwable,它有两个子类java.lang.Error和java.lang.Exception。
Error是比较严重的错误,基本会在程序无法继续执行的情况下抛出,我们无法捕获更无法处理。
Exception是“编译时”异常的根类,它的子类java.lang.RuntimeException是“运行时”异常。所谓编译时指的是在编译Java源文件时抛出的异常,必须在处理(捕获或者抛出)后源文件才可以正常编译;所谓运行时异常,指的是在Java程序运行过程中有“可能”抛出的异常。
除了Error之外,编译时异常也是比较验证的异常情况,所以必须显示地处理。而运行时异常通常不严重,即遇到了这种异常情况程序也还是可以继续的。
- Java多线程(Thread)
实现一个多线程类,可以实现接口java.lang.Runnable或者类java.lang.Thread。这里要注意的是类Thread也实现了接口Runnable。启动一个线程要调用start方法,如下例子所示:
/**
* @author suren
* @date 2016年6月29日 下午1:58:37
*/
public class Test
{
public static void main(String[] args) throws Exception
{
new ThreadTestA().start();
new Thread(new ThreadTestB()).start();
}
static class ThreadTestA extends Thread
{
@Override
public void run()
{
System.out.println("from thread test a.");
}
}
static class ThreadTestB implements Runnable
{
@Override
public void run()
{
System.out.println("from thread test b.");
}
}
}
线程间同步,可以在类或者方法上使用关键字synchronized。
另外,还有个线程相关的知识点。使用Thread.sleep和Object.wait相比较,前者会一直占用CPU,而后者会放弃CPU的控制权。
- JSP原理
JSP(Java Server Pages)作为常用的一种动态页面技术,有几个很关键的地方是必须理解清楚、正确的,这也是作为一个合格、称职、专业的程序员所应该了解的。
首先,从JSP的字面上来说,它一定是服务器端(后端)的技术,而不是前端技术,不可以和HTML混为一谈。和其他的动态页面技术不同,它是需要编译的——当它被访问时,将会由JSP引擎编译(class字节码文件);如果是在Tomcat中运行的话,编译后的字节码文件会保存在目录work/Catalina/localhost/${webroot}/org/apache/jsp中。
那JSP编译完的class文件是什么呢?从它所继承(实现)的类上看,就能一目了然了。它继承了类org.apache.jasper.runtime.HttpJspBase,实现了接口org.apache.jasper.runtime.JspSourceDependent。
而HttpJspBase是个抽象类,它继承了抽象类javax.servlet.http.HttpServlet,实现了接口javax.servlet.jsp.HttpJspPage。
接口JspSourceDependent是为了能够跟踪JSP源码文件的依赖关系,从而能够编译过期的JSP文件。
- jQuery常用方法
这里至少应该知道如何使用jQuery定位元素、设置(获取)值、ajax请求。
jQuery有类(class)选择器、名称(tagname)选择器、ID选择器、属性(attribute)选择器、派生选择器等。
- JavaScript基本概念
- 各种浏览器的调试技巧
本站有一篇《JavaScript调试介绍》您可以搜索一下,介绍了各种主流浏览器的JavaScript调试方法和技巧。
- 集成开发工具Eclipse的熟练使用
本站有一篇《Eclipse使用技巧》您可以搜索一下,介绍了Eclipse的一些使用技巧。
- 应用服务器配置
本章有一篇《玩转Tomcat》您可以搜索一下,介绍了Tomcat所有常用的配置方法。
- 数据库
除了要会使用数据库的带有界面的客户端(例如:Navicat等)连接,还需要知道如何通过命令行来连接。