### 1. **不使用任何优化,直接访问数据库,如何优化?**

   **优化思路**:
   - **Redo、Undo Log**的开销:数据库的事务日志(Redo和Undo日志)在事务处理过程中会产生大量的I/O操作。如果数据库没有优化,事务的回滚或提交会产生很大的性能开销。为了优化,可以减少事务的提交频率,或者批量处理多条SQL语句。
   - **批处理(Batch Processing)**:将多个SQL语句合并成一个批处理,减少与数据库的交互次数。这可以大幅降低网络延迟及数据库I/O负担。
   - **连接池(Connection Pool)**:数据库连接的创建和销毁是非常耗时的,使用连接池可以重用现有的连接,避免频繁的连接和断开数据库。常见的连接池有HikariCP、C3P0等。
   - **缓存**:使用缓存技术减少对数据库的频繁访问,例如通过Redis等内存数据库缓存热点数据。

### 2. **行锁锁的是索引,如果一个表没有主键怎么加锁?**

   如果表没有主键,InnoDB会选择使用一行记录的最左边的唯一索引作为锁定对象。如果表没有任何唯一索引,InnoDB将使用一个隐式的“隐藏主键”(实际上是一个基于行数据的聚簇索引)来执行锁定操作。由于没有显式的主键或唯一索引,锁定可能会影响性能,因此推荐给每个表添加主键或唯一索引。

### 3. **HashMap 为什么不直接用红黑树,还要用链表?**

   - **性能考虑**:HashMap的设计目的是在平均情况下提供O(1)的查找速度,而链表作为HashMap中“碰撞”处理的方式,在大多数情况下非常高效。红黑树的查找操作复杂度为O(log n),相比之下,链表的查找复杂度虽然为O(n),但是对于大多数情况下的哈希冲突,它足够快。
   - **空间和复杂度**:红黑树需要更多的内存空间来保存平衡信息。链表结构简单,占用内存较少且实现起来更容易,适合哈希表的冲突处理。
   - **链表转红黑树**:如果哈希冲突过于严重,Java 8中的HashMap会在链表长度超过一定阈值时(如8个元素)转为红黑树,从而提高性能。

### 4. **红黑树的特性?各种操作的时间复杂度?最多旋转几次达到平衡?**

   **红黑树的特性**:
   - 每个节点是红色或黑色。
   - 根节点为黑色。
   - 所有叶子节点(NIL节点)为黑色。
   - 如果一个红色节点有子节点,它的两个子节点都为黑色(即不允许有两个连续的红色节点)。
   - 从任意节点到其子孙节点的路径上,黑色节点的数量是相同的(称为黑色高度)。
   
   **时间复杂度**:
   - 插入、删除、查找的时间复杂度均为O(log n),这是因为红黑树保证了树的高度是对数级别。
   
   **最多旋转次数**:
   - 插入和删除操作在最坏情况下最多需要进行2次旋转来保持红黑树的平衡。

### 5. **finally 中 return 会发生什么?**

   - 在`finally`块中使用`return`会导致它覆盖`try`或`catch`块中的`return`,并且`finally`中的`return`会在方法执行完成之前先执行。
   - **注意**:如果在`finally`中使用`return`,方法会返回`finally`中的值,而不是`try`或`catch`中的值。这是因为`finally`块中的`return`会先执行,且覆盖了之前的`return`。
   
### 6. **如何破坏双亲委派?**

   双亲委派模型是Java类加载机制的核心原则,即加载器委托给父类加载器加载类。要破坏双亲委派模型,可以通过自定义类加载器来实现:
   - 在自定义类加载器中,重写`findClass()`方法,直接加载类文件而不委托给父类加载器。
   - 通过设置`setParent()`方法或其他方式改变父加载器,或者将父加载器设置为`null`。

### 7. **浏览器中用户信息和密码的安全有没有考虑过?**

   在浏览器中存储用户信息和密码时,需要考虑以下安全措施:
   - **加密存储**:密码应在客户端或服务器端加密存储。常用的加密算法包括AES、SHA等。
   - **SSL/TLS**:使用HTTPS协议(即SSL/TLS)加密用户和服务器之间的通信,防止信息被中间人攻击窃取。
   - **JWT**:使用JWT(JSON Web Token)来确保身份验证的安全性,并确保令牌的有效期。
   - **输入验证**:对密码和用户信息进行严格的输入验证,防止SQL注入等攻击。
   
### 8. **两个线程如何交替打印A和B?**

   可以使用`Object`的`wait()`和`notify()`方法来实现线程交替打印:
   ```java
   class PrintAB {
       private static final Object lock = new Object();
       private static boolean printA = true;

       public static void main(String[] args) {
           Thread threadA = new Thread(() -> {
               while (true) {
                   synchronized (lock) {
                       while (!printA) {
                           try {
                               lock.wait();
                           } catch (InterruptedException e) {
                               Thread.currentThread().interrupt();
                           }
                       }
                       System.out.println("A");
                       printA = false;
                       lock.notify();
                   }
               }
           });

           Thread threadB = new Thread(() -> {
               while (true) {
                   synchronized (lock) {
                       while (printA) {
                           try {
                               lock.wait();
                           } catch (InterruptedException e) {
                               Thread.currentThread().interrupt();
                           }
                       }
                       System.out.println("B");
                       printA = true;
                       lock.notify();
                   }
               }
           });

           threadA.start();
           threadB.start();
       }
   }
   ```

### 9. **100万个数,数写一篇某电商大厂某里的场景面试相关的文章,并回答以下问题:类型是int,给你8核CPU,8G内存,如何求数组的和?**

   可以利用多线程来并行计算数组的和。由于有8个核心,可以将数组分成8个部分,每个核心计算一部分的和,然后将各部分的结果相加:
   - 切分数组成8个部分。
   - 每个线程计算一个部分的和。
   - 汇总各线程的结果。
   
   **代码示例**:
   ```java
   public class SumArray {
       public static void main(String[] args) {
           int[] arr = new int[1000000];
           // 填充数组
           for (int i = 0; i < arr.length; i++) {
               arr[i] = i + 1;
           }

           int numThreads = 8;
           int chunkSize = arr.length / numThreads;
           ExecutorService executor = Executors.newFixedThreadPool(numThreads);
           List<Future<Integer>> results = new ArrayList<>();

           // 分配任务给线程
           for (int i = 0; i < numThreads; i++) {
               int start = i * chunkSize;
               int end = (i == numThreads - 1) ? arr.length : (i + 1) * chunkSize;
               results.add(executor.submit(() -> {
                   int sum = 0;
                   for (int j = start; j < end; j++) {
                       sum += arr[j];
                   }
                   return sum;
               }));
           }

           // 汇总结果
           int totalSum = 0;
           for (Future<Integer> result : results) {
               try {
                   totalSum += result.get();
               } catch (InterruptedException | ExecutionException e) {
                   e.printStackTrace();
               }
           }

           System.out.println("Total Sum: " + totalSum);
           executor.shutdown();
       }
   }
   ```

### 10. **很多个不重复的数,假设用的数组来装,我希望你实现一个方法,每次调用这个方法给我随机返回100个不重复,记住是随机的。**

   可以通过`Collections.shuffle()`方法来随机打乱数组,然后取前100个数:
   ```java
   import java.util.*;

   public class RandomSelector {
       private List<Integer> list;

       public RandomSelector(List<Integer> numbers) {
           this.list = new ArrayList<>(numbers);
       }

       public List<Integer> getRandom100() {
           Collections.shuffle(list);
           return list.subList(0, 100);
       }

       public static void main(String[] args) {
           List<Integer> numbers = new ArrayList<>();

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐