面试题学习

   a left join b最多返回多少条记录,最少返回多少条记录?

      a left join b将返回a中所有的记录和b中符合on条件的记录。

      最少返回的记录数是a的记录数,这还是好理解的。

      最多返回的记录数a*b,如下:

      select * from a;

      id   name

      1    allen

      2    tim

      3    jackson

      select * from b;

      id    grade

      4    a

      5    b

      select a.id,a.name,b.grade from a left join b on a.id != b.id;返回的记录数是6条。

 

  PreparedStatement和Statement的区别

      应尽量使用PreparedStatement,可以防止SQL注入,例如:      

  mysql> select * from a where name = "abc" or 1=1--"";

  +------+--------  +

  | id  | name  |

  +------+--------  +

  |    1 | allen |

  |    2 | edison |

  |    3 | tim  |

  +------+--------+

  3 rows in set (0.00 sec)

   name字段输入的是:abc" or 1=1--",本应该查不到任何记录,结果却是查到了所有的记录。

     使用PreparedStatement做测试,查询到的结果是空,是不存在SQL注入的问题。PreparedStatement会先进行预编译,传递的参数会被当做字符串进行处理,这样就不会出现SQL拼接产生的问题。   

   String sql = "select * from a where name = ?";

   String paramter = "abc\" or 1=1--\"";

   Connection conn = null;

   PreparedStatement pstmt = null;

   ResultSet rs = null;

   try {

    conn = DBConnectionManager.getConnection();

    pstmt = conn.prepareStatement(sql);

    for (int i = 0; params != null && i < params.length; i++){

         pstmt.setString(i + 1, params[i]);

     }

        使用PreparedStatement还需要注意的一点是,在MySQL中,字段上如果有索引并且是varchar的,查询时不加引号,会导致为普通查询,索引会失效。反之,字段上如果有索引并且是int的,查询时加不加引号都是OK的。       

  mysql> explain select * from rcnetnode where index_in_mib = 10100001;

  +----+-------------+-----------+------+------------------+------+---------+------+------+-------------+

  | id | select_type | table     | type | possible_keys    | key  | key_len | ref  | rows | Extra       |

  +----+-------------+-----------+------+------------------+------+---------+------+------+-------------+

  |  1 | SIMPLE      | rcnetnode | ALL  | idx_index_in_mib | NULL | NULL    | NULL |  203 | Using where |

  +----+-------------+-----------+------+------------------+------+---------+------+------+-------------+

  1 row in set (0.00 sec)

 

  mysql> explain select * from rcnetnode where index_in_mib = "10100001";

  +----+-------------+-----------+------+------------------+------------------+---------+-------+------+-------------+

  | id | select_type | table     | type | possible_keys    | key              | key_len | ref   | rows | Extra       |

  +----+-------------+-----------+------+------------------+------------------+---------+-------+------+-------------+

  |  1 | SIMPLE      | rcnetnode | ref  | idx_index_in_mib | idx_index_in_mib | 203     | const |    2 | Using where |

  +----+-------------+-----------+------+------------------+------------------+---------+-------+------+-------------+

  1 row in set (0.00 sec)

      所以上面的代码中pstmt.setString(i + 1, params[i]);是没有问题的。

 

  HashMap实现的底层原理

      先从根源说起,对象的比较使用的是equals方法。比较字符串的内容用equals而不是==,是因为String类已经重写了equals,比较的是字符串的内容,而不是Object的比较内存地址。

      对象的比较重写equals方法的同时会重写hashcode方法,这是因为对象如果要放到hash类的集合(hashmap,hashset)中时,hashcode是对key进行散列的依据,决定了散列的效率。

     

       从上图我们可以发现HashMap是由数组+链表组成的,初始的容量是16,负载因子是0.75,即存储的元素超过12个时,容量自动扩充为32.元素存储的位置是key%16,比如31,31%16结果是15,(15,value)就在15的位置。

       

       HashMap对于上述的过程做了一些优化,不仅仅是key%16了。

       当调用put(key,value)时,首先获取key的hashcode,int hash = key.hashCode(); 
       再把hash通过一下运算得到一个int h. 
       hash ^= (hash >>> 20) ^ (hash >>> 12); 
       int h = hash ^ (hash >>> 7) ^ (hash >>> 4);

       再做index = h & (length-1),算出的index是(key,value)应在的位置,这样做会使index的分布尽量均匀。

       这点也是好理解的,如果hashcode写的不好,简单的key%16可能会使得个别链条很长,这样效率是较低的。

       HashSet的实现是用的HashMap的key。

 

    多线程模拟多个客户进行转账操作,有一个方法是转账,要求当转出金额大于账户余额时该线程放弃执行,将执行权力交给其他的线程。

        第一个反应是用yield,但是yield依赖于操作系统,不是最好的选择。

        正确的应是用notifyAll通知其他线程去继续执行,需要注意的是同步块锁得对象是this,下面是个例子程序。每个线程打印5个数字,将执 行权力交给其他的线程。

        使用notifyAll而不notify是因为notify更容易引起死锁而notifyAll则不会。      

public class NotifyTest {
 public static void main(String[] args) {
  TestThread t = new TestThread();
  Thread t1 = new Thread(t);
  Thread t2 = new Thread(t);
  Thread t3 = new Thread(t);
  
  t1.start();
  t2.start();
  t3.start();
 }
}

class TestThread implements Runnable{
 int sum = 100;
 @Override
 public synchronized void run() {
  int localNum = sum;
  for(int i= sum;;){   
   if(i<= localNum -5){
    this.notifyAll();
    break;
   }else{
    System.out.println(Thread.currentThread().getName() + ":"+ i);
    i--;
    sum = i;
   }
  }  
 } 
}

 

posted on 2014-08-26 16:26  lnlvinso  阅读(145)  评论(0编辑  收藏  举报