java练习题(三)
- 1.Statement和PreparedStatement有什么区别?哪个性能更好?
- 2.transient关键字的作用
- 3. mysql中使用delete和trucate删除表中数据的区别
- 4. 死锁的四个必要条件
- 5.解释脏读,不可重复读,幻读,mysql默认使用的隔离策略是什么?
- 6.concurrentHashMap是如何实现线程安全的?
- 7. 简述ThreadLocal的工作原理及流程?
- 8.举例说明内部类,局部内部类,匿名内部类?
- 9.给你一个字符串 s,由若干单词组成,单词之间用单个或多个连续的空格字符隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。(58)
- 10.给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
1.Statement和PreparedStatement有什么区别?哪个性能更好?
Statement和PreparedStatement的功能主要是对sql语句的执行。
区别:
①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少 SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);
②当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)
③PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;
性能: 当批量处理SQL或频繁执行相同的查询时,PreparedStatement不用再次编译和生成执行计划,有明显的性能上的优势
2.transient关键字的作用
一个对象只要实现了Serilizable接口,这个对象就会被自动序列化。
transient关键字的作用:被transient修饰的变量不参与序列化和反序列化
transient关键字小结:
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
3. mysql中使用delete和trucate删除表中数据的区别
区别:
1.delete可以删除部分数据(添加where子句)或者整张条的数据,而trucate只能删除整张表的数据。
2.当表被trucate后,这个表和索引所占用的空间会恢复到初始大小,而delete操作不会减少表或索引所占用的空间。
3.delete from删空表后,会保留一个空的页,而truncate在表中不会留有任何页。
4.truncate操作的执行速度大于delete操作
5.delete语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作,而trucate table则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。
6.当使用行锁执行delete语句时,将锁定表中各行以便删除,而truncate始终锁定表和页,而不是锁定各行。
7.如果有identity产生的自增id列,delete from后仍然从上次的数开始增加,即种子不变。而使用truncate删除之后,种子会恢复到初始值。
4. 死锁的四个必要条件
1.互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
2.不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
3.请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
4.循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。
以上这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
5.解释脏读,不可重复读,幻读,mysql默认使用的隔离策略是什么?
脏读隔离策略:Read committed(不可重复读)
不可重复读隔离策略:Repeatable read(可重复读)
幻读隔离策略:Serializable(串行化)
Mysql的默认隔离级别:Repeatable read(可重复读)
6.concurrentHashMap是如何实现线程安全的?
ConcurrentHashMap 在1.7中实现线程安全是通过锁住Segment对象的。而在1.8 中则是针对首个节点(table[hash(key)]取得的链接或红黑树的首个节点)进行加锁操作。
ConcurrentHashMap 1.7:
ConcurrentHashMap将数据分别放到多个Segment中,默认16个,每一个Segment中又包含了多个HashEntry列表数组,对于一个key,需要经过三次hash操作,才能最终定位这个元素的位置,这三次hash分别为:
- 对于一个key,先进行一次hash操作,得到hash值h1,也即h1 = hash1(key);
- 将得到的h1的高几位进行第二次hash,得到hash值h2,也即h2 = hash2(h1高几位),通过h2能够确定该元素的放在哪个Segment;
- 将得到的h1进行第三次hash,得到hash值h3,也即h3 = hash3(h1),通过h3能够确定该元素放置在哪个HashEntry。
每一个Segment都拥有一个锁,当进行写操作时,只需要锁定一个Segment,而其它Segment中的数据是可以访问的。
static final class Segment<K,V> extends ReentrantLock implements Serializable {
transient volatile HashEntry<K,V>[] table;
transient int count;
}
ConcurrentHashMap 1.8:
ConcurrentHashMap在jdk1.8中取消segments字段,直接采用transient volatile Node<K,V>[] table保存数据,采用table数组元素(链表的首个元素或者红黑色的根节点)作为锁,从而实现了对每一行数据进行加锁,减少并发冲突的概率。
transient volatile Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
......
}
7. 简述ThreadLocal的工作原理及流程?
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储之后,只能在指定线程中可以获取到存储的数据。对于其他线程来说无法获取到数据。
ThreadLoal:解决了线程上下文中的变量传递问题;用于线程共享数据,使得共享数据更加方便了
**工作原理:**在ThreadLocal类中定义了一个ThreadLocalMap,每一个Thread都有一个ThreadLocalMap类型的变量threadLocals,就是用threadLocals来存储每一个线程的变量副本,threadLocals内部有一个Entry数组,我们根据键值线程对象,来找到对应线程的变量副本。
流程:
- 开发者自定义的ThreadLocal实例调用set()方法
直接获取当前线程,然后直接获取当前线程的ThreadLocalMap实例。如果为空,则创建ThreadLocalMap实例并赋值给当前线程,并把值(T v)放入到map中的entry[]中;如果不为空,则直接set值即可。
2)开发者自定义ThreadLocal实例调用get()方法
直接获取当前线程,然后直接获取当前线程的ThreadLocalMap实例。如果为空,则设置初始值,这个设置初始值的逻辑是,先执行自己默认初始值设定,默认值是null,然后获取当前线程,然后获取当前线程的ThreadLocalMap实例,如果为空,则创建ThreadLocalMap实例并赋值给当前线程,并把值(T v)放入到map中的entry[]中;如果不为空,则直接获取值。
8.举例说明内部类,局部内部类,匿名内部类?
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
1.成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。形如下面的形式:
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
System.out.println(count); //外部类的静态成员
}
}
}
2.局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
3.匿名内部类
匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
history_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
4.静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
9.给你一个字符串 s,由若干单词组成,单词之间用单个或多个连续的空格字符隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。(58)
class Solution {
public int lengthOfLastWord(String s) {
int res = 0;//最后一个单词长度
for(int i=s.length()-1;i>=0;i--){//从最后一项开始遍历
if(s.charAt(i)==' '&&res!=0){
return res;
}else if(s.charAt(i)!=' '){//防止末尾出现空格的情况
res++;
}
}
return res;
}
}
10.给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
class Solution {
public int removeDuplicates(int[] nums) {
int index = 0;
for(int i = 1; i < nums.length; ++i){
if(nums[i] != nums[index]){
nums[++index] = nums[i];
}
}
return index + 1;
}
}