Java工程师面试1000题131-140

131、看程序说出执行结果

public class MyTest2 {
    public static void main(String[] args) {
        System.out.println(MyParent2.str);
    }
}

class MyParent2{
    public static final String str = "hello world";
    static {
        System.out.println("MyParent2 static block");
    }
}

输出:

hello world

解析:常量在编译阶段会存入到调用这个常量的方法所在类的常量池中。在本题中就是MyTest2类中的主函数里面调用了这个常量,所以在这里就是将常量存放到了MyTest2的常量池中。之后,MyTest2与MyParent就没有任何关系了,甚至我们可以将MyParent2的class文件删除了。本质上,调用类并没有直接引用到定义常量的这个类(MyParent2),因此并不会触发定义常量的这个类(MyParent2)的初始化,没有初始化,就不会执行静态代码块,所以只会输出一行。

132、知道JVM反编译指令和常见的助记符吗?

反编译指令:javap -c xxx.class

助记符(特别特别多):

ldc : 表示将int,float或是String类型的常量值从常量池中推送至栈顶

bipush:表示将单字节(-128-127)的常量值推送至栈顶

sipush:表示将一个短整型常量值(-32768 - 32767)推送至栈顶

iconst_1:表示将int类型1推送至栈顶(只有iconst_m1、iconst_0 - iconst_5这7个)

anewarray:表示创建一个引用类型的数组(如类、接口、数组),并将其引用值压入栈顶

newarray:表示创建一个指定的原始类型的数组(如int、float、char等),并将其引用值压入栈顶

......................

133、看下面这题和131题的区别

import java.util.UUID;
public class MyTest3 {
    public static void main(String[] args) {
        System.out.println(MyParent3.str);
    }
}

class MyParent3{
    public static final String str = UUID.randomUUID().toString();
    static {
        System.out.println("MyParent3 static code");
    }
}

打印结果:

MyParent3 static code
c8fed399-b99c-4639-96a9-777bfe5e017a

为什么静态代码块里面的代码会执行呢?str都是常量,131题中静态代码块里的程序就没有执行啊!问题的关键是,这个常量的值在编译器是否可以确定下来,131题中,常量的值在编译期已经确定下来了,但是在本题中,常量的值在编译期无法确定下来,由于使用了UUID和随机函数。

知识点:当一个常量的值并非在编译期间就可以确定的,那么其值就不会被放到调用类的常量池中,这时候在程序运行时会导致主动使用这个常量所在的那个类,显然就会导致那个类的初始化。

134、开发中有没有遇到过内存溢出?内存溢出原因有哪些?怎么解决?

引起内存溢出的原因有很多,常见的有以下几种:

  1. 内存中加载的数据量过于庞大,比如一次从数据库中取出过多的数据
  2. 集合类中有对象的引用,使用完后未清空,使得JVM不能回收
  3. 代码中存在死循环或循环产生过多重复的对象实体
  4. 使用第三方软件中有bug
  5. 启动参数内存设置的值太小

解决方案:

  1. 修改JVM启动参数,直接增加内存(-Xms,-Xmx参数一定不要忘记加)
  2. 检查错误日志,查看“OutOfMemory”错误前是否有其他异常或错误
  3. 对代码进行走查和分析,找出可能发生内存溢出的位置

重点排查以下几点:

  1. 检查对数据库查询中,是否有一次获得全部数据的查询操作,一般来说,如果一次获取10万条记录到内存时,就有可能引起内存溢出,这个问题比较隐蔽,再上线前,数据库中数据比较少,不容易出问题,上线后,数据库中记录多了,一次查询就有可能引起内存溢出,因此对于数据库查询尽量采用分页的方式查询。
  2. 检查代码中是否有死循环或者递归调用
  3. 检查是否有大量循环重复产生新对象实体
  4. 检查List、Map等集合对象是否有使用完未清除的问题。List、Map等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。可以使用内存查看工具动态查看内存使用情况。

135、JDBC操作数据库流程?

  1. Class.forName()加载数据库连接驱动
  2. DriverManager.getConnection()获取数据连接对象
  3. 根据SQL获取sql会话对象,有两种方式:Statement、PreparedStatement;
  4. 执行SQL处理结果集,执行SQL前如果有参数值就设置参数值setXXX()
  5. 关闭结果集,关闭会话,关闭连接

136、为什么要使用PreparedStatement?

  1. PreparedStatement接口继承自Statement,PreparedStatement实例包含已编译的SQL语句,所以其执行速度要快于Statement对象。
  2. 作为Statement的子类,PreparedStatement继承了Statement的所有功能,三种方法execute、executeQuery、executeUpdate已被更改以使之不再需要参数。
  3. 在JDBC应用中,在任何时候都不要使用Statement,原因如下:
  • 代码的可读性和可维护性Statement需要不断地拼接,而PreparedStatement不会。
  • PreparedStatement尽可能提高性能,DB有缓存机制,相同的预编译语句再次调用不会再次编译
  • 最重要的一点就是极大地提高了安全性,Statement容易被SQL注入,而PreparedStatement传入的内容不会和SQL语句发生任何匹配关系。

137、关系数据库中连接池的机制是什么?

前提:为数据库连接建立一个缓冲池。

  1. 从连接池获取或创建可用连接
  2. 使用完毕之后,把连接返回给连接池
  3. 在系统关闭前,断开所有连接并释放连接占用的系统资源
  4. 能够处理无效链接,限制连接池中的连接总数不低于或者不超过某个限定值。

最小连接数是连接池一直保持的数据连接。如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费掉。

最大连接数是连接池能申请的最大连接数,如果数据连接请求超过此数,后面的连接请求将被加入到等待队列中。

如果最小连接数与最大连接数相差太大,那么,最先的连接请求会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接,不过,这些大于最小连接数的数据库连接在使用完不会马上释放,他将被放到连接池中等待重复使用,或是空闲超时后被释放。

总结:数据库连接池连接数量一直保持一个不少于最小连接数的数量,当数据不够时,数据库会创建一些连接,直到一个最大连接数,之后连接数据库就会等待。

138、TRUNCATE和DELETE的区别是什么?

DELETE命令从一个表中删除某一行,或多行,TRUNCATE命令永久地从表中删除每一行。

139、什么是触发器,MySQL中都有哪些触发器?

触发器是指一段代码,当触发某个事件时,自动执行这些代码。在MySQL数据库中有如下六种触发器:

  • 1、Before Insert

  • 2、After Insert

  • 3、Before Update

  • 4、After Update

  • 5、Before Delete

  • 6、After Delete

140、请说明InnoDB和MyISAM的区别

  • InnoDB支持事务,MyISAM不支持;

  • InnoDB数据存储在共享表空间,MyISAM数据存储在文件中;

  • InnoDB支持行级锁,MyISAM只支持表锁;

  • InnoDB支持崩溃后的恢复,MyISAM不支持;

  • InnoDB支持外键,MyISAM不支持;

  • InnoDB不支持全文索引,MyISAM支持全文索引;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值