知识点总结中。持续更新。。。

一、Java 基础

1. JDK 和 JRE 有什么区别?

  • JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
  • JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。

具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。

举个简单的例子,就是说,JRE就是地球,java就是人类,JDK就是人类的办公环境。因为人类只有在地球上才能生存,有了生存环境,才能正常的使用办公环境进行工作。

2. == 和 equals 的区别是什么?

== 解读

对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  • 基本类型:比较的是值是否相同;
  • 引用类型:比较的是引用是否相同;
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。

equals 解读

equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。

首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

class Cat {
    public Cat(String name) {
        this.name = name;
    }
 
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
 
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

原来 equals 本质上就是 ==。

那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:

String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true

同样的,当我们进入 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 重写了 Object 的 equals 方法,把引用比较改成了值比较。

总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

2. 附加。5 个刁钻的 String 面试题!我差点翻车!

查看微信的收藏夹里面内容,还是很不错的。

3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

不对,两个对象的 hashCode()相同,equals()不一定 true。

代码示例:

String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d",  str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));

执行的结果:

str1:1179395 | str2:1179395

false

代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。

4. final 在 java 中有什么作用?

  • final 修饰的类叫最终类,该类不能被继承。
  • final不能用于修饰构造方法。 
  • final 修饰的方法不能被重写。
  • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。(修饰的常量不能改变,但是修饰的是对象的时候,对象中的属性是可以修改的);
  • 高效,编译器在遇到final修饰的方法的时候,会实现内嵌机制,大大提高执行效;

5. java 中的 Math.round(-1.5) 等于多少?

等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。

6. String 属于基础的数据类型吗?

String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。

Java中8种基本数据类型总结

序号

数据类型

大小/位

封装类

默认值

可表示数据范围

1

byte(位)

8

Byte

0

-128~127

2

short(短整数)

16

Short

0

-32768~32767

3

int(整数)

32

Integer

0

-2147483648~2147483647

4

long(长整数)

64

Long

0

-9223372036854775808~9223372036854775807

5

float(单精度)

32

Float

0.0

1.4E-45~3.4028235E38

6

double(双精度)

64

Double

0.0

4.9E-324~1.7976931348623157E308

7

char(字符)

16

Character

0~65535

8

boolean

8

Boolean

flase

true或false

7. java 中操作字符串都有哪些类?它们之间有什么区别?


操作字符串的类有:String、StringBuffer、StringBuilder。

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

注意:说StringBuffer线程安全,是因为在其内部的方法里面,使用了很多的锁synchronized,但是StringBuilder没有,再多线程并发的时候,不能保证数据的原子性了。

8. String str="i"与 String str=new String("i")一样吗?

具体的扩展信息,可以看2.附加。

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。

9. 如何将字符串反转?

使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

示例代码:

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder.reverse()); // gfedcba

10. String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。


11. 抽象类必须要有抽象方法吗?

不需要,抽象类不一定非要有抽象方法。

示例代码:

abstract class Cat {
    public static void sayHi() {
        System.out.println("hi~");
    }
}

上面代码,抽象类并没有抽象方法但完全可以正常运行。

12. 普通类和抽象类有哪些区别?

  • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
  • 抽象类不能直接实例化,普通类可以直接实例化。

13. 抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息:

14. 接口和抽象类有什么区别?

实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。


15. java 中 IO 流分为几种?

按功能来分:输入流(input)、输出流(output)。

按类型来分:字节流和字符流。

字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

16. BIO、NIO、AIO 有什么区别?

BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

17. Files的常用方法都有哪些?

Files.exists():检测文件路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。



二、容器

18. java 容器都有哪些?

常用容器的图录:

需要注意的内容:

  1. ArrayList:数组实现,初始化大小(无参构造是0,有参构造就是传入参数的大小)
    transient Object[] elementData;
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    注意扩充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容量),而后用Arrays.copyof()方法将元素拷贝到新的数组(详见下面的第3点)。从中可以看出,当容量不够时,每次增加元素,都要将原来的元素拷贝到一个新的数组中,非常之耗时,也因此建议在事先能确定元素数量的情况下,才使用ArrayList,否则建议使用LinkedList。

  2. ①、当通过 ArrayList() 构造一个空集合,初始长度是为0的,第 1 次添加元素,会创建一个长度为10的数组,并将该元素赋值到数组的第一个位置。

      ②、第 2 次添加元素,集合不为空,而且由于集合的长度size+1是小于数组的长度10,所以直接添加元素到数组的第二个位置,不用扩容。

      ③、第 11 次添加元素,此时 size+1 = 11,而数组长度是10,这时候创建一个长度为10+10*0.5 = 15 的数组(扩容1.5倍),然后将原数组元素引用拷贝到新数组。并将第 11 次添加的元素赋值到新数组下标为10的位置。

  3. java.util.Arrays 类 -- (https://www.cnblogs.com/ysocean/p/8616122.html

  4. java.util.LinkedList 类 -- 

    注意:相对于 ArrayList 集合,LinkedList 集合多实现了一个 Deque 接口,这是一个双向队列接口,双向队列就是两端都可以进行增加和删除操作。

                   LinkedList 是没有初始化链表大小的构造函数,因为链表不像数组,一个定义好的数组是必须要有确定的大小,然后去分配内            存空间,而链表不一样,它没有确定的大小,通过指针的移动来指向下一个内存地址的分配。

                   看到上面向 LinkedList 集合中添加元素的各种方式,我们发现LinkedList 每次添加元素只是改变元素的上一个指针引用和下一           个指针引用,而且没有扩容。,对比于 ArrayList ,需要扩容,而且在中间插入元素时,后面的所有元素都要移动一位,两者插入元           素时的效率差异很大,下一篇博客会对这两者的效率,以及何种情况选择何种集合进行分析。

                   remove(Object o)  如果存在,则从该列表中删除指定元素的第一次出现

   此方法本质上和 remove(int index) 没多大区别,通过循环判断元素进行删除,需要注意的是,是删除第一次出现的元素,不是所有            的。

       代码很简单,我们就利用 LinkedList 的 get(int index) 方法,遍历出所有的元素。

  但是需要注意的是, get(int index) 方法每次都要遍历该索引之前的所有元素,这句话这么理解:

  比如上面的一个 LinkedList 集合,我放入了 A,B,C,D是个元素。总共需要四次遍历:

  第一次遍历打印 A:只需遍历一次。

  第二次遍历打印 B:需要先找到 A,然后再找到 B 打印。

  第三次遍历打印 C:需要先找到 A,然后找到 B,最后找到 C 打印。

  第四次遍历打印 D:需要先找到 A,然后找到 B,然后找到 C,最后找到 D。

  这样如果集合元素很多,越查找到后面(当然此处的get方法进行了优化,查找前半部分从前面开始遍历,查找后半部分从后面开始遍历,但是需要的时间还是很多)花费的时间越多。那么如何改进呢?(使用迭代器是最好的

  1. java.util.HashMap 类 (https://www.cnblogs.com/ysocean/p/8711071.html

19. Collection 和 Collections 有什么区别?

  • java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
  • Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

20. List、Set、Map 之间的区别是什么?

21. HashMap 和 Hashtable 有什么区别?

  • hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
  • hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
  • hashMap允许空键值,而hashTable不允许。

22. 如何决定使用 HashMap 还是 TreeMap?

对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。

23. 说一下 HashMap 的实现原理?

HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 

HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。

需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

24. 说一下 HashSet 的实现原理?

  • HashSet底层由HashMap实现
  • HashSet的值存放于HashMap的key上
  • HashMap的value统一为PRESENT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值