Java基础面试

HashMap的特性

1.考察目标

  • HashMap底层的数据结构
  • HashMap和Hashtable的区别

2. 题目分析

  • Map集合的特点

  • Map是一个双列集合,将键映射到值的对象

    • Map集合的数据结构,只针对键有效,跟值没有关系
  • Map集合的键不能重复,并且一个键最多只能映射到一个值

  • HashMap集合的数据结构是什么?

    • 哈希表结构:数组 + 链表
      • 通过哈希表结构配合对象类型的hashCode和equals方法就可以保证键的唯一性
      • 建议:今后Map集合中键是对象类型的,不要忘记重写它的hashCode和equals方法
  • HashMap和Hashtable的区别是?

    相同点:

    • 都是双列集合,一个键对应一个值
    • 都是键不能重复,但是值可以重复

    不同点:

    • HashMap是JDK1.2版本出现的,允许存储null键和null值

      Hashtable是JDK1.0版本出现的,不允许存储null键和null值

    • HashMap是不同步的,线程不安全

      Hashtable是同步的,线程安全

    应用场景:

    • 双列集合优先使用HashMap集合
    • 如果是在多线程的场景下,也无需使用Hashtable集合,我们可以使用ConcurrentHashMap集合。该集合时一个线程同步的。
    • Hashtable集合虽然使用不多,但是它有一个给力的子类:Properties集合还在大量使用中,一般配合IO流来加载配置文件!

3. 问题扩展

  • JDK1.8之后,哈希表结构引入了二叉树

    • 提高了查询的效率
  • JDK1.8版本之后,某一个索引下的节点数量达到一定程度的时候,会把原本的链表结构,改成二叉树结构

TreeSet集合:二叉树结构(数据能够排序)

二叉树取数据:先取节点左边的,当左边的全部获取完毕,再取自己,最后取节点右边的

4. 应用场景

用于商品出现次数的统计

/**
 * 统计商品出现次数的使用场景----HashMap
 * 关键是键的对象类型必须重写hashCode和equals方法
 */
public class Demo02_HashMap {
    public static void main(String[] args) {
        Goods g1 = new Goods("小米手机", 1000);
        Goods g2 = new Goods("平板电脑", 7000);
        Goods g3 = new Goods("小米手机", 1000);

        List<Goods> goodsList = new ArrayList<>();
        goodsList.add(g1);
        goodsList.add(g2);
        goodsList.add(g3);
        // HashMap用来计数
        Map<Goods, Integer> countMap = new HashMap<>();
        for (Goods goods : goodsList) {
            if (!countMap.containsKey(goods)) {
                // 代表Map集合中不存在该商品
                countMap.put(goods, 1);
            } else {
                // 代表Map集合中已经存在该商品
                countMap.put(goods, countMap.get(goods)+1);
            }
        }

        System.out.println(countMap);
    }
}

class Goods{
    private String name;
    private Integer price;

    // 省略构造、getter、setter、toString、hashCode、equals方法
}
============================================================
控制台结果:
{Goods{name='小米手机', price=1000}=2, Goods{name='平板电脑', price=7000}=1}

Java虚拟机中的内存模型

1. 考察目标

  • JVM(虚拟机)的内存划分
  • 不同的数据使用的是那一块内存空间

2. 题目分析

  • Java虚拟机有哪几块内存空间

    • 栈内存

      方法运行时所进入的内存,里面还会存储程序的局部变量

    • 堆内存

      new出来的数据都会进入堆内存

    • 方法区

      字节码文件加载时所进入的内存


    • 本地方法区:这块内存空间主要调用的是操作系统相关资源

      被native修饰的方法是使用了本地方法区的

      public static native long currentTimeMillis(); // 获取1970-1-1至今的毫秒值
      
    • 寄存器:交给CPU进行使用的

  • 案例:创建Student类并使用,画出数据在内存中的分布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HqjSYDj-1602545177026)(C:\Users\Administrator\Desktop\面试题\image\1.PNG)]

3. 问题扩展

  • 案例:带有线程的内存图

    • 每一个线程都会有自己独立的栈内存空间

    • 堆内存中的数据,是被多个线程所共享的(该数据就是共享资源)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sm7tgjZP-1602545177029)(C:\Users\Administrator\Desktop\面试题\image\2.PNG)]

4.应用场景

  • 多线程消费同一商品,可以将该商品库存定义为共享资源,存放于堆内存中

例如:

  1. 写一个售票窗口类,将车票数定义为共享资源
public class Ticket implements Runnable {
		// 多线程共享的票数资源
    int ticket = 100;
  
    @Override
    public void run() {
        while(true) {
            synchronized (Ticket.class){
                if (ticket <= 0) {
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "卖出了第-" + ticket-- + "-号票");
            }
        }
    }
}
  1. 多线程共享车票数
public class Demo01_Memory {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        new Thread(t, "窗口1").start();
        new Thread(t, "窗口2").start();
    }
}

String类型

1. 考察目标

  • String属于什么数据类型
  • String常用的方法
  • String创建对象有什么特点

2. 题目分析

  • String属于什么数据类型?

    • 数据类型:

      基本数据类型:byte、short、int、long、float、double、char、boolean

      引用数据类型:类、数组、接口、枚举

    • String属于引用数据类型,因为String被final修饰,所以不能被继承

  • String常用的方法?

    equals(Object o) // 比较字符串的内容是否相同
    equalsIgnoreCase(Object o) // 忽略大小比较字符串
    length() // 获取字符串的长度
    contains(String s) // 判断是否包含传入的字符串
    substring(int start) // 从start索引开始截取字符串
    substring(int start, int end) // 从start索引开始到end索引结束截取字符串,[start, end)
    toLowerCase() // 把字符串转换为小写字符串
    toUpperCase() // 把字符串转换为大写字符串
    String[] split(String regex) // 根据传入的字符串切割原字符串,返回的是字符串数组;如果切割的是.的话,传入的字符串应该写"\\."
    

    需要注意的点:

    1. substring(int start, int end) 包含start索引的字符,不包含end索引的字符
    2. split(String regex) 参数是正则字符串,一些特殊字符串如“.”的话,应该写成“\\.”
  • String创建对象有什么特点?

    问题:String s = new String("xyz")一共创建了多少次对象?

    回答:字符串常量都是String对象。如果常量池中存在,则直接调用;不存在则创建。

    ​ 而new关键字一定是创建了对象。所以该问题分两种情况:

    ​ “xyz”在常量池中没有,则创建了两次对象;

    ​ “xyz”在常量池中存在,则创建了一次对象。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tCJXcFMv-1602545177031)(C:\Users\Administrator\Desktop\面试题\image\3.PNG)]

3. 应用场景

  • String它被用于裁剪,拼接。搜索字符串,比较字符串,截取字符串,转换大小写等。

  • 在项目中不经常发生变化的业务场景中,优先使用String

举例:

  1. 用户登录需要验证账号密码,我们需要使用equals方法进行判断

  2. 用户登录中需要填写验证码,我们可以使用equalsIgnoreCase方法进行忽略大小写判断

String,StringBuilder,StringBuffer三者的区别

1. 考察目标

  • String和StringBuilder的效率对比
  • StringBuilder和StringBuffer的效率对比

2. 问题分析

  • 问题:String和StringBuilder的本质区别?
    • String是一个不可改变的字符序列,底层是被final修饰的char类型数组
    • StringBuilder是一个可变的字符序列,字符串的缓冲区(提高效率)
  • 问题:常见的字符串拼接,该选择谁

3. 问题扩展

  • 在工作中你们如果在业务层去拼接sql,使用String类型去接收的吗?

4. 应用场景

ingBuilder的效率对比

  • StringBuilder和StringBuffer的效率对比

2. 问题分析

  • 问题:String和StringBuilder的本质区别?
    • String是一个不可改变的字符序列,底层是被final修饰的char类型数组
    • StringBuilder是一个可变的字符序列,字符串的缓冲区(提高效率)
  • 问题:常见的字符串拼接,该选择谁

3. 问题扩展

  • 在工作中你们如果在业务层去拼接sql,使用String类型去接收的吗?

4. 应用场景

  • 在项目中如果频繁地拼接字符串,推荐使用StringBuilder
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值