Java开发成长之路

  • 第一年

这时候,作为刚刚加入“码农”行列的您,还是有几点是必须要搞定的: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方法,如下例子所示:

 
package test;

/**
 * @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等)连接,还需要知道如何通过命令行来连接。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值