JavaSE部分之(1)Java基础

1、为什么重写 equals 还要重写 hashcode
打个比方,一个名叫张三的人去住酒店,在前台登记完名字就去了 99 层 100 号房间,
此时警察来前台找叫张三的这个人住在哪间房,经过查询,该酒店住宿的有 50 个叫张三的,
需要遍历查询,查询起来很不方便。
那么就换另外一种登记方式,前台登记时登记身份证号,警察来前台找身份证号时发现
身份证号也存在重复,经过哈希算法进行计算后相同的 hashcode 值被分到了一个房间然后
产生链表,链表查询效率非常慢,然后警察找的时候也会遇到问题。
那么只能换第三种登记方式了,前台登记时同时登记身份证号和名字,这样警察来找的
时候同时按照两个条件去查,这样就能直接锁定要找的人在哪个房间。
在程序中:登记的前台好比哈希算法,名字是对比好比 equals 方法,身份证号的对比
好比 hashcode 方法只有 equals 和 hashcode 都满足的时候才能确保是同一个对象。


当我们重写一个类的 equals 方法时就应当连同重写 hashcode 方法,并且两个方法应
满足:
a:一致性,即:当两个对象 equals 比较为 true,那么 hashcode 值应当相等,反之
亦然,因为当两个对象 hashcode 值相等,但是 equals 比较为 false,那么在 HashMap 中
会产生链表,影响查询性能。
b:成对重写,即重写 equals 就应当重写 hashcode。
2、说一下 map 的分类和常见的情况
java 为数据结构中的映射定义了一个接口 java.util.Map;它有四个实现类,分别是
HashMap、 Hashtable、 LinkedHashMap 和 TreeMap。 Map 主要用于存储健值对,不允许键
重复(重复了会覆盖掉),但允许值重复。
Hashmap 是一个最常用的 Map,它根据键的 HashCode 值存储数据,根据键可以直接
获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的; HashMap 最
多只允许一条记录的键为 Null,允许多条记录的值为 Null; HashMap 不支持线程的同步,
即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致;如果需要同步,
可以用 Collections 的 synchronizedMap 方法使 HashMap 具有同步的能力,或者使用
ConcurrentHashMap。
Hashtable 与 HashMap 类似,不同的是,它不允许记录的键或者值为空,支持线程同
步,即任一时刻只有一个线程能写 Hashtable,因此也导致了 Hashtable 在写入时会比较慢。
LinkedHashMap 是 HashMap 的 一 个 子 类 , 保 存 了 记 录 的 插 入 顺 序 , 在 遍 历
LinkedHashMap 时,先得到的记录肯定是先插入的。在遍历的时候会比 HashMap 慢;不过
有种情况例外,当 HashMap 容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap
慢,因为 LinkedHashMap 的遍历速度只和实际数据有关,和容量无关,而 HashMap 的遍历
速度和他的容量有关。
TreeMap 实现了 SortMap 接口,能够把它保存的记录根据键排序,默认是按键值的升
序排序,也可以指定排序比较器,遍历得到的记录是排过序的。
一般情况下,我们用的最多的是 HashMap,在 Map 中插入、删除和定位元素, HashMap
是最好的选择;但如果想要按自然顺序或自定义顺序遍历键,那么 TreeMap 会更好;如果
需要输出的顺序和输入的相同,那么用 LinkedHashMap 可以实现。
3、 Object 若不重写 hashCode()的话, hashCode()如何计算出来的?
Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++实现的,该方法返回的是
一个由内存地址经过散列得到的整数值。
4、 ==比较的是什么?
==比较的是两个对象的内存地址是否相同。
5、若对一个类不重写,它的 equals()方法是如何比较的?
和==比较是一样的,都是比较两个对象的内存地址是否相同。
6、 java8 新特性
1.Lambda 表达式
2.接口的默认方法与静态方法
3.方法引用
4.重复注解
5.扩展注解的支持
6.Optional 类
7.Stream API
8.Date Time API
9.JavaScript 引擎 Nashorn
10.Base64
7、说说 Lamda 表达式的优缺点。
优点:
简洁
非常容易并行计算
可能代表未来的编程趋势
缺点:
可读性不是很强
若不用并行计算,很多时候计算速度没有比传统的 for 循环快
不易调试
参考: https://blog.csdn.net/robert_chen1988/article/details/78508322
8、一个十进制的数在内存中是怎么存的?
是以二进制补码形式存储的
9、为啥有时会出现 4.0-3.6=0.40000001 这种现象?
在二进制系统中无法精确地表示分数 1/10,这就好像十进制无法精确地表示分数 1/3
一样。
如果在数值计算中不允许有任何舍入误差 ,就应该使用 BigDecimal 类。
10、 Java 支持的数据类型有哪些?什么是自动拆装箱?
八个基本数据类型: byte, short, int, long, float, double, char, boolean;以及引用
类型。
整数默认 int 型,小数默认是 double 型, float、 long 类型必须加后缀 f、 l;
自动装箱和拆箱就是基本类型和其对应引用类型之间的转换,
自动装箱: 就是将基本数据类型自动转换成对应的包装类,
自动拆箱:就是将包装类自动转换成对应的基本数据类型,
基本类型转换为引用类型后,就可以直接调用包装类中封装好的一些方法。
详见:
https://blog.csdn.net/wufaliang003/article/details/82347077
11、什么是值传递和引用传递?
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数
值的改变不影响实际参数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用被传递给方法中对应的形式参
数,方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值
的改变将会影响实际参数的值。
12、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用 Array 而不是 ArrayList?
区别:
数组的大小是固定的,列表的大小是动态变化的;
数组在声明的同时必须进行实例化(至少得初始化数组的大小),列表可以只是先
声明,之后再进行实例化;
数组可以存储基本类型和对象类型,列表只能存储对象类型(存储基本类型要用包
装类);
数组只能存储同一类型的数据,列表可以存放不同类型的数据(在没有声明泛型具
体类型的情况下);
使用选择:
如果想要保存一些在整个程序运行期间都会存在而且不变的数据,可以使用一个全
局数组;
如果只是单纯想要以数组的形式保存数据,而不对数据进行增加、删除等操作,只
是为了方便进行查找的话,可以使用 ArrayList,如果需要对元素进行频繁的移动或删除, 或
者是处理超大量的数据,使用 ArrayList 就不合适了,因为它的效率很低,可以选择使用
LinkedList。
13、你了解大 O 符号(big-O notation)么?你能给出不同数据结构的例子么?
大 O 符号描述了当数据结构里的元素增加的时候,算法的规模或性能在最坏的情况下
有多好。
比如数组的插入时间复杂度为 O(N),空间复杂度为 O(1);链表的插入时间复杂度为 O(1),
空间复杂度为 O(1)。
14、 String 是最基本的数据类型吗?
不是, String 是引用类型; String 类是 final 的,不能被继承,不能被修改;
Java 的基本类型只有八个: byte(1 字节)、 short(2 字节)、 int(4 字节)、 long(8 字节)、 float(4
字节)、 double(8 字节)、 char(2 字节)、 boolean。
15、 int 和 Integer 有什么区别
int 是 Java 的基本类型, Integer 是 int 的包装类,是引用类型;
int 的默认值为 0, Ingeter 的默认值为 null。
java 在编译 Integer i = 128 的时候,被翻译成 Integer i = Integer.valueOf(128),而 valueOf()
函数会对-128 到 127 之间的数进行缓存,如果在缓存中,就不会新建一个对象,否则,新
建一个对象;
同样适用于 Byte、 Short、 Integer、 Long、 Character,其中 Character 缓存的是 0 到 127
之间的数;
public class Java8Tester {
public static void main(String args[]) {
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2);
}
}//结果为: true
public class Java8Tester {
public static void main(String args[]) {
Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2);
}
}//结果为: false
int 类型和 Integer 类型比较,会把 Integer 自动拆箱为 int 再去比,所以,只要值相同,
两者就是相同的。
public class Java8Tester {
public static void main(String args[]) {
Integer i1 = 99999;
int i2 = 99999;
System.out.println(i1==i2);
}
}//结果为: true
16、 String 和 StringBuffer 的区别
String 类是 final 的,不可变(这就导致每次对 String 的操作都会生成新的 String 对象,
不仅效率低下,而且大量浪费有限的内存空间),
StringBuilder 和 StringBuffer(线程安全的字符串操作类,任何对它指向的字符串的操作
都不会产生新的对象。 每个 StringBuffer 对象都有一定的缓冲区容量,当字符串大小没有超
过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量)可变;
大部分情况下的执行效率: StringBuilder > StringBuffer > String,但是类似 String str =
"abc"+"def"这种情况下, String 的效率最高;
String 是线程安全的,因为 String 类是 final 的, StringBuffer 也是线程安全的,
StringBuilder 不是线程安全的。
总结一下:
String 适用于少量字符串操作的情况;
StringBuilder 适用于单线程下进行大量操作的情况;
StringBuffer 适用于多线程下进行大量操作的情况。
StringBuilder 线程不安全验证:
https://blog.csdn.net/weixin_34062469/article/details/86825792
17、我们在 web 应用开发过程中经常遇到输出某种编码的字符,如 iso8859-1 等,如何输
出一个某种编码的字符串?

 1 public class Java8Tester {
 2   public String translate(String str) {
 3     String tempStr = "";
 4     try {
 5       //按照 ISO-8859-1 进行解码
 6       byte[] b = str.getBytes("ISO-8859-1");
 7       //按照 GBK 重新进行编码
 8       tempStr = new String(b, "GBK");
 9       tempStr = tempStr.trim();
10     } catch (UnsupportedEncodingException e) {
11       e.printStackTrace();
12     }
13     return tempStr;
14   }
15 }


18、 &和&&的区别?
相同点:
&和&&都可以用作逻辑与的运算符,表示逻辑与
不同点:
&不具备短路功能, &两边都要计算,而&&具有短路功能,即&&左边为 false 结果就为
false,右边不再进行计算;
&还可以表示按位与操作,而&&不行。
19、在 Java 中,如何跳出当前的多重嵌套循环?
java 中使用带有标号的 break 语句跳出多重循环,即在外面的循环语句前定义一个标
号,然后在里层循环体的代码中使用带有标号的 break 语句,即可跳出。
20、你能比较一下 Java 和 JavaSciprt 吗?
java:面向对象,需要编译,再进行运行, 强类型;
javascript:基于对象和事件驱动,解释型语言,弱类型。
21、简述正则表达式及其用途。
在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表
达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
22、 Java 中是如何支持正则表达式操作的?
Java 中的 String 类提供了支持正则表达式操作的方法,包括: matches()、 replaceAll()、
replaceFirst()、 split()。此外, Java 中可以用 Pattern 类表示正则表达式对象,它提供了丰富
的 API 进行各种正则表达式操作。
扩展:
字符串方法 replace()、 replaceAll()、 replaceFirst()的区别和使用方法?

1 String s = "my.test.txt";
2 System.out.println(s.replace(".", "#"));
3 System.out.println(s.replaceAll(".", "#"));
4 System.out.println(s.replaceFirst(".", "#"));

运行结果:
my#test#txt
###########
#y.test.txt
解析:
“.”是正则表达式的元字符,匹配除换行符以外的任意字符,所以 replaceAll()、 replaceFirst()
才出现了意想不到的结果。
而 replace()没有用到正则表达式,但会把所有“.”替换掉,很多人可能会误解 replace()是
替换单个,而 replaceAll 是替换全部,
其实这是错的(我以前也是这么想的- -)。 replace()只是没有用到正则表达式,但会替
换所有匹配的字符串。
到这里一些不懂正则表达式的小伙伴可能就要喊坑爹了, “那我不想用正则表达式去替
换第一个字符串肿么办? ”
其实也很简单,只要将元字符串转义就行了。

1 String s = "my.test.txt";
2 System.out.println(s.replace(".", "#"));
3 System.out.println(s.replaceAll("\\.", "#"));
4 System.out.println(s.replaceFirst("\\.", "#"));

运行结果:
my#test#txt
my#test#txt
my#test.txt
23、请你说说 Java 和 PHP 的区别?
Java 是纯面向对象的语言,是编译型强类型语言;
PHP 既可面向对象,又可面向过程,是解释型弱类型语言。

猜你喜欢

转载自www.cnblogs.com/xu-xiaolong/p/10875959.html
今日推荐