1:

:jdk和jre的区别
:JDK:java development kit (java开发工具)
JRE:java runtime environment (java运行时环境)
JDK包含JRE


2:

:Java跨平台的原理
:Java语言跨平台的原理,是由一份字节码可以在不同的系统上执行,由不同系统中的Java虚拟机负责翻译成对应的Java指令


3:

:说明自动类型转换和强制类型转换这两种类型转换的区别
:1.自动类型转换也叫隐式类型转换,不需要开发人员干预,程序自动进行操作;强制类型转换也叫显式类型转换,需要开发人员在赋值时使用(结果类型)方式来进行转换;
2.自动类型转换是精度低/范围小的/子类向精度高的/范围大的/父类转换,强制类型转换则相反,比如:int->byte是范围大向范围小转换需要强制,long->float是精度低向精度高转换不需要强制。


4:

:构造器(constructor)是否可被重写(override)?
:构造器不能被继承,因此不能被重写,但是构造器只能被重载。注意成员方法也是可以重载的,重载允许改变返回值。


5:

:关键字static的用法
:static用于修饰成员变量时,该成员变量为所有类共享,一旦对其的内容进行了改变,那么所有类的该静态属性都会发生变动。在内存中,将static修饰的变量放在了方法区中。
static变量修饰成员函数时,可以在不建立对象的情况下实现函数的调用。对于Person类中的静态方法say(),不需要先创建Person p,再用p.say()调用say方法,而是可以直接用Person.say调用该方法。


6:

:Java中equals和==的区别
:= = 用于比较两个对象的地址是否相等,equals是一般用于比较两个对象的内容是否相同,一般需要重写。而顶级父类Object的equals方法是比较两个对象的地址。


7:

:描述java的三大特性

封装
封装指的是属性私有化,根据需要提供setter和getter方法来访问属性。即隐藏具体属性和实现细节,仅对外开放接口,控制程序中属性的访问级别。封装目的:增强安全性和简化编程,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员。
继承
继承是指将多个相同的属性和方法提取出来,新建一个父类。
Java中一个类只能继承一个父类,且只能继承访问权限非private的属性和方法。 子类可以重写父类中的方法,命名与父类中同名的属性。
继承目的:代码复用。
多态
多态可以分为两种:设计时多态和运行时多态。
设计时多态:即重载,是指Java允许方法名相同而参数不同(返回值可以相同也可以不相同)。
运行时多态:即重写,是指Java运行根据调用该方法的类型决定调用哪个方法。
多态目的:增加代码的灵活度。
温馨提示:
一.Java中应尽量减少继承关系,以降低耦合度。
二.使用多态时,父类在在调用方法时,优先调用子类的方法。如果子类没有重写父类的方法,则再调用父类的方法。


8:

:为什么Java语言的开发者,把String类定义为final的呢?

因为只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现,因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。


9:

:简述HashMap底层实现原理

encodeURI 对应java java encode和decode的区别_字符串


JDK1.7: 默认采用头插法
存元素
第一步:根据键获取到当前键值的hash值,获取到hash值之后%上数组的长度(hashmap底层数组长度默认为16)之后选定要存储的具体位置
第二步:得到具体的位置之后,把要存储的这个Entry放到计算出来的位置,如果当前位置什么也没有,直接放进去,如果这个位置已经有元素的话
遍历此位置上的所有元素,判断当前要存储的这个Entry对象与之前已经存储的元素的键值是否相等,如果相等,直接覆盖掉原始的value,
如果没有与之键值相等的元素,则直接将Entry对象插入到数组中。
取元素
第一步:获取键值的hash值后%16,判断元素是在当前数组的那一个节点上
第二步:遍历当前的链表,采用equals方法,根据键值和Entry当中的键值进行对比,对比成功的话,把对应的value值取出来,如果对比不成功的话为null

JDK1.8:默认采用尾插法(默认负载因子为0.75默认保证时间效率和空间效率都是最佳的)
不用头插法的原因:头插法在多线程中可能会造成链表回环
存元素
第一步: 根据键获取到当前键值的hash值,获取到hash值之后%上数组的长度(hashmap底层数组长度默认为16)之后选定要存储的具体位置
当此节点上的链表长度超过阈值8的时候,不再采用链表的方式进行存储,从第9个开始采用红黑二叉树的形式进行存储
为什么JDK1.8不采用头插法?因为他默认把插入到数组位置的第一个元素当成了二叉树的根节点
负载因子0.75是链表和数组的比例,如果超过0.75的时候会进行一个rehash的操作(hashmap的扩容被称为rehash,当rehash的时候回大大降低hash表的效率)
因此在使用hashmap的时候,应当尽量的规避rehash:在使用hashmap的时候手动的改变数组的长度