1,原生的char支不支持中文字符,为什么
答:char类型变量是用来Unicode编码的字符,Unicode编码字符集中包含了汉字,所以char型变量支持存储汉字,同时char类型占2个字节,unicode编码占用两个字节。
2.覆盖equals需要注意的事项
答:在object文档中我们可以发现,equals指示其他某个对象是否与此对象相等,equals方法在非空对象引用上实现相等关系。
(1) 自反性:对于任何非空引用值x,x.equals(x)都应该返回true.
(2)对称性:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应该返回true。
(3)传递性:对于任何非空引用值x.y.z,如果x.equals(y)返回true是,并且y.equals(z)返回ture,那么x.equals(z)应返回true。
(4)一致性:对于任何非空引用值x和y,多次调用x.equals(y)始终返回true或始终返回false,前提是对象上equals比较中所用的信息没有修改。
(5)对于任何非空引用值x,x.equals(null)都应返回false。
注意:当此方法被重写时,通常有必要重写hashcode方法,以维护hashcode方法的常规协定,该协定声明相等对象必须具备相等的哈希吗。
3.synchronized和lock的区别和所用,什么时候synchronized是对象锁
答:前提了解锁:我们从jvm的角度来看一看锁的概念,java程序在运行环境中,jvm需要对两类线程共享的数据进行协调,
(1) 保存在堆中的实例变量
(2)保存在方法区中的类变量
这两类数据是被所有线程共享的。接下来就是java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获取该锁,在退出代码块或方法时会释放该锁,获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
java的内置锁是一个互斥锁,这就意味着最多只有一个线程能够获得该锁,当线程A尝试去获取线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放锁。java的对象锁:用于对象实例方法,或者一个对象实例上。java的类锁:用于类的静态方法或者一个类的class对象。
synchronized(关键字)的使用及原理:
synchronize的三种应用方式:
(1)修饰实例方法,作用于当前实例加锁,进入同步代码前要获取当前实例的锁。
(2)修饰静态方法,作用于当前类对象加锁,进入同步代码前需要获得当前类对象的锁。多个线程分别访问实例对象的非static syschronized方法和static syschronized方法,是不会发生互斥情况,因为static syschronized方法占用的锁是当前类的class对象锁,而非static synchronize方法占用的锁是当前实例对象锁。
(3) 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码前需要获取给定对象的锁。
Lock使用及原理:
synchronized与lock的区别
(1)类型不同
synchronized是关键字,是jvm层面的实现,java的内置特性,lock是一个接口,是jdk层面的实现。
(2)获取锁和释放锁的方式不同
synchronized是jvm实现的,锁的获取和释放是不可见的,当发生异常时,锁的释放有jvm实现。
lock接口中提供的方法,可以让编程人员更加方便的实现锁的各种操作,比如尝试获取锁的,设置锁的超时时间,中断等待等,lock在编码中进行锁的操作,需要自动调用接口中的方法释放锁,所以使用lock是需要配合try模块,在finally中释放锁,不然一旦发生异常可能会在造成死锁现象。
(3) 锁的状态和锁的类型
synchronized无法判断锁的状态,lock接口可以获取锁,同时判断锁的状态。
synchronized属于可重入,不可中断,非公平锁类型,lock属于可重入,可判断,可公平锁类型。
(4)性能上
synchronized实现少量同步,在jdk1.5中,synchronize性能是抵效的,因为这是一个重量级操作,他对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些给操作系统带来很大的压力。但是到了jdk1.6,官方对synchronized加入很多优化措施,有自适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等,导致jdk1.6synchronized的性能并不比lock差,官方提倡使用synchronized来进行同步。
lock实现大量同步。
顺便浅析一下两种锁机制的底层实现策略:
互斥同步最主要的问题是线程挂起和唤醒所带来的性能问题,这种同步称为阻塞同步,属于悲观的并发策略,即线程获得的是独占锁,独占锁意味着其他线程只能依靠阻塞来等待线程释放锁,而在cpu转换线程阻塞是会引起线程上下文切换,当很多线程竞争锁的时候,会引起cpu频繁的上下文切换导致效率很低,synchronized采用的就是这种策略。
随着指令集的发展,我们有了另一种选择:基于冲突检测的乐观并发策略,通俗来讲即先进性操作,如果没有其他线程使用共享数据的话,那操作成功,如果共享数据被征用,产生了冲突,那就在进行其他的补偿操作(比如不断重拾),这种乐观的并发策略的许多伤心爱你都不需要把线程挂起,称为非阻塞同步,ReetrantLock采用的便是这种并发策略。
4.怎么遍历集合删除元素
答:使用迭代器Iterator遍历集合在删除。
ArrayList<String> a = new ArrayList<String>();
a.add("aaaa");
a.add("bbbb");
a.add("cccc");
// for(int i=0;i<a.size();i++) {
// if(a.get(i)=="aaaa" && a.get(i).equals("aaaa")) {
// System.out.println(a.get(i));
// a.remove(a.get(i));
// }
// }
// System.out.println(a);
Iterator<String> is = a.iterator();
while(is.hasNext()) {
if(is.next().equals("cccc")) {
is.remove();
}
}
System.out.println(a);
}
5.为什么string要设计成不可变的
答:首先我们看源码知道String底层是由char数组构成,而且还是private final 修饰,我们在创建一个字符串对象时,其实是将字符串保存在char数组中,因为数组是引用对象,为了防止数组可变,jdk添加了final修饰,加了final修饰的数组只是代表了引用不可变,不代表数组的内容不可变,因此又添加了private修饰符。
注:部分答案来自其他博客的引用,具体实在记不清了,望勿见怪