Skip to content

java基础

面向对象

和面向过程进行区分,面向过程比较直接高效,而面向对象更易于复用、扩展和维护

面向对象的特性:封装、继承、多态

JDK、JRE、JVM

  • JDK:Java Development Kit 开发工具
  • JRE:Java Runtime Environment 运行环境
  • JVM:Java Virtual Machine 虚拟机

=== 和 equals

对比变量的值和变量存储的地址

hashCode和equals

hashCode() 是获取哈希码(散列码),它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,Java 中的任何类都包含有hashCode() 函数。

  • 如果两个对象相等,则hashcode一定也是相同的
  • 两个对象相等,对两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashcode值,它们也不一定是相等的
  • 因此,equals方法被覆盖过,则hashCode方法也必须被覆盖
  • hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个
  • 对象无论如何都不会相等(即使这两个对象指向相同的数据)

final关键字的作用

  • 修饰类:表示类不可被继承
  • 修饰方法:表示方法不可被子类覆盖,但是可以重载
  • 修饰变量:表示变量一旦被赋值就不可以更改它的值
  • 修饰基本数据类型的变量,则其数值一旦在初始化之后便不能更改
  • 修饰引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是引用的值是可变的

String、StringBuffer、StringBuilder

  • String是不可变的,如果尝试去修改,会新⽣成一个字符串对象,StringBuffer和StringBuilder是可变的
  • StringBuffer是线程安全的,StringBuilder是线程不安全的,所以在单线程环境下StringBuilder效率会更高

重载和重写

  • 重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
  • 重写:发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围 小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法。

接口和抽象类

  • 抽象类可以存在普通成员函数,而接口中只能存在public abstract 方法
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。
  • 抽象类只能继承一个,接口可以实现多个

泛型中extends和super的区别

  • <? extends T>表示包括T在内的任何T的子类
  • <? super T>表示包括T在内的任何T的父类

List & Set

  • List:有序,按对象进入的顺序保存对象,可重复,允许多个NULL元素对象,可以使用Iterator取出所有元素,在逐一遍历,还可以使用get() 获取指定下标的元素
  • Set:无序,不可重复,最多允许有一个NULL元素对象,取元素时只能用Iterator接口取得所有元素,在逐一遍历各个元素

ArrayList & LinkedList

  • 底层数据结构不同,ArrayList底层是基于数组实现的,LinkedList底层是基于链表实现的
  • 由于底层数据结构不同,他们所适用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加,查询、添加、删除的时间复杂度不同
  • 另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用

HashMap & HashTable

  • HashMap方法没有synchronized修饰,线程非安全,
  • HashTable线程安全,HashMap允许key和value为NULL,而HashTable不允许

底层实现:数组+链表实现,jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在

  • 计算key的hash值,二次hash然后对数组长度取模,对应到数组下标
  • 如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组
  • 如果产生hash冲突,先进行equal比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到
  • 并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表
  • key为NULL,存在下标0的位置

java中有哪些类加载器

  • BootStrapClassLoader:默认负责加载%JAVA_HOME%lib下的jar包和class文件
  • ExtClassLoader:负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类
  • AppClassLoader是自定义类加载器的父类,负责加载classpath下的类文件

父子类的关系 BootStrapClassLoader -> ExtClassLoader -> AppClassLoader

类加载器的双亲委派模型

JVM在加载一个类时,会调用AppClassLoader的loadClass方法来加载这个类,不过在这个方法中,会先使用ExtClassLoader的loadClass方法来加载类, 同样ExtClassLoader的loadClass方法中会先使用BootstrapClassLoader来加载类, 如果BootstrapClassLoader加载到了就直接成功,如果BootstrapClassLoader没有加载到,那么ExtClassLoader就会自己尝试加载该类, 如果没有加载到,那么则会由AppClassLoader来加载这个类。

所以,双亲委派指得是,JVM在加载类时,会委派给Ext和Bootstrap进行加载,如果没加载到才由自己进行加载。

GC如何判断对象是否能被回收

  • 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收,
  • 可达性分析法:从GCRoots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GCRoots没有任何引用链相连时,则证明此对象是不可用的,那么虚拟机就判断是可回收对象。

GCRoots的对象有

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

JVM线程共享区

  • 堆区和方法区是所有线程共享的,
  • 栈、本地方法栈、程序计数器是每个线程独有的

JVM问题排查

  • 使用jmap来查看JVM中各个区域的使用情况
  • 通过jstack来查看线程的运行情况,比如哪些线程阻塞、是否出现了死锁

By Modify.