java基础(1)
1.int和interger的区别
Integer是int的包装类;int是基本数据类型;
Integer变量必须实例化后才能使用;int变量不需要;
Integer实际是对象的引用,指向此new的Integer对象;int是直接存储数据值 ;
Integer的默认值是null;int的默认值是0。
延伸:
关于Integer和int的比较
1、由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
1
2
3 Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false2、Integer变量和int变量比较时,只要两个变量的值是相等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
1
2
3 Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true3、非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为 ①当变量值在-128到127之间时,非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同;②当变量值不在-128到127之间时,非new生成Integer变量时,java API中最终会按照new Integer(i)进行处理(参考下面第4条),最终两个Interger的地址同样是不相同的)
1
2
3 Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
1
2
3
4
5
6 Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false对于第4条的原因:
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:
1
2
3
4
5
6
7 public static Integer valueOf(int i){
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high){
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了
2.什么时候用list什么时候用数组,linklist和arraylist的区别以及什么时候用link什么时候用array
当数据量固定时或者多维度时,我们可以使用数组,而当我们可以根据需要自动扩充,修改数据时,应该使用list
linklist和arraylist的区别
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
3.集合有哪些接口,他们有什么区别
Collection接口:单列集合,两个子接口
①List接口:有序可重复
LinkedList:基于链表实现,每个元素储存本身内存地址还储存下一个元素的地址。(增删快,查找慢)ArrayList:基于数组实现,每次增删都要重新创建新的数组,但数组有索引。(增删慢,查找快)
Vector:基于数组,线程安全相关,效率低。
②Set接口:不可重复
HashSet: 储存的元素无序,不可重复,底层是哈希表LinkedHashSet:储存元素有序,不可重复,底层是哈希表和链表的结合
TreeSet:可以指定一个顺序,对象存入之后会按照指定的顺序排序。
2 . Map接口:双列集合
HashMap:非线程安全,高效,支持nullLinkedHashMap:是HashMap的一个子类,保存了记录的插入顺序
HashTable:线程安全,低效,不支持null
TreeMap:能够把他保存的记录根据键排序,默认是键值的升序排序
4.重载和重写的区别
方法重载Overload:
1、同一个类中
2、方法名相同,参数列表不同(参数顺序、个数、类型)
3、方法返回值、访问修饰符任意
4、与方法的参数名无关
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 //重载
public void eat(){
System.out.println("我是干饭人" );
}
// public int eat(){ 会报错
// return 4;
// }
//报错原因:参数类型和个数一样,返回值类型不同是不算重载的
//因为在调用方法的时候,我们还不知道方法的返回值类型,所以编译器无法区分你调用的是哪个方法。
public void eat(String name){
System.out.println("我是干饭人:"+name );
}
public void eat(String name,int age){
System.out.println("我是干饭人:"+name+"我今年"+age );
}方法重写Override:
1、有继承关系的子类中
2、方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
3、访问修饰符,访问范围需要大于等于父类的访问范围
4、与方法的参数名无关
1
2
3
4
5
6
7
8
9
10
11
12
13
14 //重载
public class Father {
public void walk(){
System.out.println("我是父亲");
}
}
public class Son extends Father {
//方法重写
public void walk() {
System.out.println("我是儿子");
}
}
5.接口和抽象类的区别
A:成员的区别
抽象类:
构造方法:有构造方法,用于子类实例化使用。
成员变量:可以是变量,也可以是常量。
成员方法:可以是抽象的,也可以是非抽象的。接口:
构造方法:没有构造方法
成员变量:只能是常量。默认修饰符:public static final
成员方法:jdk1.7只能是抽象的。默认修饰符:public abstract (推荐:默认修饰符请自己永远手动给出)
jdk1.8可以写以default和static开头的具体方法B:类和接口的关系区别
类与类:
继承关系,只能单继承。可以多层继承。类与接口:
实现关系,可以单实现,也可以多实现。
类还可以在继承一个类的同时实现多个接口。接口与接口:
继承关系,可以单继承,也可以多继承。C:体现的理念不同
抽象类里面定义的都是一个继承体系中的共性内容。
接口是功能的集合,是一个体系额外的功能,是暴露出来的规则。
6.字符串转为json用什么接口
JSONObject jsonObject = JSON.parseObject(tt);
fastjson
7.hashmap和hashset的区别及原理
HashSet是通过HasMap来实现的,HashMap的输入参数有Key、Value两个组成,在实现HashSet的时候,保持HashMap的Value为常量,相当于在HashMap中只对Key对象进行处理。
HashMap的底层是一个数组结构,数组中的每一项对应了一个链表,这种结构称“链表散列”的数据结构,即数组和链表的结合体;也叫散列表、哈希表。HahMap存储对象的过程如下
①、对HahMap的Key调用hashCode()方法,返回int值,即对应的hashCode;②、把此hashCode作为哈希表的索引,查找哈希表的相应位置,若当前位置内容为NULL,则把hashMap的Key、Value包装成Entry数组,放入当前位置;
③、若当前位置内容不为空,则继续查找当前索引处存放的链表,利用equals方法,找到Key相同的Entry数组,则用当前Value去替换旧的Value;
④、若未找到与当前Key值相同的对象,则把当前位置的链表后移(Entry数组持有一个指向下一个元素的引用),把新的Entry数组放到链表表头;
HashSet存储对象的过程
往HashSet添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。
情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。
情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次
,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行添加。
注意:现在Hashmap不是数组加链表实现,而是数组,链表,红黑树,链表节点数大于8时会从链表结构变成树结构。
1
2
3 >ConcurrentHashMap线程安全,锁部分
Hashtable线程安全,锁全部
上者效率更高
8.io有哪些类型
Java IO方式大体上可以分为三类,基于不同的io模型可以简单分为同步阻塞的BIO,同步非阻塞的NIO和异步非阻塞的AIO.
BIO:Block IO 同步阻塞式 IO,就是咱们日常使用的传统 IO,它的特色是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端经过 Channel(通道)通信,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操做基于事件和回调机制。
9.说说对耦合的理解
耦合就是模块与模块之间的联系程度
1
2
3 高内聚,低耦合有什么好处呢?
事实上,你会发现,短期来看,并没有很明显的好处,甚至会有一些人抱怨,“我这样写不行吗?有舍么问题?” “我写了十几年代码都是这样写的也没见有什么问题。”等等;还有个最重要的,这样甚至在短期内会影响系统的开发进度,因为高内聚,低耦合的系统对开发设计人员提出了更高的要求。高内聚,低耦合的好处体现在系统持续发展的过程中,高内聚,低耦合的系统具有更好的重用性,维护性,扩展性,可以更高效的完成系统的维护开发,持续的支持业务的发展,而不会成为业务发展的障碍。
1
2
3
4
5
6
7
8
9 高内聚,低耦合是否意味着内聚越高越好,耦合越低越好?
(内聚性,又称块内联系,指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。)
(1)并不是内聚越高越好,耦合越低越好,真正好的设计是在高内聚和低耦合间进行平衡,也就是说高内聚和低耦合是冲突的。
(2)最强的内聚莫过于一个类只写一个函数,这样内聚性绝对是最高的。但这会带来一个明显的问题:类的数量急剧增多,这样就导致了其它类的耦合特别多,于是整个设计就变成了“高内聚高耦合”了。由于高耦合,整个系统变动同样非常频繁。
(3)对于耦合来说,最弱的耦合是一个类将所有的函数都包含了,这样类完全不依赖其它类,耦合性是最低的。但这样会带来一个明显的问题:内聚性很低,于是整个设计就变成了“低耦合低内聚”了。由于低内聚,整个类的变动同样非常频繁。
(4)真正做到高内聚、低耦合是很难的,很多时候未必一定要这样,更多的时候“最适合”的才是最好的,不过、审时度势、融会贯通、人尽其才、物尽其用,才是设计的王道。
10.8大基本数据类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 byte
byte属于Java中的整型,长度为1字节8bit,取值10000000(-128)到 01111111(127),变量初始化默认值为0,包装类Byte
short
short属于Java中的整型,长度为2字节16bit,取值10000000 00000000(-32768)到 01111111 11111111(32767),变量初始化默认值为0,包装类Short
int
int属于Java中的整型,长度为4字节32bit,取值-2^31 (-2,147,483,648)到 2^31-1(2,147,483,647),变量初始化默认值为0,包装类Integer
long
long属于Java中的整型,长度为8字节64bit,取值-2^63 (-9,223,372,036,854,775,808)到 2^63-1(9,223,372,036,854,775,8087),变量初始化默认值为0或0L,包装类Long
float
float属于Java中的浮点型,也叫单精度浮点型,长度为4字节32bit,变量初始化默认值0.0f,包装类Float
double
double属于Java中的浮点型,也叫双精度浮点型,长度为8字节64bit,变量初始化默认值0.0d,包装类Double
char
char属于java中的字符型,占2字节16bit,可以赋值单字符以及整型数值, 变量初始化无默认值,包装类Character。
boolean
在JVM中并没有提供boolean专用的字节码指令,而boolean类型数据在经过编译后在JVM中会通过int类型来表示,此时boolean数据4字节32位,而boolean数组将会被编码成Java虚拟机的byte数组,此时每个boolean数据1字节占8bit.
--Java虚拟机规范
仅有两个值true, false,变量初始化默认值false
11.==和equal的区别
equal与==
1.最大的区别是,==是运算符,equal是方法
简述几种情况下的equal与==
java基本类型
比较包装类型
比较String类型
比较对象
1.java基本类型(short,int,long,byte,char,float,double,boolean)比较基本类型,只能用==,不能用equal,这里的==比较的是两个变量的值
2.比较包装类型
==比较的是内存地址,因为a和b是new出来的,是两个不同的对象,所以地址肯定是不同的,而equal比较的是值.
1
2
3
4
5
6 public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}3.比较String类型
==比较的是内存地址,equal比较的是值
4.比较对象
==和equal比较的都是内存地址,因为equal没有被重写,没有被重写的equal都是object的equal方法
12.String 与 StringBuffer 和 StringBuilder 的区别
- String 是不可变的,而 StringBuffer 和 StringBuilder 是可变类。
- StringBuffer 是线程安全和同步的,而 StringBuilder 不是。这就是 StringBuilder 比 StringBuffer 快的原因。
- 字符串连接运算符 (+) 在内部使用 StringBuilder 类。
- 对于非多线程环境中的字符串操作,我们应该使用 StringBuilder 否则使用 StringBuffer 类。
13.CopyOnWriteArrayList的底层原理
CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。
优点:
读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。Java的list在遍历时,若中途有别的线程对list容器进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其”读写分离”的思想,遍历和修改操作分别作用在不同的list容器,所以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了
缺点:
缺点也很明显,一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 public boolean add(E e) {
//ReentrantLock加锁,保证线程安全
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//拷贝原容器,长度为原容器长度加一
Object[] newElements = Arrays.copyOf(elements, len + 1);
//在新副本上执行添加操作
newElements[len] = e;
//将原容器引用指向新副本
setArray(newElements);
return true;
} finally {
//解锁
lock.unlock();
}
}
14.深拷贝和浅拷贝的区别
对于基本数据类型,两者都是值传递
对于引用数据类型,浅拷贝是地址拷贝,而深拷贝是创建一个新的对象,将值复制进去