美文网首页
Java 问题总结

Java 问题总结

作者: 厚积方能薄发 | 来源:发表于2020-07-28 19:57 被阅读0次

    一、基础

    1、JDK 和 JRE 的区别

    JRE(Java Runtime Environment)

    • Java 运行时环境。主要包括 Java 虚拟机和核心类库。
    • 应用场景:如果你不需要开发只需要运行Java程序,那么你可以安装JRE。例如程序员开发出的程序最终卖给了用户,用户不用开发,只需要运行程序,所以用户在电脑上安装JRE即可。

    JDK(Java Development Kit)

    Java 开发工具包,包含了 JRE 、编译器和其它工具,可以让开发者开发、编译、执行 Java 应用程序。

    2、静态方法和实例方法的区别

    对比项 静态 动态
    绑定方式 编译时静态绑定 运行时动态绑定
    对象数 整个进程中只有一份 在进程中可创建多个实例
    调用方式 不用创建实例,可以通过类.方法名调用 必须实例化后才可调用
    可重写性 不能被重写,因为它是编译时静态绑定的,而重写是基于运行时动态绑定的 非 private 的方法可重写

    3、说一下大 O 表示法

    语句执行次数是问题规模 n 的函数,记作 T(n) = O(f(n)) 。
    一般用来描述时间复杂度和空间复杂度。

    4、Exception 和 Error 的区别

    Exception

    程序本身可以处理的异常。这些是可以预料的一些异常,应该被捕获或处理。
    例:NullPointerException、ClassCastException

    Error

    程序本身不可处理的异常。
    例:内存溢出。

    5、Lamada 函数

    Lamada 函数是一种匿名函数,优点是轻量、简捷。

    二、数据类型

    三、面向对象

    1、Java 是否支持多继承

    这个要从不同的角度区分:

    • 类:只支持单继承
    • 接口:支持多继承

    2、接口和抽象类的区别

    对比项 抽象类 接口
    继承性 单继承性 多实现
    方法类型 可以有抽象方法和非抽象方法 只能有抽象方法
    实现方法 非抽象方法可以不实现 必须实现接口中的所有方法
    权限 函数也可以是 private 和 protected 函数都是 public 的
    包含对象 可包含非 final 的对象 申明的变量都是 final 的

    3、绑定 ? 静态绑定? 动态绑定 ?

    • 绑定:把一个方法与其所在的类/对象关联起来叫做方法的绑定。
    • 静态绑定:在编译的时候就已经知道方法是属于那个类的。
    • 动态绑定:在程序运行过程中,才能具体确定哪个方法属于哪个类。

    四、泛型

    五、集合框架

    1、集合类框架的基本接口有哪些

    • Collection:代表一组对象,每一个对象都是它的子元素。
    • Set:不包含重复元素的Collection。
    • List:有顺序的collection,并且可以包含重复元素。
    • Map:可以把键(key)映射到值(value)的对象,键不能重复。

    2、hashCode()和equals()方法的作用

    1. 确定索引:Java中的HashMap使用这两个方法来确定键值对的索引和取值
    2. 重复:如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。

    3、数组(Array)和列表(ArrayList)有什么区别?

    区别:

    • 存什么的:Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。
    • 大小:Array 大小是固定的,ArrayList 的大小是动态变化的。
    • ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

    使用场景:
    对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

    4、ArrayList 和 LinkedList 的区别

    • 速度:ArrayList 查询快,增删慢;LinkedList 增删快,查询慢。
    • 存储:LinkedList 更占内存,因为它不仅存储了元素内容,还多存储2个引用。

    六、多线程

    1、进程和线程的区别

    对比项 进程 线程
    作用 资源分配的最小单位 程序执行的最小单位
    资源 进程间相互独立 同一进程不同线程间相互共享
    健壮性 一个进程死掉不会影响其它线程 一个线程死掉会影响整个进程

    2、创建线程的几种方法

    1. 继承 Thread 类
    2. 实现 Runnable 接口
    3. Executor 创建线程池
    4. 实现 Callable 接口

    3、线程的几种状态

    • 新创建:创建了一个线程对象。
    • 可运行:已经调用 start 方法,正在等待 CPU 的时间片。
    • 运行:获得了 CPU 的时间片,并且正在运行。
    • 阻塞:线程因为某种原因让出了 CPU 使用权。
    • 死亡:线程执行完了 run() 或 main() 方法。

    4、什么情况会引起线程阻塞

    1. 等待阻塞:运行的线程执行了 wait 、join、sleep 方法。
    2. 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池。
    3. IO操作:发出了 IO 请求时, JVM 会把该线程置为阻塞状态。

    5、sleep、wait、join的区别

    • sleep:不释放锁让出 CPU
    • wait:释放锁让出 CPU
    • join:调用线程先阻塞,等待被调用线程释放后才执行

    6、线程锁

    什么是线程锁?

    多线程可以同时运行多个任务,但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误!
    线程锁主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。

    哪些可以作为线程锁?

    可作为线程锁的有对象锁和类锁,对象锁是用来修饰实例方法的,类锁是用来修饰静态方法的。

    对象锁:多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。

    public synchronized void obj3() {}
    
    public void obj2() {
           synchronized (this) {}
    }
    
    public void obj2() {
           String str=new String("lock");
           //在方法体内,调用一次就实例化一次,多线程访问不会阻塞,因为不是同一个对象,锁是不同的
           synchronized (str) {}
           }
       }
    

    类锁:

    public static synchronized void obj3() {}
    
    public void obj1() {
            synchronized (test.class) {}
    }
    

    类锁和对象锁同时存在时,多线程访问时不会阻塞,因为他们不是一个锁。

    死锁

    当两个线程都持有对方所需要的资源,并且同时等待对方的资源时就会造成死锁。举例:夫妻吵架,都待着对方先道歉,就会造成死锁。

    7、volatile 关键字

    L1

    • 可见性:被 volatile 修饰的变量被改变后其它线程立马可见,避免出现脏读的现象。
    • 有序性:防止指令重排序。

    为什么会出现脏读?
    Java内存模型规定所有的变量都是存在主存当中,每个线程都有自己的工作内存。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。变量的值何时从线程的工作内存写回主存,无法确定。

    L2

    计算机在执行程序时,每条指令都是在CPU中执行的,而程序运行过程中的临时数据是存放在主存(物理内存)当中的。

    执行指令过程中,势必涉及到数据的读取和写入。这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存。

    当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

    那这样就会有问题了:

    i = i + 1;
    

    假如初始值为 0,两个线程都操作主存中的变量 i,我们希望执行两次加法后 i 的值为 2,实际情况会如我们预期吗?

    可能存在下面一种情况:初始时,两个线程分别读取 i 的值存入各自所在的 CPU 的高速缓存当中,然后线程 1 进行加 1 操作,然后把 i 的最新值 1 写入到内存。此时线程 2 的高速缓存当中i的值还是 0,进行加 1 操作之后,i 的值为 1,然后线程 2 把 i 的值写入内存,最终结果 i 的值是1。

    解决这样的问题有两种方案:

    1. 总线加锁:synchronized
    2. 一致性协议:volatile

    由于在锁住总线期间,其他CPU无法访问内存,导致效率低下。所以就有了缓存一致性协议。

    MESI 协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当 CPU 写数据时,如果发现操作的变量是共享变量,会发出信号通知其他 CPU 将该变量的缓存置为无效状态,因此当其他CPU 需要读取这个变量时,发现自己缓存中该变量是无效的,那么它就会从内存重新读取。

    七、底层原理

    1、Java虚拟机原理

    L1:

    我们平常写的代码放在.java文件中,通过javac会将其编译成.class字节文件,执行的时候会将这些字节class文件载入内存并转化为机器码执行。

    L2:

    Java的类加载器将.class文件载入内存,并分配给RuntimeDataArea,执行引擎会解释或编译这些类文件,转化成特定CPU机器码,CPU执行机器码,到此结束整个过程。

    L3:

    类加载器分为4种:Bootstrap、Extention、System、UserDefined,它们分别加载系统基本API、安全性能相关、应用程序中的类(也就是classpath中配置的)、开发人员自定义一些程序需要加载的类。

    运行时区域:
    堆内存:存放对象实例。
    方法区:被虚拟机加载的类信息、常量、变量、方法。
    运行时常量池:是方法区的一部分,存放程序中使用的各种常量。

    以上这些是被线程所共享的。
    而另外一部分就是线程,而每个线程中又包括了:虚拟机栈、程序计数器、本地方法栈。
    虚拟机栈:作用是存放一系列栈帧,执行一个方法时入栈,结束时出栈。
    程序计数器:每个线程启动时会创建一个程序计数器,它用来存放当前正在被执行的字节码指令的地址。
    本地方法栈:与虚拟机栈类似,但它是用来执行native方法。

    执行引擎:
    Java的字节码,并不能被机器识别,如果想要被机器运行还要转换为机器码,而类执行引擎就是来完成这一步的,可以由其字节码解释器来转换,也可由即时编译器来转换。

    2、JVM垃圾回收算法

    1. 引用计数(Reference Counting) 比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。

    2. 标记-清除(Mark-Sweep) 此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。

    3. 复制(Copying) 此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。

    4. 标记-整理(Mark-Compact) 此算法结合了 “标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。

    5. 增量收集(Incremental Collecting) 实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。

    6. 分代(Generational Collecting) 基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。

    待总结

    参考:

    相关文章

      网友评论

          本文标题:Java 问题总结

          本文链接:https://www.haomeiwen.com/subject/pweqrktx.html