春秋招java后端方向技能全面突破-基础篇04

ClassLoader

对于定义,ClassLoader类是一个抽象类,是一个负责加载classesde的对象,一个典型的策略是把二进制名字转换成文件名然后到文件系统中找到该文件。

对于类加载,最重要的就是它的双亲委派机制,这里从源码的角度来重新分析一下

1、BootstrapClassLoader(祖父)

  • 下边简称为boot
  • 为ExtClassLoader的父类,但是通过ExtClassLoader的getParent()获取到的是null(在类加载器部分:null就是指boot)
  • 主要加载:jdk1.6\jre\lib\*.jar(最重要的就是:rt.jar)

2、ExtClassLoader(爷爷)

  • 下边简称为ext
  • java编写,位于sun.misc包下,该包在你导入源代码的时候是没有的,需要重新去下
  • 主要加载:jdk1.6\jre\lib\ext\*.jar(eg.dnsns.jar)

3、AppClassLoader:(爸爸)

  • 下边简称为app
  • java编写,位于sun.misc包下
  • 主要加载:类路径下的jar

4、自定义类加载器(儿子)

  • 下边简称为custom
  • 自己编写的类加载器,需要继承ClassLoader类或URLClassLoader,并至少重写其中的findClass(String name)方法,若想打破双亲委托机制,需要重写loadClass方法
  • 主要加载:自己指定路径的class文件

 这里有一个全盘概念(!!假设ClassLoaderA要加载class B,但是B引用了class C,那么ClassLoaderA先要加载C,再加载B,"全盘"的意思就是,加载B的类加载器A,也会加载B所引用的类

这是经过注释以后的源码,包含了整个委派过程:

/**
     * 根据指定的binary name加载class。
     * 步驟:
     * 假设我现在从类路径下加载一个类A,
     * 1)那么app会先查找是否加载过A(findLoadedClass(name)),若有,直接返回;
     * 2)若没有,去ext检查是否加载过A(parent.loadClass(name, false)),若有,直接返回;
     * findBootstrapClassOrNull(name) 3)4)5)都是这个方法
     * 3)若没有,去boot检查是否加载过A,若有,直接返回;
     * 4)若没有,那就boot加载,若在E:\Java\jdk1.6\jre\lib\*.jar下找到了指定名称的类,则加载,结束;
     * 5)若没找到,boot加载失败;
     * findClass(name) 6)7)8)9)都是这个方法
     * 在findClass中调用了defineClass方法,该方法会生成当前类的java.lang.Class对象
     * 6)ext开始加载,若在E:\Java\jdk1.6\jre\lib\ext\*.jar下找到了指定名称的类,则加载,结束;
     * 7)若没找到,ext加载失败;
     * 8)app加载,若在类路径下找到了指定名称的类,则加载,结束;
     * 9)若没有找到,抛出异常ClassNotFoundException
     * 注意:在上述过程中的1)2)3)4)6)8)后边,都要去判断是否需要进行"解析"过程
     */
    protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        Class c = findLoadedClass(name);//检查要加载的类是不是已经被加载了
        if (c == null) {//没有被加载过
            try {
                if (parent != null) {
                    //如果父加载器不是boot,递归调用loadClass(name, false)
                    c = parent.loadClass(name, false);
                } else {//父加载器是boot
                    /*
                     * 返回一个由boot加载过的类;3)
                     * 若没有,就去试着在E:\Java\jdk1.6\jre\lib\*.jar下查找 4)
                     * 若在bootstrap class loader的查找范围内没有查找到该类,则返回null 5)
                     */
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                //父类加载器无法完成加载请求
            }
            if (c == null) {
                //如果父类加载器未找到,再调用本身(这个本身包括ext和app)的findClass(name)来查找类
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

大致流程如下:

1)那么app会先查找是否加载过A,若有,直接返回;

2)若没有,去ext检查是否加载过A,若有,直接返回;

3)若没有,去boot检查是否加载过A,若有,直接返回;

4)若没有,那就boot加载,若在E:\Java\jdk1.6\jre\lib\*.jar下找到了指定名称的类,则加载,结束;

5)若没找到,boot加载失败;

6)ext开始加载,若在E:\Java\jdk1.6\jre\lib\ext\*.jar下找到了指定名称的类,则加载,结束;

7)若没找到,ext加载失败;

8)app加载,若在类路径下找到了指定名称的类,则加载,结束;

9)若没有找到,抛出异常ClassNotFoundException

ArrayList

       ArrayList是可以动态增长和缩减的索引序列,它是基于数组实现的List类。

       ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。(由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

       ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

       ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

  该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个capacity属性,表示它们所封装的Object[]数组的长度,当向ArrayList中添加元素时,该属性值会自动增加。如果想ArrayList中添加大量元素,可使用ensureCapacity方法一次性增加capacity(注意此处扩充capacity的方式是将其向右一位再加上原来的数,实际上是扩充了1.5倍),可以减少增加重分配的次数提高性能。

这里提一点,调用 toArray() 函数会抛出“java.lang.ClassCastException”异常,因为Java不支持向下转型,我们可以通过调用 toArray(T[] contents) 返回T[]来解决。

public static Integer[] vectorToArray2(ArrayList<Integer> v) {
    Integer[] newText = (Integer[])v.toArray(new Integer[0]);
    return newText;
}

这里插入讲一点fail-fast的知识(当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了,那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。当然,解决办法建议使用“java.util.concurrent包下的类”去取代“java.util包下的类”。)

LinkedList(是非同步的

首先要明确LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList 实现 List 接口,能对它进行队列操作。同时也实现 Deque 接口,即能将LinkedList当作双端队列使用。

在说Linkedlist之前,先说说它所继承的父类AbstractSequentialList,在里面实现了实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。

然后来说说LinkedList所包含两个重要的成员:header 和 size。
  header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。 
  而size是双向链表中节点的个数。

   通过实现遍历发现,千万不要使用随机变量,使用removeFist()或removeLast()效率最高。

通过removeFirst()来遍历LinkedList

try {
    while(list.removeFirst() != null)
        ;
} catch (NoSuchElementException e) {
}

 通过removeLast()来遍历LinkedList

try {
    while(list.removeLast() != null)
        ;
} catch (NoSuchElementException e) {
}

猜你喜欢

转载自blog.csdn.net/qq_40901379/article/details/83988794