Java 面试

1、ArrayList和LinkedList的区别

2、@Autowired和@Resource的主要区别

3、集合

4、mysql索引失效的几种情况

5、string,stringbuffer、stringbulider的区别

6、&和&&的区别

7、sql的执行顺序

8、设计模式

9、五大原则

10、垃圾回收算法

 11、Lock 接口实现类

 

 

1、ArrayList和LinkedList的区别

ArrayList:

 底层数据结构:

  ArrayList基于数组实现,元素在内存中连续存储,支持随机访问(时间复杂度为o(1));

  LinkedList基于双向链表实现,节点离散存储并通过指针关联,不支持随机访问(时间复杂度为O(n));

 随机访问:

  ArrayList通过索引直接访问元素;

  LinkedList需遍历链表,效率较低;

 插入、删除:

  ArrayList在末尾插入/删除效率较高(时间复杂度O(1)),中间插入/删除需移动后续元素,(时间复杂度O(n));

  LinkedList在任意位置插入/删除仅需修改节点指针引用,效率较高(时间复杂度O(1)),但需遍历链表定位节点。 ‌

 扩容机制:arrayList默认容量不足时自动扩容为原容量的1.5倍,LinkedList无需扩容

  • ‌优先选择ArrayList‌:当需要频繁随机访问元素或尾部操作较多时(如排行榜、购物车等)。 ‌
  • ‌优先选择LinkedList‌:当需要频繁在中间或首尾插入/删除元素时。 ‌

 

2、@Autowired和@Resource的主要区别

  1-- @Autowired是spring框架,@Resource是Java标准注解;

  2-- @Autowired优先于按照类型(bytype)匹配,然后名称匹配(byname),冲突时需显式指定@qualifier;

   @Resource优先于按照名称(byname)进行匹配,然后按照类型(bytype)进行匹配;

  3-- @Autowired支持构造方法注入、属性注入、setter方法注入、方法参数注入

            @Resource仅支持属性方法与setter方法注入,使用构造方法注入会报错。

3、集合

  1.collection

    list(有序集合,可以包含重复元素,允许插入null元素) : arrayList(动态数组)、linkedList(双向链表)

    set (无序集合,不包含重复元素):hashSet(不保证元素的顺序)、linkedHashSet(保持元素的插入顺序)

  2、map(用于存储键值对)

    hashMap(允许使用空值和空键)、LinkedHashMap(维护插入顺序或者访问顺序)

4、mysql索引失效的几种情况

  ---1 索引列参与了计算:查询条件中对索引列进行了数学运算、函数操作或者其他非索引列的操作

  ---2 索引列使用了函数

  ---3 隐式类型转换  :比较列类型和比较值类型不匹配时,mysql会进行类型转换

  ---4 使用通配符like

  ---5 or条件中的列没有被索引:使用or连接多个条件时,如果每个条件中的列都没有被索引,那么整个查询都没有被索引

  ---6 复合索引的不正确使用:如果查询条件没有从索引的最左列开始,那么mysql可能不会使用该复合索引

5、string,stringbuffer、stringbulider的区别 

  String

  • ‌不可变‌:每次修改都会生成新对象,导致内存浪费。 ‌
  • ‌线程安全‌:不可变特性使其天然具备线程安全性。 ‌
  • ‌适用场景‌:存储常量、作为方法参数传递等不需要修改的场景。 ‌

  StringBuffer

  • ‌可变‌:支持内容修改,方法同步(线程安全)。 ‌
  • ‌性能‌:因同步机制,性能较低,适合多线程环境。 ‌
  • ‌适用场景‌:多线程环境下需要频繁修改字符串(如日志处理)。 ‌

  StringBuilder

  • ‌可变‌:支持内容修改,非线程安全。 ‌
  • ‌性能‌:无同步开销,效率更高,适合单线程。 ‌
  • ‌适用场景‌:单线程中频繁拼接字符串(如循环生成动态文本)。‌

  

6、&和&&的区别

  & 和 && 的核心区别在于短路特性:&& 具有短路功能(若左侧表达式为假则跳过右侧计算),

  & 无论左侧结果如何都会计算右侧表达式;此外,& 还支持位运算,而 && 仅用于逻辑运算。‌‌

7、sql的执行顺序

   FROM:指定要查询的表。
  JOIN:根据指定的条件,将两个或多个表合并为一个结果集。
  WHERE:对查询结果进行筛选,只保留满足指定条件的行。
  GROUP BY:将结果集按照指定的列进行分组。
  WITH ROLLUP:按照GROUP BY的列对结果集进行汇总,并添加一行用于总计或小计。
  HAVING:对分组后的结果进行筛选,只保留满足指定条件的分组。
  SELECT:选择要查询的列。
  DISTINCT:对查询结果进行去重。
  UNION:将两个或多个查询结果集合并为一个结果集。
  ORDER BY:按照指定的列对结果集进行排序。
  LIMIT:指定查询结果的行数限制。

9、五大原则

SOLID 原则

  • S - 单一职责原则:一个类应该只有一个引起变化的原因。

  • O - 开放封闭原则:软件实体应该对扩展开放,对修改关闭。

  • L - 里氏替换原则:子类必须能够替换掉它们的父类。

  • I - 接口隔离原则:不应该强迫客户依赖于它们不用的方法。

  • D - 依赖倒置原则:要依赖于抽象,不要依赖于具体实现。

10、垃圾回收算法 

垃圾回收算法是自动管理内存的机制,用于回收不再使用的对象所占用的内存空间。以下是常见的垃圾回收算法及其原理:

引用计数法

  • 原理:通过记录对象的引用次数,当引用计数为0时回收对象。
  • 优点:实现简单,回收效率高。
  • 缺点:无法处理循环引用,计数器开销大。 ‌

标记-清除算法

  • 原理:分为标记和清除两阶段,标记存活对象后清除未标记对象。
  • 适用场景:存活对象较多的老年代。
  • 缺点:易产生内存碎片,需扫描整个空间两次。 ‌

复制算法

  • 原理:将存活对象复制到新内存区域,并清空原区域。
  • 适用场景:存活对象较少的新生代。
  • 缺点:需要额外内存空间,需复制对象。 ‌

标记-整理算法

  • 原理:标记存活对象后将其压缩到内存一端,清理边界外空间。
  • 适用场景:老年代,避免碎片且无需额外内存。 ‌

分代收集算法

  • 原理:将堆分为新生代和老年代,分别采用复制算法和标记-整理算法。
  • 优点:结合不同算法优势,提高回收效率。

11、Lock 接口实现类

  在Java中,Lock接口是java.util.concurrent.locks包的一部分,提供了比使用synchronized方法和语句更灵活的线程同步机制。Lock接口的实现类提供了比内置的同步机制更多的功能,例如尝试非阻塞地获取锁、尝试在给定的等待时间内获取锁、以及在释放锁之前执行一些清理操作等。

    • 以下是Java中一些常见的Lock接口实现类的例子:

      1. ‌ReentrantLock‌

        • ReentrantLock是最常用的Lock实现类之一。它实现了Lock接口,支持重进入(reentrant),意味着在同一个线程中可以多次获取锁。
        • 示例代码:
          import java.util.concurrent.locks.ReentrantLock;
          
          public class ReentrantLockExample {
              private final ReentrantLock lock = new ReentrantLock();
          
              public void criticalSection() {
                  lock.lock();
                  try {
                      // 保护的代码块
                  } finally {
                      lock.unlock();
                  }
              }
          }

           

      2. ‌ReentrantReadWriteLock‌

        • ReentrantReadWriteLock是一种读写锁实现,允许多个读线程同时访问,但写线程在访问时需要独占访问权。它包含了一对锁:一个用于读操作,一个用于写操作。
        • 示例代码:
          import java.util.concurrent.locks.ReentrantReadWriteLock;
          
          public class ReentrantReadWriteLockExample {
              private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
              private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
              private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
          
              public void read() {
                  readLock.lock();
                  try {
                      // 读取操作
                  } finally {
                      readLock.unlock();
                  }
              }
          
              public void write() {
                  writeLock.lock();
                  try {
                      // 写入操作
                  } finally {
                      writeLock.unlock();
                  }
              }
          }

           

      3. ‌StampedLock‌

        • StampedLock是Java 8中引入的一种乐观读锁,它提供了比读写锁更灵活的锁定模式。它可以用于读操作,也可以用于写操作,并且支持乐观读(即非阻塞读)。
        • 示例代码:
          import java.util.concurrent.locks.StampedLock;
          
          public class StampedLockExample {
              private final StampedLock stampedLock = new StampedLock();
              private int value = 0;
          
              public void write(int newValue) {
                  long stamp = stampedLock.writeLock(); // 获取写锁
                  try {
                      value = newValue; // 执行写操作
                  } finally {
                      stampedLock.unlockWrite(stamp); // 释放写锁
                  }
              }
              
              public int read() {
                  long stamp = stampedLock.readLock(); // 获取读锁(乐观读)
                  try {
                      return value; // 读取数据
                  } finally {
                      stampedLock.unlockRead(stamp); // 释放读锁(乐观读)
                  }
              }
          }

           

        选择哪种锁取决于你的具体需求,例如是否需要公平性、是否需要重入性、是否需要读写分离等。每种锁都有其特定的使用场景和性能特点。通常,ReentrantLock是最通用和最灵活的选择,而ReentrantReadWriteLock适合于读多写少的场景。StampedLock则提供了一种更高级的乐观读锁定。

posted @ 2025-10-13 22:55  krt-wanyi  阅读(6)  评论(0)    收藏  举报