Java基础
1. 为什么重写 equals 还要重写 hashcode
hashcode 相当于身份证,而 equals 则相当于名字,名字相同的有很多,hashcode 相同的也有可能。
比如说在hashset中某一类型重写了equals我们会发现他虽然表面上看上去两个数值 equals 返回正确,但是实际上在 hashset 会分配两个 key ,因为他们的hash之后的hash值是不同的。
2. 说一下 map 的分类和常见情况
Map 不允许键重复,但允许值重复
- HashMap
根据键的 hashcode 的值来存储数据,hash 冲突使用链表,遍历时候取得的数据是随机的,允许一个 null 键,多个 null 值,不支持线程同步,可以使用 synchronzied Map 或者 concurrentHashMap - HashTable
类似于 hashmap 不同的是 HashTable 不允许键值为空,线程同步,这也导致他速度变慢。 - LinkedHashMap
HashMap 的一个子类,遍历的时候按照插入的顺序,也可以在构造时候带参数,按照自定义顺序遍历,遍历速度比 hashmap 慢 - TreeMap
实现 sortMap 接口,返回的数是按key排序之后的,默认升。
根据各自的优势判断在什么时候使用什么
3. Object如果不重写 hashcode(),hashcode() 如何计算出来。
public native int hashCode();
native 是联合 c++ 的时候使用的
4. == 比较的是什么
基本数据类型比较的是数值
对象引用类型,比较对象内存地址
###5. 若对一个类不重写,它的 equals() 方法是如何比较的?
public boolean equals(Object obj) {return (this == obj);}
结合上一题说明是比较两个对象的内存地址,也说明equals() 方法不能对基本数据类型使用
而 String 重写了 equals() 方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
先判断两个 String 内存地址,不同比较字符串数值。
6. java8新特性
-
Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。)
-
方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
-
默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
-
新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
-
Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
-
Date Time API − 加强对日期与时间的处理。
-
Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
-
Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
7. 说说Lamdba表达式的优缺点
优点:
Lambda 表达式可以使代码变的更加简洁紧凑
Lambda 表达式中使用外部定义的局部变量的时候,局部变量不再必须是final型
缺点:
可读性变得差
只能用于一种情况,那就是仅能用在接口中,且仅仅只在接口中只有一个接口方法的时候有用
8. 一个十进制的数在内存中是怎么存的?
二进制补码
9. 为啥有时会出现4.0-3.6=0.40000001这种现象?
因为十进制的小数在转化为二进制的时候会出现误差,就像十进制无法精确的表达1/3一样,二进制也无法表达1/10。
10. Java支持的数据类型有哪些?什么是自动拆装箱?
数据类型 占用字节
byte 1
short 2
int 4
long 8
float 4
double 8
char 2
boolean 1
自动装箱:自动将基本数据类型转换为包装器类型 比如int i=new Integer(1);
或其他包装器类型
拆箱:反一下
11.值传递和引用传递
值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。
引用传递:(形式参数类型是引用数据类型参数):也称为传地址。方法调用时,实际参数是对象(或数组),这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。
java类型都是值传递,但是传递的是地址
12. 数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?
Array 可以存储基础数据类型或对象,ArrayList 只能存储对象。ArrayList里面的不同的数据可以类型不同,ArrayList
Array 长度固定,ArrayList 会扩容。
ArrayList 提供更多的处理方法,add()等。
适用场景,因为ArrayList 的扩容,可以有时候对于开辟的数据数量会多,造成资源的浪费,而且数值越多,浪费的就可能会越多。所以对于那些固定长度的,无需插入删除的,可以采用数组。而对于那些需要删除等操作的,ArrayList的性能也很低。
13. 你了解大O符号(big-O notation)么?你能给出不同数据结构的例子么?
大O描述当数据结构中的元素增加时,算法的规模和性能在最坏情景下有多好。
大O还可以描述其它行为,比如内存消耗。因为集合类实际上是数据结构,因此我们一般使用大O符号基于时间,内存,性能选择最好的实现。
大O符号可以对大量数据性能给予一个很好的说明。大O符号一般对空间,时间的复杂度进行说明。
14. 如何输出某一种编码的字符串
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
String str=new String(new String("ok").getBytes("ISO-8859-1"),"GBK");
15. &和&&的区别
&会将左右两个表达式都执行,然后查看true,false;&&当左边的表达式为false之后就不执行右边的了。
&对于int型的比较会将两个int型转化为二进制,然后逐位比较,都为1则为1,其他为0,然后将结果转化为十进制输出。
16. 在Java中,如何跳出当前的多重嵌套循环?
在你需要跳出循环的地方做一个标记,然后break 到这个标记的地方。
public static void main(String[] args) {
int z=0;
//做的一个标记,如果不加这个标记,输出的应该为10,加了标记之后输出1,即直接跳出两重for循环。
Retr:
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
z++;
break Retr;
}
}
System.out.println(z);
}
17. 正则表达式,用途以及java中的使用。
正则表达式可以用来描述一些文本的规则,例如一个手机号 ^1(3|4|5|7|8)\d{9}$
表示以1开头,3或4或5或7或8是第二位剩下九位为随机0-9的数字的字符串。
java中使用:
Pattern r = Pattern.compile("^1(3|4|5|7|8)\d{9}$");
r.matcher(r).find();//true,false
[========]
Java关键字
1. Syncronized
Syncronized,一种同步锁,如果两个线程同时公用一个变量,则会导致这个变量的数据无法达到我们的要求,这个时候需要用到所,当一个线程访问这个变量的时候就将他锁起来。用完之后再释放。
(1)修饰普通方法(锁是当前实例对象)
(2)修饰静态方法(锁是当前对象的Class对象)
(3)修饰代码块(锁是Synchonized括号里配置的对象)
2.介绍一下volatile?
参考这里的
volatile作为java中的关键词之一,用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile会禁止指令重排。
并发编程中的三个概念:
- 原子性:即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
比如说一个我们需要在一个线程中执行i++
(i++分为读,i+1,写)而当读完之后之后被另一个线程打断另一个线程读取了i
的值并进行+1,而最后两个线程运行完会变为i+1,而不是i+2。 - 可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
- 有序性:即程序执行的顺序按照代码的先后顺序执行。
单线程不会因为重排序而影响最后的结果,而多线程则有可能会导致最后结果不同。
如下的例子,a与z没有数据依赖性,则有可能导致a与z进行重排序,此时,线程二会以为z为true了就跳出循环,执行equals,而此时a还为null,会出现NullPointException。//线程一 a="111"