• 22-08-22 西安 Mysql高级&javaSE面试题(01)“== 和 equals的区别” 、存储引擎


    一万五千年前,一根断裂又愈合的大腿骨头,标志着人类文明的起点。

    大腿骨被折断是一件极其危险的事,这其实意味着死亡,因为无法逃避危险,不能去河
    边喝水或狩猎食物,很快会被四处游荡的野兽吃掉。
    而愈合的骨头则表明:有人花了很长时间来照顾受伤的人一一处理伤口,提供食物,保护
    他不受攻击。
    从困难中学会团结,学会帮助他人,人类文明由此诞生。

     在历史长河的一个又一个节点里,人类的命运都取决于自己的选择。


    JavaSE部分面试题

    1、== 和 equals的区别

    你要是回答:‘==比较内存地址,equals比较值’,我很生气,还是哪凉快哪去吧

    ==既可以比较基本类型,又可以比较引用类型

    基本类型:比较值是否相等,对于引用类型,比较内存地址是否相等

    -------------------------

    JVM,new一个对象,实际而言堆内存的新生区的伊甸园区里面。
    结论:
    也就是说,只要是new出来的对象,100%内存地址不可能相同,
    所以,只要用==比较,一定是false

    equals是Object类的方法,看源码知道equals只能比较引用类型

    1. //以下是Object类源码中的equals方法
    2. public boolean equals(Object obj) {
    3. return (this == obj);
    4. }

    equals比较规则:

    1.没有被重写过。equals方法就是==
    2.被重写过,就具体问题,具体分析。以String类为例,equals就是比较每个字符是否相等进而决定字符串整体是否相等。

    1. //以下为String类源码部分
    2. public boolean equals(Object anObject) {
    3. if (this == anObject) {
    4. return true;
    5. }
    6. if (anObject instanceof String) {
    7. String anotherString = (String)anObject;
    8. int n = value.length;
    9. if (n == anotherString.value.length) {
    10. char v1[] = value;
    11. char v2[] = anotherString.value;
    12. int i = 0;
    13. while (n-- != 0) {
    14. if (v1[i] != v2[i])
    15. return false;
    16. i++;
    17. }
    18. return true;
    19. }
    20. }
    21. return false;
    22. }

    2、方法中实参变量值传递

    java里到底是传递值还是传递引用?注意变量的作用域范围

    一个方法里,定义的局部变量且基本类型

    则传递的是复印件,原件不动。

    一个方法里,定义的局部变量且是引用类型,

    传递的是内存地址

    测试代码

    1. public class TestValue {
    2. public static void main(String[] args) {
    3. TestValue tv = new TestValue();
    4. int age=20;
    5. tv.c1(age);//基本类型传递的是复印件
    6. System.out.println("age---"+age);
    7. User user = new User("坦然");
    8. tv.c2(user);//引用类型传递的是地址值
    9. System.out.println("userName---"+user.getName());
    10. String str="nbw";//字符串常量池
    11. tv.c3(str);//引用类型传递的是地址值
    12. System.out.println("str---"+str);
    13. }
    14. public void c1(int age){
    15. age=30;
    16. }
    17. public void c2(User user){
    18. user.setName("清融");
    19. }
    20. public void c3(String str){
    21. str="xyg";//字符串常量池
    22. }
    23. }

    运行结果

    结果分析,前2个打印结果就不说了,主要分析第三个

    String有点特殊,字符串常量池

    tv.c3(str) //传递的也是地址值

     字符串常量池,池子里面有直接复用,没有新建

       str="xyg";  //执行这个的时候,新建了一块内存放“xyg”,所以这俩str一个指向“xyg”,一个指向“nbw”。

    3、HashSet的add方法

    1. @Test
    2. public void test5(){
    3. HashSet set = new HashSet();
    4. User u1 = new User(1001L, "AA");
    5. User u2 = new User(1002L, "BB");
    6. set.add(u1);
    7. set.add(u2);
    8. System.out.println(set);
    9. //1.考点一 删除的时候会先计算 (1001L, "CC")的哈希值
    10. u1.setName("CC");
    11. boolean b = set.remove(u1);
    12. System.out.println("是否删除成功: "+b);
    13. System.out.println("考点一:"+set);
    14. //2.考点二
    15. set.add(new User(1001L,"CC"));
    16. System.out.println("考点二: "+set);
    17. //3、考点三
    18. set.add(new User(1001L,"AA"));
    19. System.out.println("考点三: "+set);
    20. }

    运行结果:当然前提是你要重写User中的equals方法和hashcode方法 ,或者加个@Data注解

    考点1:先算出来(1001L,“CC”)的哈希值,它极大概率是和(1001L,“AA”)、(1002L,“BB”)不一样的,所以在remove删除判断的时候,并没有找到该hashcode,删除失败。

    考点2:既然这个位置(1001L,“CC”)的哈希值,没有东西,那就自然可以加的进去了,所以set里元素是3个,且看着俩个User长的一样

    考点3:再加(1001L,“AA”),它和现在的第一处的(1001L,“CC”)是在同一处数组的索引,所以再在这个元素后面加链


    4、HashMap初始化容量问题

    设置初始容量大小的必要性

    HashMap中的扩容机制决定了每次扩容都需要重建hash表,是非常影响性能的。 随着元素的不断增加,HashMap会有可能发生多次扩容

    设置初始化容量为多少

    结论:

    当我们明确知道HashMap中元素的个数(initialCapacity )的时候,把默认容量(构造器的参数)设置成 initialCapacity/ 0.75F + 1.0F

    但是,JDK并不会直接拿用户传进来的数字当做默认容量,而是会进行一番运算,最终得到一个2的幂

    不使用这个公式:

    如果我们设置的默认值是7(明确要存储7个元素,然后构造器的参数也就傻乎乎的传了7),经过Jdk处理之后,会被设置成8,但是,这个HashMap在元素个数达到 8*0.75 = 6的时候就会进行一次扩容,这明显是我们不希望见到的。

    使用公式 initialCapacity/ 0.75F + 1.0F

    7/0.75 + 1 = 10 ,10经过Jdk处理之后,会被设置成16,这就大大的减少了扩容的几率。

    为什么必须是2的n次幂?如果输入值不是2的幂比如10会怎么样?

    在确定要存储的元素在数组中的具体位置时,HashMap用某种算法尽量把数据分配均匀,这样每个链表长度大致相同,这个算法实际就是取模。

    但是:计算机中直接求余效率不如位移运算

    实际上hash%length等于hash&(length-1)的前提是length是2的n次幂

    2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1

    20%16=4

    20&(2^4-1)=20&15= 4

       0001 0100

    & 0000 1111

    ------------------

       0000 0100

    默认情况下HashMap的容量是16,但是,如果用户通过构造函数指定了一个数字作为容量,那么Hash会选择大于该数字的第一个2的幂作为容量。(3->4、7->8、9->16)

    1. //HashMap类源码
    2. //构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap
    3. public HashMap(int initialCapacity) {
    4. this(initialCapacity, DEFAULT_LOAD_FACTOR);
    5. }

    存储引擎

    MySQL从上到下分为4层:连接-服务-引擎-存储

    1、MySQL逻辑架构

    mysql插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。让我们可以根据业务的需求和实际需要选择合适的存储引擎。

    连接层,并不属于mysql

    • java----jdbc---mysql

    服务层

    • 查询mysql的自带的缓存,有的话不用调用mysql更多的后台内容
    • SQL接口分析,分析sql语句的语法,语法验证
    • 漏斗分分类,到底是读还是写、还是定义语句
    • 查询优化器,mysql自身认为最优的效果返回,不见得你最喜欢

    引擎层,插件式的存储引擎架构,有10多个以上。

    • 用的最多的MyISAM、InnoDB
    在不同的环境,可以拔插式处理,换不同的引擎,mysql还是那个mysql,维护成本急剧下降
    

    存储层

    • 数据真正是放在硬盘上

    2、存储引擎InnoDB和MyISAM

    查看MySQL的存储引擎,默认是Innodb

    SHOW ENGINES;

    结果解析 

    InnoDB和MyISAM区别

    前3个要知道。。。

    MyISAM 一锁就是锁住了整张表,在并发写的时候InnoDB性能远超MyISAM。而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁

    MyISAM允许没有主键的表存在。InnoDB表必须有主键,如果没有设定主键,就会自动生成一个 6 字节隐藏列作为主键列(用户不可见)。

    MyISAM使用非聚集索引,索引和数据分开,只缓存索引;InnoDB使用聚集索引,主索引和数据存在一个文件。


    3、SQL执行流程

    SQL语句在MySQL中的执行流程是:

    1.查询缓存就是如果在缓存中发现了这条SQL语句,就会直接将结果返回给客户端了;如果没有命中缓存,再进入到解析器阶段。但是缓存的命中率并不高,MySQL8.0开始就没有缓存了

    1. # 查看缓存的状态
    2. SHOW VARIABLES LIKE '%query_cache_type';

    query_cache_type有3个值,

    • 0代表关闭查询缓存OFF
    • 1代表关闭查询缓存ON
    • 2代表DEMAND(按需使用)
    1. #SQL_CACHE 指定该条sql使用查询缓存
    2. SELECT SQL_CACHE * FROM test WHERE id=5;
    3. #SQL_NO_CACHE 指定该条sql使用不使用缓存
    4. SELECT SQL_NO_CACHE * FROM test WHERE id=5;

    2.解析器,也叫分析器。在解析器中对SQL语句进行语法分析、语义分析。SQL没啥问题就会生成解析树。

    Mysql服务端程序要从文本中将具体的请求含义解析出来,如查询什么字段,查询哪一些表等

    经过解析器,MySQL就知道你要做什么了

    3.优化器,在优化器中会确定SQL语句的执行路径。比如全表检索还是根据索引检索。优化的结果就是生成一个执行计划,就是平常我们使用Explain关键字看到的一个结果。

    一条查询SQL可以有很多种执行方式,最后都会返回相同的结果。优化器的作用就是找到这其中最好的执行计划

    4.执行器。优化器会把执行计划交给执行器,执行器要先判断用户是否具备权限,如果有权限,就打开表继续执行。打开表的时候,执行器会根据表的引擎定义,调用存储引擎API对表进行读写。

    Mysql中,将对数据存储和提取的操作抽取到了一个叫存储引擎的模块中。在逻辑上,我们看到的是表的数据是一行行的形式,但实际物理层面上,表的数据如何存储、如何读取表的数据、这都是存储引擎需要负责的操作,Mysql中提供了不同的存储引擎,不同的存储引擎存储的数据结构可能不相同,采用的算法也可能不同

  • 相关阅读:
    20. Spring源码篇之@Lookup详解
    raw文件检索规则
    @设计模式-代理模式
    Xmake v2.8.5 发布,支持链接排序和单元测试
    计算机基础(三):C语言与汇编
    关于webpack(v5.74.0)的钩子在插件中的应用
    Docker系列第01部分:介绍+虚拟化+什么是Decker+组件
    多目标优化算法合集
    scrollIntoView锚点跳转 超好用
    麻省理工学院与Meta AI共同开发StreamingLLM框架,实现语言模型无限处理长度
  • 原文地址:https://blog.csdn.net/m0_56799642/article/details/126474019