实习准备——Java问答题摘抄

本文章转载于CSDN博主“兴趣使然的路飞”所作文章牛客网面试宝典之JAVA基础知识(一)总结牛客网面试宝典之JAVA基础知识(二)总结小滴课堂Java集合相关面试题总结

请你讲讲数组(Array)和列表(ArrayList)的区别?什么时候应该使用Array而不是ArrayList?

  1. Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。
  2. ArrayList 存储基本类型时,会自动装箱成对应的包装类,只存其引用,而不能存基本类型!
  3. Array 大小是固定的,ArrayList 的大小是动态变化的(动态扩容数组)。
  4. ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

扩展: ArrayList源码分析

请你解释什么是值传递和引用传递?

  1. 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量;
  2. 引用传递一般是对于对象(引用)型变量而言的,传递的是该对象地址的一个副本,,并不是原对象本身 。
  3. 所以对引用对象进行操作会同时改变原对象; 一般认为,java 内的传递都是值传递;

你知道java8的新特性吗,请简单介绍一下

  1. Lambda表达式:允许把函数作为一个方法的参数(函数作为参数传递进方法中。
  2. Stream流:函数式编程,流式计算
  3. 默认方法:默认方法就是一个在接口里面有了一个实现的方法。参考文章:JDK8接口默认方法和静态方法
  4. 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。JDK8方法引用的4种形式

请你说明符号“==”比较的是什么?

  1. 如果==两边是基本类型,就比较数值是否相等。
  2. 如果==两边是对象类型,就对比两个对象基于内存引用,如果两个对象的引用完全相同(指向同一个对象)时返回true,否则返回false。

请你解释Object 中的 hashCode()是如何计算出来的?

Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法直接返回对象的内存地址。

请你解释为什么重写equals还要重写hashcode?

equals只是判断对象属性是否相同,hashcode判断二者地址是否相同。如果要判断两个对象是否相等,需要同时满足地址 + 属性都相同!

参考文章: https://jiming.blog.csdn.net/article/details/88414828

  • 如果两个对象相同(即:用 equals 比较返回true),那么它们的 hashCode 值一定要相同;
  • 如果两个对象的 hashCode 相同,它们并不一定相同(即:用 equals 比较返回 false)

请你比较一下Java和JavaSciprt?

  1. Java 是一种半编译半解释的完全面向对象的程序设计语言;JavaScript 是解释性的基于对象的脚本语言 Java 诞生于 Sun
  2. 公司,后背 Oracle 收购;JavaScript 是由 Netscape 网景公司开发
  3. Java源代码在执行前必须经过编译后才能执行;JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行 Java
  4. 采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明,JavaScript的解释器在运行时检查推断其数据类型
  5. 代码格式不一样。

扩展:为什么说 Java 是一种半解释半编译的程序设计语言呢?

什么是编译形语言,什么又是解释形语言?

  • 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,就可以直接运行这个程序。执行速度快,效率高,依靠编译器,跨平台性稍差。
  • 解释型语言:把已经做好的源程序,翻译一句,执行一句,直到结束。执行速度慢,效率低,依靠编译器,跨平台性稍好。

为什么说Java 是编译型语言呢?

第一个观点认为 Java 是编译型语言,因为Java程序想要运行,那么第一步就是要使用Javac进行编译。没有经过编译的**.java**文件,是没办法运行的!

为什么又说Java 是解释型语言呢?

那么第二个观点则是认为Java是解释型语言,Java经过编译之后,仍然需要 JVM 的解释执行,Javac 将Java源文件编译成**.class文件,然后通过JVM**的解释执行!

综合上面两个观点来看,Java似乎既有编译型语言的特点,又有解释型语言的特点,也没有看到哪本权威的书籍上认定Java就是哪一种类型的语言。

int和Integer有什么区别?

Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型,int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

Java 为每个原始类型提供了包装类型:

  • 原始类型:boolean,char,byte,short,int,long,float,double
  • 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
基本类型大小(位/bit)字节数(byte)最小值最大值默认值包装器类型
boolean--falsetruefalseBoolean
char16 bits2 bytesUnicode 0Unicode 2^16-1Character
byte8 bits1 byte-2^72^7-10Byte
short16 bits2 bytes-2~152^15-10Short
int32 bits4 bytes-2^312^31-10Integer
long64 bits8 bytes-2^632^63-10Long
float32 bits4 bytes0.0Fload
double64 bits8 bytes0.0Double
void-----Void

在这里插入图片描述
图中从左向右的转换都是隐式转换,无需再代码中进行强制转换。从右向左均要进行强制类型转换,才能通过编译。强制转换会丢失精度

我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,请你讲讲如何输出一个某种编码的字符串?

 Public String translate (String str) {
    String tempStr = "";
 try {
    tempStr = new String(str.getBytes("ISO-8859-1"), "GBK");
    tempStr = tempStr.trim();
 }
 catch (Exception e) {
    System.err.println(e.getMessage());
 }
    return tempStr;
 }

Java中的final关键字有哪些用法?

  • 修饰类:表示该类不能被继承;
  • 修饰方法:表示方法不能被重写;
  • 修饰变量:表示变量只能赋值一次且赋值以后值不能被修改(常量)

请你说明String 和StringBuffer的区别

JAVA 平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers来动态构造字符数据。

相关面试题:String/StringBuffer/StringBuilder区别

关于上述三者的区别以及源码分析,参考文章String StringBuilder StringBuffer区别以及源码分析

ArrayList如何保证线程安全?

// 答案:
// 方式一:
// synchronizedList底层相当于把集合的set add remove方法加上synchronized锁
List<Object> list = Collections.synchronizedList(new ArrayList<>());

// 方式二:
// 使用线程安全的CopyOnWriteArrayList,其底层也是对增删改方法进行加锁:final ReentrantLock lock = this.lock;

// 方式三:
// 自己写一个包装类,继承ArrayList 根据业务,对add set remove方法进行加锁控制

Vector 和 ArrayList 的初始容量和扩容?

  • 二者初始容量均为0,即在调用空参构造函数实例化时,二者容量为0,并在第一次加入元素数据时候附上初始容量值10
  • Vector扩容时,如果未指定扩容递增值capacityIncrement,或该值不大于0时,每次扩容为原来的1倍,否则扩容量为capacityIncrement的值
  • ArrayList扩容时,每次扩容为原来的1.5倍

CopyOnWriteArrayList添加新元素是否需要扩容?具体是如何做的?

CopyOnWriteArrayList 底层并非动态扩容数组,不能动态扩容,其线程安全是通过加可重入锁ReentrantLock来保证的

当向CopyOnWriteArrayList添加元素时,线程获取锁的执行权后,add 方法中会新建一个容量为(旧数组容量+1)的数组,将旧数组数据拷贝到该数组中,并将新加入的数据放入新数组尾部

因此,CopyOnWriteArrayList适用于,读多写少的情况下(读写分离)!因为每次调用修改数组结构的方法都需要重新新建数组,性能低!

4. HashMap 与 HashTable 的区别?

HashMap

  • HashMap:底层是基于数组+链表 + 红黑树,非线程安全的,默认初始容量是16、允许有空的键和值
  • 扩容:newsize= oldsize << 1,size一定为2的n次幂
  • 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀计算index方法:index = hash& (tab.length – 1)
  • 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入

HashTable

  • HashTable:底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁(synchroized)住整个HashTable,效率低,ConcurrentHashMap做了相关优化
  • 初始size为11,扩容:(tab.length << 1) + 1
  • 计算index的方法:index = (hash &0x7FFFFFFF) % tab.length

二者区别

  • HashMap不是线程安全的,HashTable是线程安全的
  • HashMap允许将null作为一个entry的key或者value,而Hashtable不允许
  • HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解
  • Hashtable继承自Dictionary类,而HashMap是Map 接口的一个实现类

HashMap与HashTable 求index桶位

  • HashMap:index = hash & (tab.length – 1)
  • HashTable:index = (hash & 0x7FFFFFFF) % tab.length

二者求桶位index的公式都是为了使每次计算得到的桶位index更分散,这样可以降低哈希冲突。

HashTable中:

  • 0x7FFFFFFF 是0111 1111 1111 1111 1111 1111 1111 1111:除符号位外的所有 1,(hash & 0x7FFFFFFF)得到的结果将产生正整数,且确保index的值在 tab.length 范围内!
  • HashTable 的数组长度采用奇数导致的hash冲突会比较少,采用偶数会导致的冲突会增多!所以初始容量为11,扩容为newsize = olesize << 1+1,保证每次扩容结果均为奇数

HashMap中:

  • 桶位计算公式:index = hash & (tab.length – 1),计算桶位index时,容量一定要为2的n次幂,即偶数,这样是为了减少hash冲突,扩容:newsize = oldsize << 1,得到的结果也是偶数
  • 此外桶中的链表长度大于8时且数组长度达到64,链表进行树化,小于6时进行反树化
  • JDK1.8前HashMap中的链表采用的是头插法,优点是:效率高于尾插法,因为不需要遍历一次链表再进行数据插入
  • JDK1.8后使用尾插法,之所以采用尾插法是因为要去判段链表的长度是否大于了8
  • HashMap解决哈希冲突的方法采用的是:链表法
  • HashMap是先插入数据再判断是否需要扩容!

HashMap和TreeMap的区别?

HashMap 上面介绍过了,直接看TreeMap

TreeMap 底层是基于平衡二叉树(红黑树),可以自定义排序规则,要实现Comparator接口,能便捷的实现内部元素的各种排序,但是性能比HashMap差

Set和Map的关系

二者核心都是不保存重复的元素,存储一组唯一的对象

Set的每一种实现都是对应Map里面的一种封装,例如HashSet 底层对应的就是封装了HashMap,TreeSet底层就是封装了TreeMap

插件Map的排序规则是怎样的?

LinkedHashMap,按照元素添加顺序排序(也可以设置成按照访问顺序排序)

TreeMap,可以按照自然排序,也可以自定义排序 TreeMap(Comparetor c)

HashMap底层为什么选择红黑树而不用其他树,比如二叉查找树,为什么不一开始就使用红黑树,而是链表长度到达8且数组容量大于64的时候才树化?

二叉查找树在特殊情况下也会变成一条线性结构,和原先的长链表存在一样的深度遍历问题,查找性能慢,例如:

在这里插入图片描述

  • 使用红黑树主要是为了提升查找数据的速度,红黑树是平衡二叉树的一种,插入新数据后会通过左旋,右旋,变色等操作来保持平衡,解决单链表查询深度的问题
  • 之所以一开始不用红黑树是因为,当链表数据量少的时候,遍历线性链表比遍历红黑树消耗的资源少 (因为少量数据,红黑树本身自选、变色保持平衡也是需要消耗资源的),所以前期使用线性表
  • 而之所以以8为树化门槛,是因为经过大量测试,8这个值是最合适的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值