java基础面试题总结(2)—— JDK基础

JAVA SE基础

1.ArrayList、LinkedList、Vector的特性及存储性能(持续更新)

  • ArrayList和Vector都继承了AbstractList,前者线程不安全,后者线程安全
  • ArrayList基于数组结构实现,查找速度快,插入和删除速度慢,LinkedList则相反,因为其是基于双向链表实现
  • ArrayList通过实现AbstractList,能够随机访问,而LinkedList实现的是AbstractSequentialList,仅能顺次访问

2.HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap(持续更新)

  • HashMap线程不安全,Hashtable对每个操作都进行同步,线程安全;前者可以存在一个null的key,value可以为null,后者不能为null

3.简述JVM内存结构中的heap和stack(持续更新)

  • heap即堆内存,存放对象数据,自动增加容量,存取较慢,线程共享
  • stack即栈内存,存放方法的局部变量、基本数据类型、对象引用、方法调用登,线程独占

4.GC是什么? 为什么要有GC?

  • GC是Garbage Collection的缩写,即垃圾回收
  • 这里所谓的垃圾,指的是那些不再被使用的对象,JVM的垃圾回收机制使得开发人员从无聊、容易犯错的手动释放内存资源的过程中解放出来。
  • 开发人员可以更加专注的进行业务功能的开发,而资源回收的工作交由更加专业的垃圾回收机制自动完成

5.关于String的知识点

  1. String s = new String("xyz"); 创建了几个String Object? :
    创建了2个String对象,首先传入的"xyz"是一个String对象,然后new的过程又创建了一个String对象

6.abstract的方法是否可以是static的?是否可以是synchronized的?

  • 不能是static的:抽象方法是不能分配内存的,而static的方法在类加载时就已经分配内存,所以不能共存
  • 不能是synchronized的:方法同步的时候需要获取该方法所属实例对象的同步锁,但是abstract的方法是没有所属实例对象的,所以无法synchronized

7.lock与Synchronize的区别?lock的基本使用方法及特性(持续更新)

  • Lock是一个接口,需要进行同步操作时,可实例化一个Lock(ReentrantLock),当前线程即占有这个Lock对象锁,而不像Synchronized那样需要制定持有某个特定的对象锁,这样能够避免Synchronized容易出现的死锁情况
  • 线程无法自动释放Lock,需要手动unlock(通常在finally)中,因此如果不手动释放的话也会造成死锁
  • Lock对象通过.lock()方法让线程占有锁,也可以通过lock.tryLock(long timeout, TimeUnit unit)方法来指定获取锁的时间,如果超时则返回false,放弃获取锁(也就放弃执行某同步方法)
  • Lock实现同步的方式也是CAS机制,ReentrantLock中执行lock()操作的是内部抽象类Sync的实现,ReentrantLock实例化时默认是采用非公平锁(NonfairSync)这个实现:
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

可以看出,首先采用CAS机制来修改对象头中的锁标志位,CAS机制有三个重要参数:内存位置(V)、预期原值(A)和新值(B), 其中0就是期望的标志位原值A,1就是期望的标志位新值B;最终会调用一个native方法compareAndSwapInt()来使用CPU的CAS机制进行CAS操作,来不断尝试获取锁

  • Lock的CAS机制是一种典型的乐观锁机制,可以避免线程进入阻塞状态造成线程上下文切换降低性能;但是锁竞争太激烈的话,反而会造成性能低下;
  • Lock的Condition对象用法:使用Condition对象可以实现传统的wait()和notify()的目的,用Condition实现生产者-消费者模式:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 阻塞栈,用于存放Mantou对象
 */
public class SyncStack {
    volatile int index = 0;//栈内当前Mantou数量,需保证线程可见
    Lock lock = new ReentrantLock();//初始化锁
    Condition condition = lock.newCondition();//初始化Condition对象用于线程间通信
    Mantou[] mantous;

    public SyncStack(int size) {
        //初始化栈内容器的大小
        mantous = new Mantou[size];
    }

    /**
     * 将Mantou放入栈中,每放一个,index就增加一个,然后将等待池中的线程唤醒
     * 执行该方法前若检测若index已满则执行await,执行push()的线程进入Lock的等待池
     * @param mantou
     */
    public void push(Mantou mantou){
        //获取同步锁
        lock.lock();
        try{
            while(index == this.mantous.length){
                condition.await();
            }
            this.mantous[index] = mantou;
            index++;
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 将栈顶的Mantou拿出来,每拿一个,index就减少一个,然后将等待池中的线程唤醒
     * 执行该方法前若检测index为空则执行await,执行get()的线程进入Lock等待池
     * @return
     */
    public Mantou get(){
        lock.lock();
        try{
            while(index == 0){
                //设置等待时间,一旦超时就返回false,退出该方法
                if(!condition.await(30, TimeUnit.SECONDS)){
                    return null;
                }
            }
            index--;
            condition.signalAll();
            return this.mantous[index];
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return null;
    }
}
public class Mantou {
    int id;
    String owner;
    public Mantou(int id, String owner){
        this.id = id;
        this.owner = owner;
    }

    @Override
    public String toString() {
        return owner + "的" +String.valueOf(id);
    }
}
/**
 * 生产者线程,持续调用push方法向阻塞栈放入Mantou对象
 */
public class Producer implements Runnable{
    SyncStack syncStack;
    public Producer(SyncStack syncStack) {
        this.syncStack = syncStack;
    }
    @Override
    public void run() {
        //持续放入8个Mantou
        for(int i = 0; i<8; i++){
            Mantou mantou = new Mantou(i, Thread.currentThread().getName());
            syncStack.push(mantou);
            System.out.println(Thread.currentThread().getName()+":生产了" + mantou + "号馒头!!!");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
/**
 * 消费者线程,持续调用get方法从阻塞栈取出Mantou对象
 */
public class Consumer implements Runnable{
    SyncStack syncStack;
    public Consumer(SyncStack syncStack) {
        this.syncStack = syncStack;
    }
    @Override
    public void run() {
        Mantou mantou;
        //一旦获取Mantou超时,则退出
        while((mantou = syncStack.get())!=null) {
            System.out.println(Thread.currentThread().getName() + ":拿到了" + mantou + "号馒头!!!");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + ":靠!居然没有了!艹!走了!");
    }
}

测试:

    public static void main(String[] args){
        SyncStack syncStack = new SyncStack(10);
        Consumer consumer = new Consumer(syncStack);
        Producer producer = new Producer(syncStack);
        Thread consumerThread1 = new Thread(consumer);
        Thread consumerThread2 = new Thread(consumer);
        Thread consumerThread3 = new Thread(consumer);
        Thread producerThread1 = new Thread(producer);
        Thread producerThread2 = new Thread(producer);
        consumerThread1.setName("消费者1");
        consumerThread2.setName("消费者2");
        consumerThread3.setName("消费者3");
        producerThread1.setName("生产者甲");
        producerThread2.setName("生产者已");
        producerThread1.start();
        producerThread2.start();
        consumerThread1.start();
        consumerThread2.start();
        consumerThread3.start();

跟传统的wait和notifyAll方式大同小异

8. 反射中Class.forName()和ClassLoader.loadClass()的区别

反射中,Class.forName()和ClassLoader的方法loadClass()都可以通过类名加载类并返回类的Class对象,但是两者有一些区别:

  • Class.forName()实际调用的是forName0(className, true, ClassLoader.getClassLoader(caller), caller),这个过程默认将进行类加载->链接->初始化这一系列过程
  • ClassLoader的方法loadClass()实际调用的是ClassLoader.loadClass(className,false)这个方法,第二个参数表示不进行链接及初始化,仅仅进行类加载
  • 所有如果加载某个类需要进行链接及初始化操作,就需要调用Class.forName()这个方法来获取Class对象
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,690评论 0 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,559评论 18 399
  • 如果我能够如此幸运,希望你能早点来到我身边陪伴我每一天。 如果你能够早点遇见我,希望我是最好的我,你也是最好的你。...
    O习惯远距离阅读 199评论 0 1
  • 抛(打油诗) 谁家女娇娃, 高楼抛丝袜。 以为你是谁, 天女来散花?
    老爸的杂拌儿糖阅读 969评论 26 50
  • 清晨,我推开四叶窗, 丝缕阳光洒满了房间的角落, 阳台上的植物破土冒尖, 麻雀慵懒地梳着行头, 清风拂面,我笑了。...
    刺鱼儿阅读 513评论 0 3