1.简述java跨平台的原理
Java通过不同的系统、不同的版本、不同位数的java虚拟机(jvm),来屏蔽不同的系统指令集差异而对外提供统一的接口(javaAPI)
对于我们java开发者而言,只需要按照接口开发即可,如果系统需要部署到不同环境,只需在系统上面安装对应版本的虚拟机即可。
2.int类型占几个字节?java中有几种基本的数据类型?
略
3.面向对象的特征有哪些方面?
有四大基本特征:封装、抽象、继承、多态
- 面向对象的封装性,即将对象封装成一个高度自治和封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。(举个例子,张三的名字和性别等属性 需要由自己提供的方法来获取和改变)
- 抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。(就是把现实中的对象抽象为一个类)
- 在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并且可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要。这就是继承。
- 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能确定。
- 原则:回答比较抽象的问题的时候要举例说明
4.有了基本数据类型,为什么还需要包装类型?
延伸:装箱和拆箱
装箱:将基本数据类型转化为对应的包装类型
Integer i = 1 //自动装箱 实际上在编译时会自动调用Integer.valueOf()方法
Integer i = Integer.valueOf(1);//手动装箱
拆箱:将包装类型 转化为基本数据类型
Integer i = 1;
int j = i;//自动拆箱 实际上编译时会调用intValue
int j = Integer.intValue(i); 手动拆箱
5.说一下==和equals的区别
==:
用来判断两个变量之间的值是否相等。变量可以分为基本数据类型变量和引用类型变量。
- 如果是基本数据类型的变量则直接比较它们的值是否相等
- 如果是引用类型的变量则需要比较它们对应的内存的首地址是否相等
-
包装类Long 和Integer要考虑缓存问题 包装类的值在[-128,127]时要考虑缓存
-
例子:Integer i = 1;
Integer j = 1;
System.out.println(i == j);
返回true
(图中包装类i 和 j 是相等的 由于缓存的原因指向同一块内存区域)
所以如果值在-128到127之间( [-128,127] ),你使用valueof()将获得相同的引用,超过这个范围将返回new Integer(int)。因为是相同的引用,在-128到127范围内你的==操作是有用的。
Java缓存了-128到127范围内的Integer和Long类。所以当你给这个范围的封装类赋值时,装箱操作会调用Integer.valueOf() 函数,反过来就会给封装类赋上一个缓存池实例的引用。
另一方面来说,如果用超出这个范围的值给封装类赋值时,Integer.valueOf()会创建一个新的Integer类。因此,比对超出这个范围的Integer类时,会返回false。
equals:
下面先来研究一下Object中的equals方法的源码:
public boolean equals(Object obj) {
return (this == obj);
}
可以看到Object中的equals方法时用来判断两个对象的地址是否相同
下面再来看一个String中重写的equals方法:
/** The value is used for character storage. value数组是用来存储字符串的 */
private final char value[];
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
* 将这个字符串和指定的对象进行比较。当且仅当参数不是null并且是String类型的对象 并且二者字符序
* 列相同时才会返回true
*/
public boolean equals(Object anObject) {
if (this == anObject) { //判断二者是否为同一个对象(内存地址是否相同)
return true;
}
if (anObject instanceof String) {//参数必须是String的对象
String anotherString = (String)anObject;//创建一个新对象 并且将参数的引用赋给该对象
int n = value.length;//n表示调用equals方法 的字符串的长度
if (n == anotherString.value.length) {//如果两个对象的长度相等才进行比较
char v1[] = value;//将第一个字符串的值赋给数组
char v2[] = anotherString.value;//将第二个字符串的值赋给数组
int i = 0;
while (n-- != 0) {//对两个数组v1和v2进行遍历 并且比较它们每一个索引值 完全相同返回true 如果有一个索引值不同则返回false
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
总结:
- 对于equals方法,注意:equals方法不能作用于基本数据类型的变量
- 如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
- 诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
6.讲一下String和StringBuilder的区别?StringBuffer和StringBuilder的区别?
在java中提供三个类String,StringBuilder,StringBuffer来表示和操作字符串。字符串就是多个字符的集合。
[1]String是内容不可变的字符串。String底层使用了一个不可变的字符数组(final char[] value)
/** The value is used for character storage. */
private final char value[];
String str = new String("abc")
[2]而StringBuilder和StringBuffer是内容可以改变的字符串。二者底层使用的是可变的字符数组(没有使用final)
/**
* The value is used for character storage.
*/
char[] value;
最经典的就是拼接字符串。
1.String进行拼接 String c = "a" + "b";
2.StringBuilder或者StringBuffer
StringBuilder sb = new StringBuilder(); sb.append("a").append("b")
[3]拼接字符串不能使用String进行拼接,要使用StringBuilder或者StringBuffer
StringBuilder是线程不安全的,效率较高,而StringBuffer是线程安全的,效率低
7.讲一下java中的集合
java中的集合分为 存储值的(value)和存key-value的(Map)两种
存储值的有List和Set
- List是有序 可以重复的
- set是无序 不可重复的。根据equals和hashcode判断,也就是说 如果一个对象要存储在Set中必须重写equals和hashCode两个方法
存储key-value的为map
8.ArrayList和LinkedList的区别?
List常用的ArrayList和LinkedList 区别和使用场景?
ArrayList底层使用的是数组,LinkedList使用的是链表
- 数组查询特定的元素比较快,而插入、删除和修改比较慢(数组在内存中是一块连续的内存,如果插入或者删除需要移动内存)
- 链表不要求内存是连续的,在当前元素中存放下一个或者上一个元素的地址。查询时需要从头部开始,一个一个的找。所以查询的效率低。插入时不需要移动内存,只需要改变引用指向即可,所以插入或者删除的效率高。
- 综上所述 ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList使用在查询比较少而插入和删除比较多的情况。
9.HashMap和HashTable的区别?HashTable和ConcurrentHashMap的区别?
相同点:
- HashMap和HashTable都可以用来存储key-value的数据
- HashMap和Hashtable都实现了Map接口
不同点:
- HashMap可以把null作为key或者value但是HashTable不可以
- HashMap是线程不安全的,效率高。而HashTable是线程安全的,效率低。
- HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。(原因:因为迭代器的remove方法不仅修改了modCount,还同步更新了expectedModCount,而集合的remove方法只修改了modCount,不会同步expectedModCount,所以后者在调用iterator.next()时会快速失败,而前者不会。(前提是在迭代器遍历集合过程中新增、修改或删除了元素)详见博客:https://blog.csdn.net/weixin_33656548/article/details/85064325)
- Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
如何做到线程安全且效率高?
通过使用ConcurrentHashMap来实现。ConcurrentHashMap通过把整个Map分为n个Segment(类似于HashTable)可以提供相同的线程安全,但是效率提升了n倍,默认提升16倍。