geek的技术日志,记录每一次技术思考的闪光点。

程序员找工作黑名单厂商,换工作和当技术合伙人需谨慎

later阅读(529)评论(0)

厂商黑名单

我也只是围观群众,背后的真相大家自己判断. 以下内容是从git上copy过来的,方便不会用git的同学查看。

写在前面

谢谢 issues 提醒

首先,每一个程序猿,每一个公司都有黑点,但是如果把黑点放大了,黑名单就没存在的意义了。就拿这几个例子来吧

  1. 世纪佳缘认为白帽子,是违法的
    • 虽然这件事是我怒开 repo 的起因,但是他没有拖欠员工工资或不付工资
  2. 阿里的月饼事件,只是价值观上和我本人不符
    • 但并没有拖欠员工工资或不付工资
    • 阿里还是技术氛围很不错的公司,我也有很多好朋友在阿里
  3. 与创始人说的股份,那是个人争取的事
    • 也没拖欠工资或不付工资
    • 只是记住以后记得留个心眼,和合伙人不是只写代码就可以的
  4. 华为清理 34 岁以上员工,也是按照合同裁员,给赔偿
    • 大公司更新换代,裁员没有任何问题,不裁员的公司早晚倒闭
    • 华为也没有拖欠工资
    • 只是我个人觉得,因为这件事,不想去华为工作 仅此而已,害怕到了34就被干掉

普通程序员

技术合伙人

不确定的

待补充

选公司

  • 建议大家在选择公司的时候摸摸底子 http://tianyancha.com ,发现有问题直接问负责人省的吃哑巴亏。

当技术合伙人建议

  • 选自冯大辉的微博 只写代码和当合伙人,还是有很大差别的,我觉得上面的建议很中肯

最后

  • 最后说一下心得,竟然还有希望 GitHub 处理这个 repo,原因是想维护github这份纯净,还把 GitHub 被墙和我挂钩,我真是醉了,就像一群待宰的羔羊,心想着只要老实一点,宰的就是别人不是我一样

  • 我只是记录一下自己看到过的事件,我自己下次换工作的时候防止才坑,仅此而已

  • 我也没有那么愤世嫉俗,比如我以后换工作,还是会考虑百度阿里的,但是会避免上面出现的坑,比如百度无人车我就不去啦,阿里的其他很多部门还是很棒的,希望到时候不会因为这个名单把我 pass 吧:joy:

大家可到git上 star 和提交厂商名单和原因

https://github.com/shengxinjing/programmer-job-blacklist

PHP常见面试题及答案

later阅读(374)评论(0)

基础题:
1.表单中 get与post提交方法的区别?
答:get是发送请求HTTP协议通过url参数传递进行接收,而post是实体数据,可以通过表单提交大量信息.

2.session与cookie的区别?
答:session:储存用户访问的全局唯一变量,存储在服务器上的PHP指定的目录中的(session_dir)的位置进行的存放
   cookie:用来存储连续訪問一个頁面时所使用,是存储在客户端,对于Cookie来说是存储在用户WIN的Temp目录中的。 
   两者都可通过时间来设置时间长短

3.数据库中的事务是什么?
答:事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,

事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。

简述题:
1、用PHP打印出前一天的时间格式是2006-5-10 22:21:21(2分)
答:echo date(‘Y-m-d H:i:s’, strtotime(‘-1 days’)); 

2、echo(),print(),print_r()的区别(3分)
答:echo是PHP语句, print和print_r是函数,语句没有返回值,函数可以有返回值(即便没有用)  
   print()    只能打印出简单类型变量的值(如int,string)  
   print_r() 可以打印出复杂类型变量的值(如数组,对象)  
   echo     输出一个或者多个字符串

3、能够使HTML和PHP分离开使用的模板(1分)
答:Smarty,Dwoo,TinyButStrong,Template Lite,Savant,phemplate,XTemplate

5、使用哪些工具进行版本控制?(1分)
答:cvs,svn,vss;

6、如何实现字符串翻转?(3分)
答:echo strrev($a);

7、优化MySQL数据库的方法。(4分,多写多得)
答:
1、选取最适用的字段属性,尽可能减少定义字段长度,尽量把字段设置NOT NULL,例如’省份,性别’,最好设置为ENUM
2、使用连接(JOIN)来代替子查询:
   a.删除没有任何订单客户:DELETE FROM customerinfo WHERE customerid NOT in(SELECT customerid FROM orderinfo)
   b.提取所有没有订单客户:SELECT FROM customerinfo WHERE customerid NOT in(SELECT customerid FROM orderinfo)
   c.提高b的速度优化:SELECT FROM customerinfo LEFT JOIN orderid customerinfo.customerid=orderinfo.customerid
   WHERE orderinfo.customerid IS NULL
3、使用联合(UNION)来代替手动创建的临时表
   a.创建临时表:SELECT name FROM `nametest` UNION SELECT username FROM `nametest2`
4、事务处理:
   a.保证数据完整性,例如添加和修改同时,两者成立则都执行,一者失败都失败
   mysql_query(“BEGIN”);
   mysql_query(“INSERT INTO customerinfo (name) VALUES (‘$name1’)”;
   mysql_query(“SELECT * FROM `orderinfo` where customerid=”.$id”);
   mysql_query(“COMMIT”);
5、锁定表,优化事务处理:
   a.我们用一个 SELECT 语句取出初始数据,通过一些计算,用 UPDATE 语句将新值更新到表中。
     包含有 WRITE 关键字的 LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前,
     不会有其它的访问来对 inventory 进行插入、更新或者删除的操作
   mysql_query(“LOCK TABLE customerinfo READ, orderinfo WRITE”);
   mysql_query(“SELECT customerid FROM `customerinfo` where id=”.$id);
   mysql_query(“UPDATE `orderinfo` SET ordertitle=’$title’ where customerid=”.$id);
   mysql_query(“UNLOCK TABLES”);
6、使用外键,优化锁定表
   a.把customerinfo里的customerid映射到orderinfo里的customerid,
     任何一条没有合法的customerid的记录不会写到orderinfo里
   CREATE TABLE customerinfo
   (
     customerid INT NOT NULL,
     PRIMARY KEY(customerid)  
   )TYPE = INNODB;
   CREATE TABLE orderinfo
   (
     orderid INT NOT NULL,
     customerid INT NOT NULL,
     PRIMARY KEY(customerid,orderid),
     FOREIGN KEY (customerid) REFERENCES customerinfo
     (customerid) ON DELETE CASCADE   
   )TYPE = INNODB;
   注意:’ON DELETE CASCADE’,该参数保证当customerinfo表中的一条记录删除的话同时也会删除order
         表中的该用户的所有记录,注意使用外键要定义事务安全类型为INNODB;
7、建立索引:
   a.格式:
   (普通索引)->
   创建:CREATE INDEX <索引名> ON tablename (索引字段)
   修改:ALTER TABLE tablename ADD INDEX [索引名] (索引字段)
   创表指定索引:CREATE TABLE tablename([…],INDEX[索引名](索引字段)) 
   (唯一索引)->
   创建:CREATE UNIQUE <索引名> ON tablename (索引字段)
   修改:ALTER TABLE tablename ADD UNIQUE [索引名] (索引字段)
   创表指定索引:CREATE TABLE tablename([…],UNIQUE[索引名](索引字段)) 
   (主键)->
   它是唯一索引,一般在创建表是建立,格式为:
   CREATA TABLE tablename ([…],PRIMARY KEY[索引字段])
8、优化查询语句
   a.最好在相同字段进行比较操作,在建立好的索引字段上尽量减少函数操作
   例子1:
   SELECT * FROM order WHERE YEAR(orderDate)<2008;(慢)
   SELECT * FROM order WHERE orderDate<“2008-01-01”;(快)
   例子2:
   SELECT * FROM order WHERE addtime/7<24;(慢)
   SELECT * FROM order WHERE addtime<24*7;(快)
   例子3:
   SELECT * FROM order WHERE title like “%good%”;
   SELECT * FROM order WHERE title>=”good” and name<“good”;

8、PHP的意思(送1分)
答:PHP是一个基于服务端来创建动态网站的脚本语言,您可以用PHP和HTML生成网站主页

9、MYSQL取得当前时间的函数是?,格式化日期的函数是(2分)
答:now(),date()

10、实现中文字串截取无乱码的方法。(3分)
答:function GBsubstr($string, $start, $length) {
    if(strlen($string)>$length){
     $str=null;
     $len=$start+$length;
     for($i=$start;$i<$len;$i++){
    if(ord(substr($string,$i,1))>0xa0){
     $str.=substr($string,$i,2);
     $i++;
    }else{
     $str.=substr($string,$i,1);
     }
    }
   return $str.’…’;
    }else{
   return $string;
   }
}

11、您是否用过版本控制软件? 如果有您用的版本控制软件的名字是?(1分)
12、您是否用过模板引擎? 如果有您用的模板引擎的名字是?(1分)
答:用过,smarty

13、请简单阐述您最得意的开发之作(4分)
答:信息分类

14、对于大流量的网站,您采用什么样的方法来解决访问量问题?(4分)
答:确认服务器硬件是否足够支持当前的流量,数据库读写分离,优化数据表,
   程序功能规则,禁止外部的盗链,控制大文件的下载,使用不同主机分流主要流量

15、用PHP写出显示客户端IP与服务器IP的代码1分)
答:打印客户端IP:echo $_SERVER[‘REMOTE_ADDR’]; 或者: getenv(‘REMOTE_ADDR’);
   打印服务器IP:echo gethostbyname(“www.bolaiwu.com“)

16、语句include和require的区别是什么?为避免多次包含同一文件,可用(?)语句代替它们? (2分)
答:require->require是无条件包含也就是如果一个流程里加入require,无论条件成立与否都会先执行require 
  include->include有返回值,而require没有(可能因为如此require的速度比include快) 
  注意:包含文件不存在或者语法错误的时候require是致命的,include不是

17、如何修改SESSION的生存时间(1分).
答:方法1:将php.ini中的session.gc_maxlifetime设置为9999重启apache
   方法2:$savePath = “./session_save_dir/”;
         $lifeTime = 小时 * 秒;
         session_save_path($savePath);
         session_set_cookie_params($lifeTime);
         session_start();
   方法3:setcookie() and session_set_cookie_params($lifeTime);
 
18、有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?($1分)
答:方法1(对于PHP5及更高版本):
   $readcontents = fopen(“http://www.phpres.com/index.html“, “rb”);
   $contents = stream_get_contents($readcontents);
   fclose($readcontents);
   echo $contents;
   方法2:
   echo file_get_contents(“http://www.phpres.com/index.html“); 

19、在HTTP 1.0中,状态码401的含义是(?);如果返回“找不到文件”的提示,则可用 header 函数,其语句为(?);(2分)
答:状态401代表未被授权,header(“Location:www.xxx.php”);

12、在PHP中,heredoc是一种特殊的字符串,它的结束标志必须?(1分)
答:heredoc的语法是用”<<<“加上自己定义成对的标签,在标签范围內的文字视为一个字符串
   例子:
   $str = <<<SHOW
   my name is Jiang Qihui!
   SHOW;

13、谈谈asp,php,jsp的优缺点(1分)
答:ASP全名Active Server Pages,是一个WEB服务器端的开发环境, 利用它可以产生和运
行动态的、交互的、高性能的WEB服务应用程序。ASP采用脚本语言VB Script(Java script
)作为自己的开发语言。 
  PHP是一种跨平台的服务器端的嵌入式脚本语言. 它大量地借用C,Java和Perl语言的语法
, 并耦合PHP自己的特性,使WEB开发者能够快速地写出动态生成页面.它支持目前绝大多数数
据库。还有一点,PHP是完全免费的,不用花钱,你可以从PHP官方站点(http://www.php.ne
t)自由下载。而且你可以不受限制地获得源码,甚至可以从中加进你自己需要的特色。 
  JSP 是Sun公司推出的新一代站点开发语言,他完全解决了目前ASP,PHP的一个通病--
脚本级执行(据说PHP4 也已经在Zend 的支持下,实现编译运行).Sun 公司借助自己在Jav
a 上的不凡造诣,将Java 从Java 应用程序 和 Java Applet 之外,又有新的硕果,就是Js
p--Java Server Page。Jsp 可以在Serverlet和JavaBean的支持下,完成功能强大的站点
程序。 
  三者都提供在 HTML 代码中混合某种程序代码、由语言引擎解释执行程序代码的能力。
但JSP代码被编译成 Servlet 并由 Java 虚拟机解释执行,这种编译操作仅在对 JSP 页面的
第一次请求时发生。在 ASP 、PHP、JSP 环境下, HTML 代码主要负责描述信息的显示样式
,而程序代码则用来描述处理逻辑。普通的 HTML 页面只依赖于 Web 服务器,而 ASP 、PH
P、JSP 页面需要附加的语言引擎分析和执行程序代码。程序代码的执行结果被重新嵌入到 
HTML 代码中,然后一起发送给浏览器。 ASP 、PHP、 JSP三者都是面向 Web 服务器的技术
,客户端浏览器不需要任何附加的软件支持。

14、谈谈对mvc的认识(1分)
答:由模型(model),视图(view),控制器(controller)完成的应用程序
   由模型发出要实现的功能到控制器,控制器接收组织功能传递给视图;

15、写出发贴数最多的十个人名字的SQL,利用下表:members(id,username,posts,pass,email)(2分)
答:SELECT * FROM `members` ORDER BY posts DESC limit 0,10;

16. 请说明php中传值与传引用的区别。什么时候传值什么时候传引用?(2分)
答:按值传递:函数范围内对值的任何改变在函数外部都会被忽略
   按引用传递:函数范围内对值的任何改变在函数外部也能反映出这些修改
   优缺点:按值传递时,php必须复制值。特别是对于大型的字符串和对象来说,这将会是一个代价很大的操作。
   按引用传递则不需要复制值,对于性能提高很有好处。

17. 在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报

18. 请写一个函数验证电子邮件的格式是否正确 (2分)
答:function checkEmail($email)
  {
    $pregEmail = “/([a-z0-9]*[-_/.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[/.][a-z]{2,3}([/.][a-z]{2})?/i”;
    return preg_match($pregEmail,$email);  
  }

19. 简述如何得到当前执行脚本路径,包括所得到参数。(2分)
答:$script_name = basename(__file__); print_r($script_name);

21、JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
   获得输入焦点 focus()

22、JS的转向函数是?怎么引入一个外部JS文件?(2分)
答:window.location.href,<script type=”text/JavaScript” src=”js/js_function.js”></script>

23、foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出

24、如何声明一个名为”myclass”的没有方法和属性的类? (1分)
答:class myclass{ }

25、如何实例化一个名为”myclass”的对象?(1分)
答:new myclass()

26、你如何访问和设置一个类的属性? (2分)
答:$object = new myclass();
   $newstr = $object->test;
   $object->test = “info”;

27、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
   mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得

28、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。 
   在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。

29、指出一些在PHP输入一段HTML代码的办法。(1分)
答:echo “<a href=’index.php’>aaa</a>”;

30、下面哪个函数可以打开一个文件,以对文件进行读和写操作?(1分)
    (a) fget() (b) file_open() (c) fopen() (d) open_file()  [  c  ]

31、下面哪个选项没有将 john 添加到users 数组中? (1分)
  (a) $users[] = ‘john’;
  (b) array_add($users,’john’);
  (c) array_push($users,‘john’);
  (d) $users ||= ‘john’;  [  a , c  ]

32、下面的程序会输入是否?(1分)
  $num = 10;
  function multiply(){
  $num = $num * 10;
  }
  multiply();
  echo $num;
  ?>
    输出:10

33、使用php写一段简单查询,查出所有姓名为“张三”的内容并打印出来 (2分)
  表名User
  Name Tel Content Date
  张三 13333663366 大专毕业 2006-10-11
  张三 13612312331 本科毕业 2006-10-15
  张四 021-55665566 中专毕业 2006-10-15
  请根据上面的题目完成代码:
  $mysql_db=mysql_connect(“local”,”root”,”pass”);
  @mysql_select_db(“DB”,$mysql_db);
    $result = mysql_query(“SELECT * FROM `user` WHERE name=’张三'”);
    while($rs = mysql_fetch_array($result)){
      echo $rs[“tel”].$rs[“content”].$rs[“date”];
    }    

34、如何使用下面的类,并解释下面什么意思?(3)
  class test{
     function Get_test($num){
      $num=md5(md5($num).”En”);
      return $num;
   }
  }
答:$testnum = “123”;
   $object = new test();
   $encrypt = $object->Get_test($testnum);
   echo $encrypt;
   类test里面包含Get_test方法,实例化类调用方法多字符串加密

35、写出 SQL语句的格式 : 插入 ,更新 ,删除 (4分)
  表名User
  Name Tel Content Date
  张三 13333663366 大专毕业 2006-10-11
  张三 13612312331 本科毕业 2006-10-15
  张四 021-55665566 中专毕业 2006-10-15
  (a) 有一新记录(小王 13254748547 高中毕业 2007-05-06)请用SQL语句新增至表中
    mysql_query(“INSERT INTO `user` (name,tel,content,date) VALUES 
    (‘小王’,’13254748547′,’高中毕业’,’2007-05-06′)”)

  (b) 请用sql语句把张三的时间更新成为当前系统时间
    $nowDate = date(“Ymd”);
    mysql_query(“UPDATE `user` SET date='”.$nowDate.”‘ WHERE name=’张山'”);

  (c) 请写出删除名为张四的全部记录
    mysql_query(“DELETE FROM `user` WHERE name=’张四'”);

36、请写出数据类型(int char varchar datetime text)的意思; 请问varchar和char有什么区别(2分)
答:int是数字类型,char固定长度字符串,varchar实际长度字符串,datetime日期时间型,text文本字符串
   char的场地固定为创建表设置的长度,varchar为可变长度的字符

38、写出以下程序的输出结果 (1分)
  $b=201;
  $c=40;
    $a=$b>$c?4:5;
  echo $a;
  ?>
答:4

39、检测一个变量是否有设置的函数是否?是否为空的函数是?(2分)
答:isset($str),empty($str);

40、取得查询结果集总数的函数是?(1分)
答:mysql_num_rows($result);

41、$arr = array(‘james’, ‘tom’, ‘symfony’); 请打印出第一个元素的值 (1分)
答:echo $array[0];

42、请将41题的数组的值用’,’号分隔并合并成字串输出(1分)
答:for($i=0;$i<count($array);$i++){ echo $array[$i].”,”;}

43、$a = ‘abcdef’; 请取出$a的值并打印出第一个字母(1分)
答:echo $a{0} 或 echo substr($a,0,1)

44、PHP可以和sql server/Oracle等数据库连接吗?(1分)
答:当然可以

45、请写出PHP5权限控制修饰符(3分)
答:public(公共),private(私用),protected(继承)

46、请写出php5的构造函数和析构函数(2分)
答:__construct , __destruct

47、完成以下:
   (一)创建新闻发布系统,表名为message有如下字段 (3分)
  id 文章id
  title 文章标题
  content 文章内容
  category_id 文章分类id
    hits 点击量
答:CREATE TABLE ‘message'(
   ‘id’ int(10) NOT NULL auto_increment,
   ‘title’ varchar(200) default NULL,
   ‘content’ text,
   ‘category_id’ int(10) NOT NULL,
   ‘hits’ int(20),
   PRIMARY KEY(‘id’);
   )ENGINE=InnoDB DEFAULT CHARSET=utf8;

    (二)同样上述新闻发布系统:表comment记录用户回复内容,字段如下 (4分)
  comment_id 回复id
  id 文章id,关联message表中的id
  comment_content 回复内容
  现通过查询数据库需要得到以下格式的文章标题列表,并按照回复数量排序,回复最高的排在最前面
  文章id 文章标题 点击量 回复数量
  用一个SQL语句完成上述查询,如果文章没有回复则回复数量显示为0
答:SELECT message.id id,message.title title,IF(message.`hits` IS NULL,0,message.`hits`) hits,
   IF(comment.`id` is NULL,0,count(*)) number FROM message LEFT JOIN 
   comment ON message.id=comment.id GROUP BY message.`id`;

  (三)上述内容管理系统,表category保存分类信息,字段如下 (3分)
  category_id int(4) not null auto_increment;
  categroy_name varchar(40) not null;
  用户输入文章时,通过选择下拉菜单选定文章分类
  写出如何实现这个下拉菜单
答:function categoryList()
{
    $result=mysql_query(“select category_id,categroy_name from category”)
            or die(“Invalid query: ” . mysql_error());
    print(“<select name=’category’ value=”>/n”);
    while($rowArray=mysql_fetch_array($result))
    {
       print(“<option value='”.$rowArray[‘category_id’].”‘>”.$rowArray[‘categroy_name’].”</option>/n”);
    }
    print(“</select>”);
}

编程题:
1. 写一个函数,尽可能高效的,从一个标准 url 里取出文件的扩展名
   例如: http://www.sina.com.cn/abc/de/fg.php?id=1 需要取出 php 或 .php
答案1:
   function getExt($url){
   $arr = parse_url($url);
   
   $file = basename($arr[‘path’]);
   $ext = explode(“.”,$file);
   return $ext[1];
}
答案2:
    function getExt($url) {
    $url = basename($url);
    $pos1 = strpos($url,”.”);
    $pos2 = strpos($url,”?”);
    if(strstr($url,”?”)){
         return substr($url,$pos1 + 1,$pos2 – $pos1 – 1);
    } else {
      return substr($url,$pos1);
    }
}

2. 在 HTML 语言中,页面头部的 meta 标记可以用来输出文件的编码格式,以下是一个标准的 meta 语句
  请使用 PHP 语言写一个函数,把一个标准 HTML 页面中的类似 meta 标记中的 charset 部分值改为 big5
  请注意:
  1. 需要处理完整的 html 页面,即不光此 meta 语句
  2. 忽略大小写
    3. ‘ 和 ” 在此处是可以互换的
    4. ‘Content-Type’ 两侧的引号是可以忽略的,但 ‘text/html; charset=gbk’ 两侧的不行
  5. 注意处理多余空格

3. 写一个函数,算出两个文件的相对路径
  如 $a = ‘/a/b/c/d/e.php’;
  $b = ‘/a/b/12/34/c.php’;
  计算出 $b 相对于 $a 的相对路径应该是 ../../c/d将()添上
答:function getRelativePath($a, $b) {   
    $returnPath = array(dirname($b));   
    $arrA = explode(‘/’, $a);   
    $arrB = explode(‘/’, $returnPath[0]);   
    for ($n = 1, $len = count($arrB); $n < $len; $n++) {   
        if ($arrA[$n] != $arrB[$n]) {   
            break;   
        }    
    }   
    if ($len – $n > 0) {   
        $returnPath = array_merge($returnPath, array_fill(1, $len – $n, ‘..’));   
    }   
       
    $returnPath = array_merge($returnPath, array_slice($arrA, $n));   
    return implode(‘/’, $returnPath);   
   }   
   echo getRelativePath($a, $b);  

填空题:
1.在PHP中,当前脚本的名称(不包括路径和查询字符串)记录在预定义变量__$_SERVER[‘PHP_SELF’]__中;而链接到当前页面的URL记录在预定义变量__$_SERVER[‘HTTP_REFERER’]__

2.执行程序段<?php echo 8%(-2) ?>将输出__0__。

3.在HTTP 1.0中,状态码 401 的含义是____;如果返回“找不到文件”的提示,则可用 header 函数,其语句为____。

4.数组函数 arsort 的作用是__对数组进行逆向排序并保持索引关系__;语句 error_reporting(2047)的作用是__报告所有错误和警告__。

5.PEAR中的数据库连接字符串格式是____。

6.写出一个正则表达式,过虑网页上的所有JS/VBS脚本(即把scrīpt标记及其内容都去掉):preg_replace(” /<script[^>].*?>.*?</script>/si”, “newinfo”, $script);

7.以Apache模块的方式安装PHP,在文件http.conf中首先要用语句____动态装载PHP模块,然后再用语句____使得Apache把所有扩展名为php的文件都作为PHP脚本处理。
  LoadModule php5_module “c:/php/php5apache2.dll” , AddType application/x-httpd-php .php,

8.语句 include 和 require 都能把另外一个文件包含到当前文件中,它们的区别是____;为了避免多次包含同一文件,可以用语句__require_once||include_once__来代替它们。

9.类的属性可以序列化后保存到 session 中,从而以后可以恢复整个类,这要用到的函数是____。

10.一个函数的参数不能是对变量的引用,除非在php.ini中把__allow_call_time_pass_reference boolean__设为on.

11.SQL中LEFT JOIN的含义是__自然左外链接__。如果 tbl_user记录了学生的姓名(name)和学号(ID),tbl_score记录了学生(有的学生考试以后被开除了,没有其记录)的学号(ID)

和考试成绩(score)以及考试科目(subject),要想打印出各个学生姓名及对应的的各科总成绩,则可以用SQL语句____。

12.在PHP中,heredoc是一种特殊的字符串,它的结束标志必须____。

编程题:
13.写一个函数,能够遍历一个文件夹下的所有文件和子文件夹。
答:
function my_scandir($dir)
{
     $files = array();
     if ( $handle = opendir($dir) ) {
         while ( ($file = readdir($handle)) !== false ) {
             if ( $file != “..” && $file != “.” ) {
                 if ( is_dir($dir . “/” . $file) ) {
                     $files[$file] = scandir($dir . “/” . $file);
                 }else {
                     $files[] = $file;
                 }
             }
         }
         closedir($handle);
         return $files;
     }
}

14.简述论坛中无限分类的实现原理。
答:
<?php
/*
数据表结构如下:
CREATE TABLE `category` (
 `categoryID` smallint(5) unsigned NOT NULL auto_increment,
 `categoryParentID` smallint(5) unsigned NOT NULL default ‘0’,
 `categoryName` varchar(50) NOT NULL default ”,
 PRIMARY KEY (`categoryID`)
) ENGINE=MyISAM DEFAULT CHARSET=gbk;

INSERT INTO `category` ( `categoryParentID`, `categoryName`) VALUES 
(0, ‘一级类别’),
(1, ‘二级类别’),
(1, ‘二级类别’),
(1, ‘二级类别’),
(2, ‘三级类别’),
(2, ‘333332’),
(2, ‘234234’),
(3, ‘aqqqqqd’),
(4, ‘哈哈’),
(5, ‘66333666’);

*/

//指定分类id变量$category_id,然后返回该分类的所有子类
//$default_category为默认的选中的分类
function Get_Category($category_id = 0,$level = 0, $default_category = 0)
{
 global $DB;
 $sql = “SELECT * FROM category ORDER BY categoryID DESC”;
 $result = $DB->query( $sql );
 while ($rows = $DB->fetch_array($result)) 
 {
 $category_array[$rows[categoryParentID]][$rows[categoryID]] = array(‘id’ => $rows[categoryID], ‘parent’ => $rows[categoryParentID], ‘name’ => $rows

[categoryName]);
 }
 if (!isset($category_array[$category_id]))
 {
 return “”;
 }
 foreach($category_array[$category_id] AS $key => $category)
 { 
 if ($category[‘id’] == $default_category)
 {
 echo “<option selected value=”.$category[‘id’].””;
 }else
 {
 echo “<option value=”.$category[‘id’].””;
 }

 if ($level > 0)
 {
 echo “>” . str_repeat( ” “, $level ) . ” ” . $category[‘name’] . “</option>/n”;
 }
 else
 {
 echo “>” . $category[‘name’] . “</option>/n”;
 }
 Get_Category($key, $level + 1, $default_category);
 }
 unset($category_array[$category_id]);
}

/*
函数返回的数组格式如下所示:
Array 
(
 [1] => Array ( [id] => 1 [name] => 一级类别 [level] => 0 [ParentID] => 0 )
 [4] => Array ( [id] => 4 [name] => 二级类别 [level] => 1 [ParentID] => 1 )
 [9] => Array ( [id] => 9 [name] => 哈哈 [level] => 2 [ParentID] => 4 )
 [3] => Array ( [id] => 3 [name] => 二级类别 [level] => 1 [ParentID] => 1 ) 
 [8] => Array ( [id] => 8 [name] => aqqqqqd [level] => 2 [ParentID] => 3 )
 [2] => Array ( [id] => 2 [name] => 二级类别 [level] => 1 [ParentID] => 1 )
 [7] => Array ( [id] => 7 [name] => 234234 [level] => 2 [ParentID] => 2 )
 [6] => Array ( [id] => 6 [name] => 333332 [level] => 2 [ParentID] => 2 ) 
 [5] => Array ( [id] => 5 [name] => 三级类别 [level] => 2 [ParentID] => 2 ) 
 [10] => Array ( [id] => 10 [name] => 66333666 [level] => 3 [ParentID] => 5 ) 
)
*/
//指定分类id,然后返回数组
function Category_array($category_id = 0,$level=0)
{
 global $DB;
 $sql = “SELECT * FROM category ORDER BY categoryID DESC”;
 $result = $DB->query($sql);
 while ($rows = $DB->fetch_array($result))
 {
 $category_array[$rows[‘categoryParentID’]][$rows[‘categoryID’]] = $rows;
 }

 foreach ($category_array AS $key=>$val)
 {
 if ($key == $category_id)
 {
 foreach ($val AS $k=> $v)
 {
 $options[$k] =
 array(
 ‘id’ => $v[‘categoryID’], ‘name’ => $v[‘categoryName’], ‘level’ => $level, ‘ParentID’=>$v[‘categoryParentID’]
 );

 $children = Category_array($k, $level+1);

 if (count($children) > 0)
 {
 $options = $options + $children;
 }
 }
 }
 }
 unset($category_array[$category_id]);
 return $options;
}

?>

 

<?php

class cate
{

        function Get_Category($category_id = 0,$level = 0, $default_category = 0)
        {
             echo $category_id;
             $arr = array(
              ‘0’ => array(
                             ‘1’ => array(‘id’ => 1, ‘parent’ => 0, ‘name’ => ‘1111’),
                             ‘2’ => array(‘id’ => 2, ‘parent’ => 0, ‘name’ => ‘2222’),
                            ‘4’ => array(‘id’ => 4, ‘parent’ => 0, ‘name’ => ‘4444’)    
                          ),
              ‘1’ => array(
                              ‘3’ => array(‘id’ => 3, ‘parent’ => 1, ‘name’ => ‘333333’),
                            ‘5’ => array(‘id’ => 5, ‘parent’ => 1, ‘name’ => ‘555555’)     
                            ),
                          
              ‘3’ => array(
                            ‘6’ => array(‘id’ => 6, ‘parent’ => 3, ‘name’ => ‘66666’),
                            ‘7’ => array(‘id’ => 7, ‘parent’ => 3, ‘name’ => ‘77777’)
                            ),
              ‘4’ => array(
                            ‘8’ => array(‘id’ => 8, ‘parent’ => 4, ‘name’ => ‘8888’),
                            ‘9’ => array(‘id’ => 9, ‘parent’ => 4, ‘name’ => ‘9999’)
                            )    
             );

             if (!isset($arr[$category_id]))
             {
                return “”;
             }
    
             foreach($arr[$category_id] AS $key => $cate)
             {
                 if ($cate[‘id’] == $default_category)
                 {
                     $txt = “<option selected value=”.$cate[‘id’].””;
                 }else{
                     $txt = “<option value=”.$cate[‘id’].””;
                 }
            
                 if ($level > 0)
                 {
                    $txt1 = “>” . str_repeat( “-“, $level ) . ” ” . $cate[‘name’] . “</option>/n”;
                 }else{
                     $txt1 = “>” . $cate[‘name’] . “</option>/n”;
                 }
                 $val = $txt.$txt1;
                 echo $val;
                 self::Get_Category($key, $level + 1, $default_category);
             }
            
        }
        
        
        function getFlush($category_id = 0,$level = 0, $default_category = 0)
        {
            
            ob_start();

            self::Get_Category($category_id ,$level, $default_category);

            $out = ob_get_contents();

            ob_end_clean();
            return $out;
        }    
}
$id =$_GET[‘id’];
echo “<select>”;
$c = new cate();
//$c->Get_Category();
$ttt=  $c->getFlush($id,’0′,’3′);
echo $ttt;
echo “</select>”;
?>

2017最新PHP经典面试题总结

later阅读(879)评论(0)

1、双引号和单引号的区别

  • 双引号解释变量,单引号不解释变量
  • 双引号里插入单引号,其中单引号里如果有变量的话,变量解释
  • 双引号的变量名后面必须要有一个非数字、字母、下划线的特殊字符,或者用{}讲变量括起来,否则会将变量名后面的部分当做一个整体,引起语法错误
  • 双引号解释转义字符,单引号不解释转义字符,但是解释’\和\\
  • 能使单引号字符尽量使用单引号,单引号的效率比双引号要高(因为双引号要先遍历一遍,判断里面有没有变量,然后再进行操作,而单引号则不需要判断)

2、常用的超全局变量(8个)

  • $_GET —–>get传送方式
  • $POST —–>post传送方式
  • $REQUEST —–>可以接收到get和post两种方式的值
    ***
  • $GLOBALS —–>所有的变量都放在里面
  • $FILE —–>上传文件使用
  • $SERVER —–>系统环境变量
    * **

  • $SESSION —–>会话控制的时候会用到
  • $COOKIE —–>会话控制的时候会用到

3、HTTP中POST、GET、PUT、DELETE方式的区别

HTTP定义了与服务器交互的不同的方法,最基本的是POST、GET、PUT、DELETE,与其比不可少的URL的全称是资源描述符,我们可以这样理解:url描述了一个网络上资源,而post、get、put、delegate就是对这个资源进行增、删、改、查的操作!

3.1表单中get和post提交方式的区别
  • get是把参数数据队列加到提交表单的action属性所指的url中,值和表单内各个字段一一对应,从url中可以看到;post是通过HTTPPOST机制,将表单内各个字段与其内容防止在HTML的head中一起传送到action属性所指的url地址,用户看不到这个过程
  • 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据
  • get传送的数据量较小,post传送的数据量较大,一般被默认不受限制,但在理论上,IIS4中最大量为80kb,IIS5中为1000k,get安全性非常低,post安全性较高
3.2
  • GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。

  • 与GET不同的是,PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。

  • POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。

  • DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。

4、PHP介绍

Hypertext Preprocessor—-超文本预处理器

Personal Home Page 原始名称

目标用途: 允许web开发人员快速编写动态生成的web页面,与其他页面相比,PHP是将程序嵌入到HTML文档中去执行,效率比完全生成HTML编辑的CGI高很多

HTML: Hypertext Markup Language

创始人: 拉姆斯勒·勒多夫Rasmus Lerdorf,1968年生,加拿大滑铁卢大学

勒多夫最开始是为了维护个人网页,用prel语言写了维护程序,之后又用c进行了重写,最终衍生出php/fi

时间轴:

  • 1995.06.08将PHP/FI公开释出
  • 1995 php2.0,加入了对MySQL的支持
  • 1997 php3.0
  • 2000 php4.0
  • 2008 php5.0
  • 由于php6.0没有完全解决Unicode编码,所以基本没有生产线上的应用,基本只是一款概念产品,很多功能已经在php5.3.3和php5.3.4上实现

常见的IDE(Intergrated Development Environment): 集成开发环境

常见文本编辑器,具备代码高亮:

PHP优势

PHP特性:

  • php独特混合了C,Java,Prel以及PHP自创的语法
  • 可以比CGI或者Prel更快速去执行动态网页,与其他变成语言相比,PHP是讲程序嵌入到HTML文档中去执行,执行效率比完全生成HTML编辑的CGI要高很多,所有的CGI都能实现
  • 支持几乎所有流行的数据库以及操作系统
  • PHP可以使用C,C++进行程序的扩展

PHP优势:

  • 开放源代码
  • 免费性
  • 快捷性
  • 跨平台强
  • 效率高
  • 图形处理
  • 面向对象
  • 专业专注

PHP技术应用:

  • 静态页面生成
  • 数据库缓存
  • 过程缓存
  • div+css w3c标准
  • 大负荷
  • 分布式
  • flex
  • 支持MVC
  • Smarty模块引擎

PHP认证级别

  • 初级 IFE:Index Front Engineer 前端工程师
  • 中级 IPE:Index PHP Engineer PHP工程师
  • 高级 IAE:Index Architecture Engineer 架构工程师

6、echo、print_r、print、var_dump之间的区别

* echoprint是php语句,var_dump和print_r是函数
* echo 输出一个或多个字符串,中间以逗号隔开,没有返回值是语言结构而不是真正的函数,因此不能作为表达式的一部分使用
* print也是php的一个关键字,有返回值 只能打印出简单类型变量的值(如int,string),如果字符串显示成功则返回true,否则返回false
* print_r 可以打印出复杂类型变量的值(如数组、对象)以列表的形式显示,并以array、object开头,但print_r输出布尔值和NULL的结果没有意义,因为都是打印"\n",因此var_dump()函数更适合调试
* var_dump() 判断一个变量的类型和长度,并输出变量的数值

7、HTTP状态码

点击这儿查看HTTP状态码详解

常见的HTTP状态码:

  • 200 – 请求成功
  • 301 – 资源(网页等)被永久转义到其他URL
  • 404 – 请求的资源(网页等)不存在
  • 505 – 内部服务器错误

HTTP状态码分类:

  • 1** – 信息,服务器收到的请求,需要请求者继续执行操作
  • 2** – 成功,操作被成功接收并处理
  • 3** – 重定向,需要进一步的操作以完成请求
  • 4** – 客户端错误,请求包含语法错误或者无法完成请求
  • 5** 服务器错误,服务器在处理请求的过程
    中发生了错误

8、什么是魔术引号

魔术引号是一个将自动将进入PHP脚本的数据进行转义的过程,最好在编码时不要转义而在运行时根据需要而转义

9、如何获取客户端的ip(要求取得一个int)和服务器ip的代码

客户端:$_SERVER["REMOTE_ADDR"];或者getenv('REMOTE_ADDR')
ip2long进行转换
服务器端:gethostbyname('www.baidu.com')

10、使用那些工具进行版本控制

cvs、svn、vss、git

11、优化数据库的方法

MySQL数据库优化的八大方式(经典必看)点击获取
  • 选取最适用的字段属性,尽可能减少定义字段宽度,尽量把字段设置NOTNULL,例如’省份’、’性别’最好适用ENUM
  • 使用连接(JOIN)来代替子查询
  • 适用联合(UNION)来代替手动创建的临时表
  • 事务处理
  • 锁定表、优化事务处理
  • 适用外键,优化锁定表
  • 建立索引
  • 优化查询语句

12、是否使用过模板引擎?使用的模板引擎的名字是?

Smarty:Smarty算是一种很老的PHP模板引擎了,它曾是我使用这门语言模板的最初选择。虽然它的更新已经不算频繁了,并且缺少新一代模板引擎所具有的部分特性,但是它仍然值得一看。

13、对于大流量网站,采用什么方法来解决访问量的问题

  • 确认服务器硬件是否能够支持当前的流量
  • 数据库读写分离,优化数据表
  • 程序功能规则,禁止外部的盗链
  • 控制大文件的下载
  • 使用不同主机分流主要流量

14、语句include和require的区别是什么?为避免多次包含同一文件,可以用(?)语句代替他们

  • require是无条件包含,也就是如果一个流程里加入require,无论条件成立与否都会先执行require,当文件不存在或者无法打开的时候,会提示错误,并且会终止程序执行

  • include有返回值,而require没有(可能因为如此require的速度比include快),如果被包含的文件不存在的化,那么会提示一个错误,但是程序会继续执行下去

注意:包含文件不存在或者语法错误的时候require是致命的,而include不是

  • require_once表示了只包含一次,避免了重复包含

15、谈谈mvc的认识

由模型、视图、控制器完成的应用程序,由模型发出要实现的功能到控制器,控制器接收组织功能传递给视图

16、 说明php中传值与传引用的区别,并说明传值什么时候传引用?

变量默认总是传值赋值,那也就是说,当将一个表达式的值赋予一个变量时,整个表达式的值被赋值到目标变量,这意味着:当一个变量的赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量

php也提供了另外一种方式给变量赋值:引用赋值。这意味着新的变量简单的__引用__(换言之,成为了其别名或者指向)了原始变量。改动的新的变量将影响到原始变量,反之亦然。使用引用赋值,简单地将一个&符号加到将要赋值的变量前(源变量)

对象默认是传引用
对于较大是的数据,传引用比较好,这样可以节省内存的开销

17、isset、empty、is_null的区别

isset 判断变量是否定义或者是否为空

  变量存在返回ture,否则返回false
  变量定义不赋值返回false
  unset一个变量,返回false
  变量赋值为null,返回false
  

empty:判断变量的值是否为空,能转换为false的都是空,为空返回true,反之返回false。

    "",0,"0",NULLFALSE都认为为空,返回true
    没有任何属性的对象都认为是空
    

is_null:检测传入的值(值、变量、表达式)是否为null

    定义了,但是赋值为Null
    定义了,但是没有赋值
    unset一个变量

18、前端调试的工具

  • Firefox的firebug
  • Chrome的开发工具
  • Emmet
  • JSON格式校验工具

19. 简单描述mysql中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响(从读写两方面)(新浪网技术部)

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。
主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。
索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。
索引可以极大的提高数据的查询速度,但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件。

20.数据库中的事务是什么?

事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。ACID 四大特性,原子性、隔离性、一致性、持久性。

21.了解XSS攻击吗?如何防止?

XSS是跨站脚本攻击,首先是利用跨站脚本漏洞以一个特权模式去执行攻击者构造的脚本,然后利用不安全的Activex控件执行恶意的行为。
使用htmlspecialchars()函数对提交的内容进行过滤,使字符串里面的特殊符号实体化。

22.SQL注入漏洞产生的原因?如何防止?

SQL注入产生的原因:程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量POST和GET提交一些sql语句正常执行。

防止SQL注入的方式:
  1. 开启配置文件中的magic_quotes_gpc 和 magic_quotes_runtime设置
  2. 执行sql语句时使用addslashes进行sql语句转换
  3. Sql语句书写尽量不要省略双引号和单引号。
  4. 过滤掉sql语句中的一些关键词:update、insert、delete、select、 * 。
  5. 提高数据库表和字段的命名技巧,对一些重要的字段根据程序的特点命名,取不易被猜到的。
  6. Php配置文件中设置register_globals为off,关闭全局变量注册
  7. 控制错误信息,不要在浏览器上输出错误信息,将错误信息写到日志文件中。

23.PHP网站的主要攻击方式有哪些?

  1. 命令注入(Command Injection)
  2. eval 注入(Eval Injection)
  3. 客户端脚本攻击(Script Insertion)
  4. 跨网站脚本攻击(Cross Site Scripting, XSS)
  5. SQL 注入攻击(SQL injection)
  6. 跨网站请求伪造攻击(Cross Site Request
    Forgeries, CSRF)
  7. Session 会话劫持(Session Hijacking)
  8. Session 固定攻击(Session Fixation)
  9. HTTP 响应拆分攻击(HTTP Response Splitting)
  10. 文件上传漏洞(File Upload Attack)
  11. 目录穿越漏洞(Directory Traversal)
  12. 远程文件包含攻击(Remote Inclusion)
  13. 动态函数注入攻击(Dynamic Variable
    Evaluation)
  14. URL 攻击(URL attack)
  15. 表单提交欺骗攻击(Spoofed Form
    Submissions)
  16. HTTP 请求欺骗攻击(Spoofed HTTP Requests)

24、框架中什么是单一入口和多入口 , 单一入口的优缺点?

  1. 多口就是通过访问不同的文件来完成用户请求。单一入口只 web 程序所有的请求都指向一个脚本文件的。
  2. 单一入口更容易控制权限,方便对 http 请求可以进行安全性检查。
    缺点:URL 看起来不那么美观,特别是对搜索引擎来说不友好。

25、 对于关系型数据库而言,索引是相当重要的概念,请回答有关索引的几个问题:

a)、索引的目的是什么?
  1. 快速访问数据表中的特定信息,提高检索速度
  2. 创建唯一性索引,保证数据库表中每一行数据的唯一性。
  3. 加速表和表之间的连接
  4. 使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
b)、索引对数据库系统的负面影响是什么?

负面影响:
创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度。

c)、为数据表建立索引的原则有哪些?
  1. 在最频繁使用的、用以缩小查询范围的字段上建立索引。
  2. 在频繁使用的、需要排序的字段上建立索引
d)、 什么情况下不宜建立索引?
  1. 对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引。
  2. 对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等。

26、 简述在MySQL数据库中MyISAM和InnoDB的区别

区别于其他数据库的最重要的特点就是其插件式的表存储引擎。切记:存储引擎是基于表的,而不是数据库。

InnoDB与MyISAM的区别:

InnoDB存储引擎: 主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用,是第一个完整支持ACID事务的存储引擎(BDB第一个支持事务的存储引擎,已经停止开发)。

特点:

  • 行锁设计、支持外键;
  • 支持类似于Oracle风格的一致性非锁定读(即:默认情况下读取操作不会产生锁);
  • InnoDB将数据放在一个逻辑的表空间中,由InnoDB自身进行管理。从MySQL4.1版本开始,可以将每个InnoDB存储引擎的表单独存放到一个独立的ibd文件中;
  • InnoDB通过使用MVCC(多版本并发控制:读不会阻塞写,写也不会阻塞读)来获得高并发性,并且实现了SQL标准的4种隔离级别(默认为REPEATABLE级别);
  • InnoDB还提供了插入缓冲(insert buffer)、二次写(double write)、自适应哈希索引(adaptive hash index)、预读(read ahead)等高性能和高可用的功能;
  • InnoDB采用了聚集(clustered)的方式来存储表中的数据,每张标的存储都按主键的顺序存放(如果没有显式的在建表时指定主键,InnoDB会为每一行生成一个6字节的ROWID,并以此作为主键);
  • InnoDB表会有三个隐藏字段:除了上面提到了6字节的DB_ROW_ID外,还有6字节的DB_TX_ID(事务ID)和7字节的DB_ROLL_PTR(指向对应回滚段的地址)。这个可以通过innodb monitor看到;

MyISAM存储引擎: 是MySQL官方提供的存储引擎,主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。
特点:

  • 不支持事务,支持表所和全文索引。操作速度快;
  • MyISAM存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。MySQL数据库只缓存其索引文件,数据文件的缓存交给操作系统本身来完成;
    MySQL5.0版本开始,MyISAM默认支持256T的单表数据;

27、 解释MySQL外连接、内连接与自连接的区别

先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。

内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。
外连接 其结果集中不仅包含符合连接条件的行,而且还会包括左表、右表或两个表中
的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。

左外连接,也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以NULL来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL目前还不支持全外连接。

28、 写出三种以上MySQL数据库存储引擎的名称(提示:不区分大小写)

MyISAM、InnoDB、BDB(BerkeleyDB)、Merge、Memory(Heap)、Example、Federated、
Archive、CSV、Blackhole、MaxDB 等等十几个引擎

29、 什么是面向对象?主要特征是什么?几大原则是什么?

面向对象是程序的一种设计模式,它利于提高程序的重用性,使程序机构更加清晰。 主要特征是:封装、继承、多态。
五大基本原则: 单一职责原则;开放封闭原则;替换原则; 依赖原则; 接口分离原则。

30、什么是静态路由,其特点是什么?什么是动态路由,其特点是什么?

 参考答案:
  静态路由是由系统管理员设计与构建的路由表规定的路由。适用于网关数量有限的场 合,且网络拓朴结构不经常变化的网络。其缺点是不能动态地适用网络状况的变化,当 网络状况变化后必须由网络管理员修改路由表。
动态路由是由路由选择协议而动态构建的,路由协议之间通过交换各自所拥有的路由信 息实时更新路由表的内容。动态路由可以自动学习网络的拓朴结构,并更新路由表。其 缺点是路由广播更新信息将占据大量的网络带宽。

31、使用过 Memcache 缓存吗,如果使用过,能够简单的描述一下它的工作原理吗?

Memcahce 是把所有的数据保存在内存当中,采用 hash 表的方式,每条数据由 key 和 value 组成,每个 key 是独一无二的,当要访问某个值的时候先按照找到值,然后返回结果。
Memcahce 采用 LRU 算法来逐渐把过期数据清除掉。

32. 列举流行的 Ajax 框架?说明 Ajax 实现原理是什么及 json 在 Ajax 中起什么作用?

流行的 Ajax 框架有 jQuery,Prototype,Dojo,MooTools。

Ajax 的工作原理是一个页面的指定位置可以加载另一个页面所有的输出内容,这样就实现了一个静态页面也能获取到数据库中的返回数据信息了。所以 Ajax 技术实现了一个静态网页在不刷新整个页面的情况下与服务器通信,减少了用户等待时间,同时也从而降低了网络流量,增强了客户体验的友好程度。
在使用 Ajax 时,涉及到数据传输,即将数据从服务器返回到客户端,服务器端和客户端分别使用不同的脚步语言来处理数据,这就需要一种通用的数据格式,XML 和 json 就是最常用的两种,而 json 比 XML 更简单。

33、Myql中的事务回滚机制概述

事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位,事务回滚是指将该事务已经完成的对数据库的更新操作撤销。

  要同时修改数据库中两个不同表时,如果它们不是一个事务的话,当第一个表修改完,可能第二个表修改过程中出现了异常而没能修改,此时就只有第二个表依旧是未修改之前的状态,而第一个表已经被修改完毕。而当你把它们设定为一个事务的时候,当第一个表修改完,第二表修改出现异常而没能修改,第一个表和第二个表都要回到未修改的状态,这就是所谓的事务回滚。

最近3年常见的Java面试问题总结

later阅读(471)评论(0)

Java 面试随着时间的改变而改变。在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来越高级,面试官问的问题也更深入。 在我初入职场的时候,类似于 Vector 与 Array 的区别、HashMap 与 Hashtable 的区别是最流行的问题,只需要记住它们,就能在面试中获得更好的机会,但这种情形已经不复存在。如今,你将会被问到许多 Java 程序员都没有看过的领域,如 NIO,设计模式,成熟的单元测试,或者那些很难掌握的知识,如并发、算法、数据结构及编码。

由于我喜欢研究面试题,因此我已经收集了许多的面试问题,包括许多许多不同的主题。我已经为这众多的问题准备一段时间了,现在我将它们分享给你们。这里面不但包含经典的面试问题,如线程、集合、equals 和 hashcode、socket,而且还包含了 NIO、数组、字符串、Java 8 等主题。

该列表包含了入门级 Java 程序员和多年经验的高级开发者的问题。无论你是 1、2、3、4、5、6、7、8、9 还是 10 年经验的开发者,你都能在其中找到一些有趣的问题。这里包含了一些超级容易回答的问题,同时包含经验丰富的 Java 程序员也会棘手的问题。

当然你们也是非常幸运的,当今有许多好的书来帮助你准备 Java 面试,其中有一本我觉得特别有用和有趣的是 Markham 的 Java 程序面试揭秘(Java Programming Interview Exposed)。 这本书会告诉你一些 Java 和 JEE 面试中最重要的主题,即使你不是准备 Java 面试,也值得一读。

该问题列表特别长,我们有各个地方的问题,所以,答案必须要短小、简洁、干脆,不拖泥带水。因此,除了这一个段落,你只会听到问题与答案,再无其他内容,没有反馈,也没有评价。为此,我已经写好了一些博文,在这些文章中你可以找到我对某些问题的观点,如我为什么喜欢这个问题,这个问题的挑战是什么?期望从面试者那获取到什么样的答案?

这个列表有一点不同,我鼓励你采用类似的方式去分享问题和答案,这样容易温习。我希望这个列表对面试官和候选人都有很好的用处,面试官可以对这些问题上做一些改变以获取新奇和令人惊奇的元素,这对一次好的面试来说非常重要。而候选者,可以扩展和测试 Java 程序语言和平台关键领域的知识。2015 年,会更多的关注并发概念,JVM 内部,32 位 JVM 和 64 JVM的区别,单元测试及整洁的代码。我确信,如果你读过这个庞大的 Java 面试问题列表,无论是电话面试还是面对面的面试,你都能有很好的表现。

Java 面试中的重要话题

除了你看到的惊人的问题数量,我也尽量保证质量。我不止一次分享各个重要主题中的问题,也确保包含所谓的高级话题,这些话题很多程序员不喜欢准备或者直接放弃,因为他们的工作不会涉及到这些。Java NIO 和 JVM 底层就是最好的例子。你也可以将设计模式划分到这一类中,但是越来越多有经验的程序员了解 GOF 设计模式并应用这些模式。我也尽量在这个列表中包含 2015 年最新的面试问题,这些问题可能是来年关注的核心。为了给你一个大致的了解,下面列出这份 Java 面试问题列表包含的主题:

多线程,并发及线程基础
数据类型转换的基本原则
垃圾回收(GC)
Java 集合框架
数组
字符串
GOF 设计模式
SOLID (单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)设计原则
抽象类与接口
Java 基础,如 equals 和 hashcode
泛型与枚举
Java IO 与 NIO
常用网络协议
Java 中的数据结构和算法
正则表达式
JVM 底层
Java 最佳实践
JDBC
Date, Time 与 Calendar
Java 处理 XML
JUnit
编程

120 大 Java 面试题及答案

现在是时候给你展示我近 5 年从各种面试中收集来的 120 个问题了。我确定你在自己的面试中见过很多这些问题,很多问题你也能正确回答。

多线程、并发及线程的基础问题

1)Java 中能创建 volatile 数组吗?
能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。我的意思是,如果改变引用指向的数组,将会受到 volatile 的保护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前的保护作用了。

2)volatile 能使得一个非原子操作变成原子操作吗?
一个典型的例子是在类中有一个 long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取 long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或 double 变量的读写是原子。

3)volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和 long 都是64位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,这个过程不是原子的,但 Java 中 volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障(write barrier),读一个 volatile 变量之前,会插入一个读屏障(read barrier)。意思就是说,在你写一个 volatile 域时,能保证任何线程都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。

4)volatile 类型变量提供什么保证?(答案)
volatile 变量提供顺序和可见性保证,例如,JVM 或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和 long 就是原子的。

5) 10 个线程和 2 个线程的同步代码,哪个更容易写?
从写代码的角度来说,两者的复杂度是相同的,因为同步代码与线程数量是相互独立的。但是同步策略的选择依赖于线程的数量,因为越多的线程意味着更大的竞争,所以你需要利用同步技术,如锁分离,这要求更复杂的代码和专业知识。

6)你是如何调用 wait()方法的?使用 if 块还是循环?为什么?(答案)
wait() 方法应该在循环调用,因为当线程获取到 CPU 开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:

1
2
3
4
5
6
// The standard idiom for using the wait method
synchronized (obj) {
while (condition does not hold)
obj.wait(); // (Releases lock, and reacquires on wakeup)
... // Perform action appropriate to condition
}

参见 Effective Java 第 69 条,获取更多关于为什么应该在循环中来调用 wait 方法的内容。

7)什么是多线程环境下的伪共享(false sharing)?
伪共享是多线程系统(每个处理器有自己的局部缓存)中一个众所周知的性能问题。伪共享发生在不同处理器的上的线程对变量的修改依赖于相同的缓存行。

有经验程序员的 Java 面试题

伪共享问题很难被发现,因为线程可能访问完全不同的全局变量,内存中却碰巧在很相近的位置上。如其他诸多的并发问题,避免伪共享的最基本方式是仔细审查代码,根据缓存行来调整你的数据结构。

8)什么是 Busy spin?我们为什么要使用它?
Busy spin 是一种在不释放 CPU 的基础上等待事件的技术。它经常用于避免丢失 CPU 缓存中的数据(如果线程先暂停,之后在其他CPU上运行就会丢失)。所以,如果你的工作要求低延迟,并且你的线程目前没有任何顺序,这样你就可以通过循环检测队列中的新消息来代替调用 sleep() 或 wait() 方法。它唯一的好处就是你只需等待很短的时间,如几微秒或几纳秒。LMAX 分布式框架是一个高性能线程间通信的库,该库有一个 BusySpinWaitStrategy 类就是基于这个概念实现的,使用 busy spin 循环 EventProcessors 等待屏障。

9)Java 中怎么获取一份线程 dump 文件?
在 Linux 下,你可以通过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java 应用的 dump 文件。在 Windows 下,你可以按下 Ctrl + Break 来获取。这样 JVM 就会将线程的 dump 文件打印到标准输出或错误文件中,它可能打印在控制台或者日志文件中,具体位置依赖应用的配置。如果你使用Tomcat。

10)Swing 是线程安全的?(答案)
不是,Swing 不是线程安全的。你不能通过任何线程来更新 Swing 组件,如 JTable、JList 或 JPanel,事实上,它们只能通过 GUI 或 AWT 线程来更新。这就是为什么 Swing 提供 invokeAndWait() 和 invokeLater() 方法来获取其他线程的 GUI 更新请求。这些方法将更新请求放入 AWT 的线程队列中,可以一直等待,也可以通过异步更新直接返回结果。你也可以在参考答案中查看和学习到更详细的内容。

11)什么是线程局部变量?(答案)
线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。

12)用 wait-notify 写一段代码来解决生产者-消费者问题?(答案)
请参考答案中的示例代码。只要记住在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。

13) 用 Java 写一个线程安全的单例模式(Singleton)?(答案)
请参考答案中的示例代码,这里面一步一步教你创建一个线程安全的 Java 单例类。当我们说线程安全时,意思是即使初始化是在多线程环境中,仍然能保证单个实例。Java 中,使用枚举作为单例类是最简单的方式来创建线程安全单例模式的方式。

14)Java 中 sleep 方法和 wait 方法的区别?(答案)
虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁。

15)什么是不可变对象(immutable object)?Java 中怎么创建一个不可变对象?(答案)
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。详情参见答案,一步一步指导你在 Java 中创建一个不可变的类。

16)我们能创建一个包含可变对象的不可变对象吗?
是的,我们是可以创建一个包含可变对象的不可变对象的,你只需要谨慎一点,不要共享可变对象的引用就可以了,如果需要变化时,就返回原对象的一个拷贝。最常见的例子就是对象中包含一个日期对象的引用。

数据类型和 Java 基础面试问题

17)Java 中应该使用什么数据类型来代表价格?(答案)
如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的 double 类型。

18)怎么将 byte 转换为 String?(答案)
可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

19)Java 中怎样将 bytes 转换为 long 类型?
这个问题你来回答 🙂

20)我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于 byte 类型的范围,将会出现什么现象?
是的,我们可以做强制转换,但是 Java 中 int 是 32 位的,而 byte 是 8 位的,所以,如果强制转化是,int 类型的高 24 位将会被丢弃,byte 类型的范围是从 -128 到 128。

21)存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为 C 么?如 C = (C) B;(answer答案)

22)哪个类包含 clone 方法?是 Cloneable 还是 Object?(答案)
java.lang.Cloneable 是一个标示性接口,不包含任何方法,clone 方法在 object 类中定义。并且需要知道 clone() 方法是一个本地方法,这意味着它是由 c 或 c++ 或 其他本地语言实现的。

23)Java 中 ++ 操作符是线程安全的吗?(答案)
23)不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。

24)a = a + b 与 a += b 的区别(答案)
+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。如果加法操作的结果比 a 的最大值要大,则 a+b 会出现编译错误,但是 a += b 没问题,如下:
byte a = 127;
byte b = 127;
b = a + b; // error : cannot convert from int to byte
b += a; // ok
(译者注:这个地方应该表述的有误,其实无论 a+b 的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)

25)我能在不进行强制转换的情况下将一个 double 值赋值给 long 类型的变量吗?(答案)
不行,你不能在没有强制类型转换的前提下将一个 double 值赋值给 long 类型的变量,因为 double 类型的范围比 long 类型更广,所以必须要进行强制转换。

26)3*0.1 == 0.3 将会返回什么?true 还是 false?(答案)
false,因为有些浮点数不能完全精确的表示出来。

27)int 和 Integer 哪个会占用更多的内存?(答案)
Integer 对象会占用更多的内存。Integer 是一个对象,需要存储对象的元数据。但是 int 是一个原始类型的数据,所以占用的空间更少。

28)为什么 Java 中的 String 是不可变的(Immutable)?(answer答案)
Java 中的 String 不可变是因为 Java 的设计者认为字符串使用非常频繁,将字符串设置为不可变可以允许多个客户端之间共享相同的字符串。更详细的内容参见答案。

29)我们能在 Switch 中使用 String 吗?(answer答案)
从 Java 7 开始,我们可以在 switch case 中使用字符串,但这仅仅是一个语法糖。内部实现在 switch 中使用字符串的 hash code。

30)Java 中的构造器链是什么?(answer答案)
当你从一个构造器中调用另一个构造器,就是Java 中的构造器链。这种情况只在重载了类的构造器的时候才会出现。

JVM 底层 与 GC(Garbage Collection) 的面试问题

31)64 位 JVM 中,int 的长度是多数?
Java 中,int 类型变量的长度是一个固定值,与平台无关,都是 32 位。意思就是说,在 32 位 和 64 位 的Java 虚拟机中,int 类型的长度是相同的。

32)Serial 与 Parallel GC之间的不同之处?(答案)
Serial 与 Parallel 在GC执行的时候都会引起 stop-the-world。它们之间主要不同 serial 收集器是默认的复制收集器,执行 GC 的时候只有一个线程,而 parallel 收集器使用多个 GC 线程来执行。

33)32 位和 64 位的 JVM,int 类型变量的长度是多数?(答案)
32 位和 64 位的 JVM 中,int 类型变量的长度是相同的,都是 32 位或者 4 个字节。

34)Java 中 WeakReference 与 SoftReference的区别?(答案)
虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率,但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。

35)WeakHashMap 是怎么工作的?(答案)
WeakHashMap 的工作与正常的 HashMap 类似,但是使用弱引用作为 key,意思就是当 key 对象没有任何引用时,key/value 将会被回收。

36)JVM 选项 -XX:+UseCompressedOops 有什么作用?为什么要使用?(答案)
当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位的 OOP。

37)怎样通过 Java 程序来判断 JVM 是 32 位 还是 64 位?(答案)
你可以检查某些系统属性如 sun.arch.data.model 或 os.arch 来获取该信息。

38)32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数?(答案)
理论上说上 32 位的 JVM 堆内存可以到达 2^32,即 4GB,但实际上会比这个小很多。不同操作系统之间不同,如 Windows 系统大约 1.5 GB,Solaris 大约 3GB。64 位 JVM允许指定最大的堆内存,理论上可以达到 2^64,这是一个非常大的数字,实际上你可以指定堆内存大小到 100GB。甚至有的 JVM,如 Azul,堆内存到 1000G 都是可能的。

39)JRE、JDK、JVM 及 JIT 之间有什么不同?(答案)
JRE 代表 Java 运行时(Java run-time),是运行 Java 引用所必须的。JDK 代表 Java 开发工具(Java development kit),是 Java 程序的开发工具,如 Java 编译器,它也包含 JRE。JVM 代表 Java 虚拟机(Java virtual machine),它的责任是运行 Java 应用。JIT 代表即时编译(Just In Time compilation),当代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码,如,主要的热点代码会被准换为本地代码,这样有利大幅度提高 Java 应用的性能。

3 年工作经验的 Java 面试题

40)解释 Java 堆空间及 GC?(答案)
当通过 Java 命令启动 Java 进程的时候,会为它分配内存。内存的一部分用于创建堆空间,当程序中创建对象的时候,就从对空间中分配内存。GC 是 JVM 内部的一个进程,回收无效对象的内存用于将来的分配。

 

JVM 底层面试题及答案

41)你能保证 GC 执行吗?(答案)
不能,虽然你可以调用 System.gc() 或者 Runtime.gc(),但是没有办法保证 GC 的执行。

42)怎么获取 Java 程序使用的内存?堆使用的百分比?
可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及最大堆内存。通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间。Runtime.freeMemory() 方法返回剩余空间的字节数,Runtime.totalMemory() 方法总内存的字节数,Runtime.maxMemory() 返回最大内存的字节数。

43)Java 中堆和栈有什么区别?(答案)
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。

关于内存的的面试问题和答案

Java 基本概念面试题

44)“a==b”和”a.equals(b)”有什么区别?(答案)
如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。

45)a.hashCode() 有什么用?与 a.equals(b) 有什么关系?(答案)
hashCode() 方法是相应对象整型的 hash 值。它常用于基于 hash 的集合类,如 Hashtable、HashMap、LinkedHashMap等等。它与 equals() 方法关系特别紧密。根据 Java 规范,两个使用 equal() 方法来判断相等的对象,必须具有相同的 hash code。

46)final、finalize 和 finally 的不同之处?(答案)
final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。

47)Java 中的编译期常量是什么?使用它又什么风险?
公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。

Java 集合框架的面试题

这部分也包含数据结构、算法及数组的面试问题

48) List、Set、Map 和 Queue 之间的区别(答案)
List 是一个有序集合,允许元素重复。它的某些实现可以提供基于下标值的常量访问时间,但是这不是 List 接口保证的。Set 是一个无序集合。

49)poll() 方法和 remove() 方法的区别?
poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。

50)Java 中 LinkedHashMap 和 PriorityQueue 的区别是什么?(答案)
PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部,但是 LinkedHashMap 维持的顺序是元素插入的顺序。当遍历一个 PriorityQueue 时,没有任何顺序保证,但是 LinkedHashMap 课保证遍历顺序是元素插入的顺序。

51)ArrayList 与 LinkedList 的不区别?(答案)
最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构书链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。更多细节的讨论参见答案。

52)用哪两种方式来实现集合的排序?(答案)
你可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通过 Collections.sort() 来排序。

53)Java 中怎么打印数组?(answer答案)
你可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来打印数组。由于数组没有实现 toString() 方法,所以如果将数组传递给 System.out.println() 方法,将无法打印出数组的内容,但是 Arrays.toString() 可以打印每个元素。

54)Java 中的 LinkedList 是单向链表还是双向链表?(答案)
是双向链表,你可以检查 JDK 的源码。在 Eclipse,你可以使用快捷键 Ctrl + T,直接在编辑器中打开该类。

55)Java 中的 TreeMap 是采用什么树实现的?(答案)
Java 中的 TreeMap 是使用红黑树实现的。

56) Hashtable 与 HashMap 有什么不同之处?(答案)
这两个类有许多不同的地方,下面列出了一部分:
a) Hashtable 是 JDK 1 遗留下来的类,而 HashMap 是后来增加的。
b)Hashtable 是同步的,比较慢,但 HashMap 没有同步策略,所以会更快。
c)Hashtable 不允许有个空的 key,但是 HashMap 允许出现一个 null key。
更多的不同之处参见答案。

57)Java 中的 HashSet,内部是如何工作的?(answer答案)
HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。

58)写一段代码在遍历 ArrayList 时移除一个元素?(答案)
该问题的关键在于面试者使用的是 ArrayList 的 remove() 还是 Iterator 的 remove()方法。这有一段示例代码,是使用正确的方式来实现在遍历的过程中移除元素,而不会出现 ConcurrentModificationException 异常的示例代码。

59)我们能自己写一个容器类,然后使用 for-each 循环码?
可以,你可以写一个自己的容器类。如果你想使用 Java 中增强的循环来遍历,你只需要实现 Iterable 接口。如果你实现 Collection 接口,默认就具有该属性。

60)ArrayList 和 HashMap 的默认大小是多数?(答案)

在 Java 7 中,ArrayList 的默认大小是 10 个元素,HashMap 的默认大小是16个元素(必须是2的幂)。这就是 Java 7 中 ArrayList 和 HashMap 类的代码片段:

1
2
3
4
5
// from ArrayList.java JDK 1.7
private static final int DEFAULT_CAPACITY = 10;
//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

61)有没有可能两个不相等的对象有有相同的 hashcode?
有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在 hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必须有相同的hashcode 值,但是没有关于不相等对象的任何规定。

62)两个相同的对象会有不同的的 hash code 吗?
不能,根据 hash code 的规定,这是不可能的。

63)我们可以在 hashcode() 中使用随机数字吗?(答案)
不行,因为对象的 hashcode 值必须是相同的。参见答案获取更多关于 Java 中重写 hashCode() 方法的知识。

64)Java 中,Comparator 与 Comparable 有什么不同?(答案)
Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。

65)为什么在重写 equals 方法的时候需要重写 hashCode 方法?(答案)
因为有强制的规范指定需要同时重写 hashcode 与 equal 是方法,许多容器类,如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。

Java IO 和 NIO 的面试题

IO 是 Java 面试中一个非常重要的点。你应该很好掌握 Java IO,NIO,NIO2 以及与操作系统,磁盘 IO 相关的基础知识。下面是 Java IO 中经常问的问题。

66)在我 Java 程序中,我有三个 socket,我需要多少个线程来处理?

67)Java 中怎么创建 ByteBuffer?

68)Java 中,怎么读写 ByteBuffer ?

69)Java 采用的是大端还是小端?

70)ByteBuffer 中的字节序是什么?

71)Java 中,直接缓冲区与非直接缓冲器有什么区别?(答案)

72)Java 中的内存映射缓存区是什么?(answer答案)

73)socket 选项 TCP NO DELAY 是指什么?

74)TCP 协议与 UDP 协议有什么区别?(answer答案)

75)Java 中,ByteBuffer 与 StringBuffer有什么区别?(答案)

Java 最佳实践的面试问题

包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等。

76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)
这是我在写Java 并发程序的时候遵循的一些最佳实践:
a)给线程命名,这样可以帮助调试。
b)最小化同步的范围,而不是将整个方法同步,只对关键部分做同步。
c)如果可以,更偏向于使用 volatile 而不是 synchronized。
d)使用更高层次的并发工具,而不是使用 wait() 和 notify() 来实现线程间通信,如 BlockingQueue,CountDownLatch 及 Semeaphore。
e)优先使用并发集合,而不是对集合进行同步。并发集合提供更好的可扩展性。

77)说出几点 Java 中使用 Collections 的最佳实践(答案)
这是我在使用 Java 中 Collectionc 类的一些最佳实践:
a)使用正确的集合类,例如,如果不需要同步列表,使用 ArrayList 而不是 Vector。
b)优先使用并发集合,而不是对集合进行同步。并发集合提供更好的可扩展性。
c)使用接口代表和访问集合,如使用List存储 ArrayList,使用 Map 存储 HashMap 等等。
d)使用迭代器来循环集合。
e)使用集合的时候使用泛型。

78)说出至少 5 点在 Java 中使用线程的最佳实践。(答案)
这个问题与之前的问题类似,你可以使用上面的答案。对线程来说,你应该:
a)对线程命名
b)将线程和任务分离,使用线程池执行器来执行 Runnable 或 Callable。
c)使用线程池

79)说出 5 条 IO 的最佳实践(答案)
IO 对 Java 应用的性能非常重要。理想情况下,你不应该在你应用的关键路径上避免 IO 操作。下面是一些你应该遵循的 Java IO 最佳实践:
a)使用有缓冲区的 IO 类,而不要单独读取字节或字符。
b)使用 NIO 和 NIO2
c)在 finally 块中关闭流,或者使用 try-with-resource 语句。
d)使用内存映射文件获取更快的 IO。

80)列出 5 个应该遵循的 JDBC 最佳实践(答案)
有很多的最佳实践,你可以根据你的喜好来例举。下面是一些更通用的原则:
a)使用批量的操作来插入和更新数据
b)使用 PreparedStatement 来避免 SQL 异常,并提高性能。
c)使用数据库连接池
d)通过列名来获取结果集,不要使用列的下标来获取。

81)说出几条 Java 中方法重载的最佳实践?(答案)
下面有几条可以遵循的方法重载的最佳实践来避免造成自动装箱的混乱。
a)不要重载这样的方法:一个方法接收 int 参数,而另个方法接收 Integer 参数。
b)不要重载参数数量一致,而只是参数顺序不同的方法。
c)如果重载的方法参数个数多于 5 个,采用可变参数。

Date、Time 及 Calendar 的面试题

82)在多线程环境下,SimpleDateFormat 是线程安全的吗?(答案)
不是,非常不幸,DateFormat 的所有实现,包括 SimpleDateFormat 都不是线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如 将 SimpleDateFormat 限制在 ThreadLocal 中。如果你不这么做,在解析或者格式化日期的时候,可能会获取到一个不正确的结果。因此,从日期、时间处理的所有实践来说,我强力推荐 joda-time 库。

83)Java 中如何格式化一个日期?如格式化为 ddMMyyyy 的形式?(答案)
Java 中,可以使用 SimpleDateFormat 类或者 joda-time 库来格式日期。DateFormat 类允许你使用多种流行的格式来格式化日期。参见答案中的示例代码,代码中演示了将日期格式化成不同的格式,如 dd-MM-yyyy 或 ddMMyyyy。

84)Java 中,怎么在格式化的日期中显示时区?(答案)

85)Java 中 java.util.Date 与 java.sql.Date 有什么区别?(答案)

86)Java 中,如何计算两个日期之间的差距?(程序)

87)Java 中,如何将字符串 YYYYMMDD 转换为日期?(答案)

单元测试 JUnit 面试题

89)如何测试静态方法?(答案)
可以使用 PowerMock 库来测试静态方法。

90)怎么利用 JUnit 来测试一个方法的异常?(答案)

91)你使用过哪个单元测试库来测试你的 Java 程序?(答案)

92)@Before 和 @BeforeClass 有什么区别?(答案)

编程和代码相关的面试题

93)怎么检查一个字符串只包含数字?(解决方案)

94)Java 中如何利用泛型写一个 LRU 缓存?(答案<)

95)写一段 Java 程序将 byte 转换为 long?(答案)

95)在不使用 StringBuffer 的前提下,怎么反转一个字符串?(解决方案)

97)Java 中,怎么获取一个文件中单词出现的最高频率?(解决方案)

98)如何检查出两个给定的字符串是反序的?(解决方案)

99)Java 中,怎么打印出一个字符串的所有排列?(解决方案)

100)Java 中,怎样才能打印出数组中的重复元素?(解决方案)

101)Java 中如何将字符串转换为整数?(解决方案)

102)在没有使用临时变量的情况如何交换两个整数变量的值?(解决方案)

关于 OOP 和设计模式的面试题

这部分包含 Java 面试过程中关于 SOLID 的设计原则,OOP 基础,如类,对象,接口,继承,多态,封装,抽象以及更高级的一些概念,如组合、聚合及关联。也包含了 GOF 设计模式的问题。

103)接口是什么?为什么要使用接口而不是直接使用具体类?
接口用于定义 API。它定义了类必须得遵循的规则。同时,它提供了一种抽象,因为客户端只使用接口,这样可以有多重实现,如 List 接口,你可以使用可随机访问的 ArrayList,也可以使用方便插入和删除的 LinkedList。接口中不允许写代码,以此来保证抽象,但是 Java 8 中你可以在接口声明静态的默认方法,这种方法是具体的。

104)Java 中,抽象类与接口之间有什么不同?(答案)
Java 中,抽象类和接口有很多不同之处,但是最重要的一个是 Java 中限制一个类只能继承一个类,但是可以实现多个接口。抽象类可以很好的定义一个家族类的默认行为,而接口能更好的定义类型,有助于后面实现多态机制。关于这个问题的讨论请查看答案。

105)除了单例模式,你在生产环境中还用过什么设计模式?
这需要根据你的经验来回答。一般情况下,你可以说依赖注入,工厂模式,装饰模式或者观察者模式,随意选择你使用过的一种即可。不过你要准备回答接下的基于你选择的模式的问题。

106)你能解释一下里氏替换原则吗?(答案)

107) 什么情况下会违反迪米特法则?为什么会有这个问题?(答案)
迪米特法则建议“只和朋友说话,不要陌生人说话”,以此来减少类之间的耦合。

108)适配器模式是什么?什么时候使用?
适配器模式提供对接口的转换。如果你的客户端使用某些接口,但是你有另外一些接口,你就可以写一个适配去来连接这些接口。

109)什么是“依赖注入”和“控制反转”?为什么有人使用?(答案)

110)抽象类是什么?它与接口有什么区别?你为什么要使用过抽象类?(答案)

111)构造器注入和 setter 依赖注入,那种方式更好?(答案)
每种方式都有它的缺点和优点。构造器注入保证所有的注入都被初始化,但是 setter 注入提供更好的灵活性来设置可选依赖。如果使用 XML 来描述依赖,Setter 注入的可读写会更强。经验法则是强制依赖使用构造器注入,可选依赖使用 setter 注入。

112)依赖注入和工程模式之间有什么不同?(答案)
虽然两种模式都是将对象的创建从应用的逻辑中分离,但是依赖注入比工程模式更清晰。通过依赖注入,你的类就是 POJO,它只知道依赖而不关心它们怎么获取。使用工厂模式,你的类需要通过工厂来获取依赖。因此,使用 DI 会比使用工厂模式更容易测试。关于这个话题的更详细讨论请参见答案。

113)适配器模式和装饰器模式有什么区别?(答案)
虽然适配器模式和装饰器模式的结构类似,但是每种模式的出现意图不同。适配器模式被用于桥接两个接口,而装饰模式的目的是在不修改类的情况下给类增加新的功能。

114)适配器模式和代理模式之前有什么不同?(答案)
这个问题与前面的类似,适配器模式和代理模式的区别在于他们的意图不同。由于适配器模式和代理模式都是封装真正执行动作的类,因此结构是一致的,但是适配器模式用于接口之间的转换,而代理模式则是增加一个额外的中间层,以便支持分配、控制或智能访问。

115)什么是模板方法模式?(答案)
模板方法提供算法的框架,你可以自己去配置或定义步骤。例如,你可以将排序算法看做是一个模板。它定义了排序的步骤,但是具体的比较,可以使用 Comparable 或者其语言中类似东西,具体策略由你去配置。列出算法概要的方法就是众所周知的模板方法。

116)什么时候使用访问者模式?(答案)
访问者模式用于解决在类的继承层次上增加操作,但是不直接与之关联。这种模式采用双派发的形式来增加中间层。

117)什么时候使用组合模式?(答案)
组合模式使用树结构来展示部分与整体继承关系。它允许客户端采用统一的形式来对待单个对象和对象容器。当你想要展示对象这种部分与整体的继承关系时采用组合模式。

118)继承和组合之间有什么不同?(答案)
虽然两种都可以实现代码复用,但是组合比继承共灵活,因为组合允许你在运行时选择不同的实现。用组合实现的代码也比继承测试起来更加简单。

119)描述 Java 中的重载和重写?(答案)
重载和重写都允许你用相同的名称来实现不同的功能,但是重载是编译时活动,而重写是运行时活动。你可以在同一个类中重载方法,但是只能在子类中重写方法。重写必须要有继承。

120)Java 中,嵌套公共静态类与顶级类有什么不同?(答案)
类的内部可以有多个嵌套公共静态类,但是一个 Java 源文件只能有一个顶级公共类,并且顶级公共类的名称与源文件名称必须一致。

121) OOP 中的 组合、聚合和关联有什么区别?(答案)
如果两个对象彼此有关系,就说他们是彼此相关联的。组合和聚合是面向对象中的两种形式的关联。组合是一种比聚合更强力的关联。组合中,一个对象是另一个的拥有者,而聚合则是指一个对象使用另一个对象。如果对象 A 是由对象 B 组合的,则 A 不存在的话,B一定不存在,但是如果 A 对象聚合了一个对象 B,则即使 A 不存在了,B 也可以单独存在。

122)给我一个符合开闭原则的设计模式的例子?(答案)
开闭原则要求你的代码对扩展开放,对修改关闭。这个意思就是说,如果你想增加一个新的功能,你可以很容易的在不改变已测试过的代码的前提下增加新的代码。有好几个设计模式是基于开闭原则的,如策略模式,如果你需要一个新的策略,只需要实现接口,增加配置,不需要改变核心逻辑。一个正在工作的例子是 Collections.sort() 方法,这就是基于策略模式,遵循开闭原则的,你不需为新的对象修改 sort() 方法,你需要做的仅仅是实现你自己的 Comparator 接口。

123)抽象工厂模式和原型模式之间的区别?(答案)

124)什么时候使用享元模式?(答案)
享元模式通过共享对象来避免创建太多的对象。为了使用享元模式,你需要确保你的对象是不可变的,这样你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。

Java 面试中其他各式各样的问题

这部分包含 Java 中关于 XML 的面试题,JDBC 面试题,正则表达式面试题,Java 错误和异常及序列化面试题

125)嵌套静态类与顶级类有什么区别?(答案)
一个公共的顶级类的源文件名称与类名相同,而嵌套静态类没有这个要求。一个嵌套类位于顶级类内部,需要使用顶级类的名称来引用嵌套静态类,如 HashMap.Entry 是一个嵌套静态类,HashMap 是一个顶级类,Entry是一个嵌套静态类。

126)你能写出一个正则表达式来判断一个字符串是否是一个数字吗?(解决方案)
一个数字字符串,只能包含数字,如 0 到 9 以及 +、- 开头,通过这个信息,你可以下一个如下的正则表达式来判断给定的字符串是不是数字。

127)Java 中,受检查异常 和 不受检查异常的区别?(答案)
受检查异常编译器在编译期间检查。对于这种异常,方法强制处理或者通过 throws 子句声明。其中一种情况是 Exception 的子类但不是 RuntimeException 的子类。非受检查是 RuntimeException 的子类,在编译阶段不受编译器的检查。

128)Java 中,throw 和 throws 有什么区别?(答案)

throw 用于抛出 java.lang.Throwable 类的一个实例化对象,意思是说你可以通过关键字 throw 抛出一个 Error 或者 一个Exception,如:
throw new IllegalArgumentException(“size must be multiple of 2″)

而throws 的作用是作为方法声明和签名的一部分,方法被抛出相应的异常以便调用者能处理。Java 中,任何未处理的受检查异常强制在 throws 子句中声明。

129)Java 中,Serializable 与 Externalizable 的区别?(答案)
Serializable 接口是一个序列化 Java 类的接口,以便于它们可以在网络上传输或者可以将它们的状态保存在磁盘上,是 JVM 内嵌的默认序列化方式,成本高、脆弱而且不安全。Externalizable 允许你控制整个序列化过程,指定特定的二进制格式,增加安全机制。

130)Java 中,DOM 和 SAX 解析器有什么不同?(答案)
DOM 解析器将整个 XML 文档加载到内存来创建一棵 DOM 模型树,这样可以更快的查找节点和修改 XML 结构,而 SAX 解析器是一个基于事件的解析器,不会将整个 XML 文档加载到内存。由于这个原因,DOM 比 SAX 更快,也要求更多的内存,不适合于解析大 XML 文件。

131)说出 JDK 1.7 中的三个新特性?(答案)
虽然 JDK 1.7 不像 JDK 5 和 8 一样的大版本,但是,还是有很多新的特性,如 try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关闭,Java 会自动关闭。Fork-Join 池某种程度上实现 Java 版的 Map-reduce。允许 Switch 中有 String 变量和文本。菱形操作符(<>)用于类型推断,不再需要在变量声明的右边申明泛型,因此可以写出可读写更强、更简洁的代码。另一个值得一提的特性是改善异常处理,如允许在同一个 catch 块中捕获多个异常。

132)说出 5 个 JDK 1.8 引入的新特性?(答案)
Java 8 在 Java 历史上是一个开创新的版本,下面 JDK 8 中 5 个主要的特性:
Lambda 表达式,允许像对象一样传递匿名函数
Stream API,充分利用现代多核 CPU,可以写出很简洁的代码
Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用
扩展方法,现在,接口中可以有静态、默认方法。
重复注解,现在你可以将相同的注解在同一类型上使用多次。

133)Java 中,Maven 和 ANT 有什么区别?(答案)
虽然两者都是构建工具,都用于创建 Java 应用,但是 Maven 做的事情更多,在基于“约定优于配置”的概念下,提供标准的Java 项目结构,同时能为应用自动管理依赖(应用中所依赖的 JAR 文件),Maven 与 ANT 工具更多的不同之处请参见答案。

这就是所有的面试题,如此之多,是不是?我可以保证,如果你能回答列表中的所有问题,你就可以很轻松的应付任何核心 Java 或者高级 Java 面试。虽然,这里没有涵盖 Servlet、JSP、JSF、JPA,JMS,EJB 及其它 Java EE 技术,也没有包含主流的框架如 Spring MVC,Struts 2.0,Hibernate,也没有包含 SOAP 和 RESTful web service,但是这份列表对做 Java 开发的、准备应聘 Java web 开发职位的人还是同样有用的,因为所有的 Java 面试,开始的问题都是 Java 基础和 JDK API 相关的。如果你认为我这里有任何应该在这份列表中而被我遗漏了的 Java 流行的问题,你可以自由的给我建议。我的目的是从最近的面试中创建一份最新的、最优的 Java 面试问题列表。

Java EE 相关的面试题

为了做 Java EE 的朋友,这里列出了一些 web 开发的特定问题,你们可以用来准备 JEE 部分的面试:

10 大 Spring 框架面试题及答案(参见)
10 个非常好的 XML 面试问题(Java 程序员)(参见)
20 个非常好的设计模式面试问题(参见)
10个最流行的 Struts 面试题(Java 开发者)(参见)
20 个 Tibco Rendezvous 及 EMS 的面试题(更多)
10 个最频繁被问到的 Servlet 面试问题及答案(参见)
20 个 jQuery 面试问题(Java Web 开发者)(列表)
10 个非常好的 Oracle 面试问题(Java 开发者)(参见)
10 大 来自 J2EE 面试中的 JSP 问题(更多)
12 个很好的 RESTful Web Services 面试问题(参见)
10 大 EJB 面试问题及答案(参见)
10 大 JMS 及 MQ 系列面试题及答案(列表)
10 个非常好 Hibernate 面试问题(Java EE 开发者)(参见)
10 个非常好的 JDBC 面试题(Java 开发者)(参见)
15 个 Java NIO 和网络面试题及答案(参见)
10 大 XSLT 面试题及答案(更多)
15 个来自 Java 面试的数据结构和算法问题(参见)
10 大 Java 面试难题及答案(参见)
40 个核心 Java 移动开发面试题及答案(列表)

推荐给 Java 面试者的书籍
如果你正为 Java 面试寻找好的准备,你可以看一下下面的书籍,这些书籍包含了理论及编码的相关问题
Markham 的 Java 编程面试揭秘(参见)
破解编码面试:150 个编程问题及解答(参见)
程序面试揭秘:寻找下一份工作的秘密(参见)

知名公司的Java面试题

later阅读(272)评论(0)

巴克莱投资:

  • 假设有一个 getNextparson() 方法返回 Person 对象,Person 类实现了 comparable 接口,现在从文件中读取记录并排序,然后给出前 1000 条记录,纸上作答
  • 答案见Glassdoor
  • 写一个函数,传入 2 个有序的整数数组,返回一个有序的整数数组。
  • 答案见Glassdoor 

骑士资本

全球医疗交流:

高盛投资:

Google:

  • 给定 2 个包含单词列表(每行一个)的文件,编程列出交集。
  • 答案见Glassdoor

Nextlabs:

树(二叉或其他)形成许多普通数据结构的基础。请描述一些这样的数据结构以及何时可以使用它们。


Delphix:

亚马逊:

  • 给定如下整数列表,如何最有效的进行排序同时剔除重复的数字?
  • 答案见Glassdoor

埃森哲: 

  • 解释 Java 和 C++ 内存管理的不同。
  • 答案见Glassdoor
  • 给定一个 C++ 或 Java 类型/表达式,给出等价的表达(如果存在)。例如:C++ 有常量,Java 有…?
  • 答案见Glassdoor
  • 给一个例子, 关于何时创建一个接口?
  • 答案见Glassdoor

Citi:

微软:

  • 写一个程序找出所有字符串的组合,并检查它们是否是回文串?
  • 答案见Glassdoor

RedMane技术:

技术问题:1. OOP的三个支柱,并解释它们 2. Java 的 final 关键字 3. 抽象类与接口的不同 4. JSP 与 Servlet 的不同 5.  Java 中的不变性 6. 多线程 – 休眠与让步? 7. 什么是设计模式,说一些。解释单例设计模式? 8. 访问修饰符中的 protected 关键字 9. continue 与 break 表达式 10. 描述 MVC 模式 11. StringBuffer 与StringBuilder 12. 一个逻辑/算法问题:向有序数组中插入一个元素到合适的位置。他们将关注非常基础的逻辑设计,如循环,函数和它们的参数。

答案见Glassdoor

OPNET:

BlackBerry:

EverBank Financial:

TRUSTe:

Airline Tariff Publishing Company:

  • 在 Spring 中使用单例实例,你只能得到唯一一个实例。如果应用想得到多个实例,你是怎么重写或克服这种情况的?
  • 答案见Glassdoor

Clearwire:

UC Davis:

  • 两个 JSP 页面见如何传递变量,那么在一个控制权 servlet 和 JSP 页面间呢?
  • 答案见Glassdoor

Deutsche Bank:

  • ArrayList 和 LinkedList 的区别,例如什么时候用 ArrayList?
  • 答案见Glassdoor

Mindteck: 

1. 什么是泛型? 2. arraylist 和 set 的区别? 3. 解释 finally

Antra:

什么 Java 原型不是线程安全的;final 和 finalize 的区别;能否在运行时向 static final 类型的赋值;抽象类和接口的区别?

常见的Java线程面试题

later阅读(212)评论(0)

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发、调试、优化经验,所以线程相关的问题在面试中经常会被提到。

在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如:继承thread类还是调用Runnable接口),然后逐渐问到并发问题像在Java并发编程的过程中遇到了什么挑战,Java内存模型,JDK1.5引入了哪些更高阶的并发工具,并发编程常用的设计模式,经典多线程问题如生产者消费者,哲学家就餐,读写器或者简单的有界缓冲区问题。仅仅知道线程的基本概念是远远不够的, 你必须知道如何处理死锁竞态条件,内存冲突和线程安全等并发问题。掌握了这些技巧,你就可以轻松应对多线程和并发面试了。

许多Java程序员在面试前才会去看面试题,这很正常。因为收集面试题和练习很花时间,所以我从许多面试者那里收集了Java多线程和并发相关的50个热门问题。我只收集了比较新的面试题且没有提供全部答案。想必聪明的你对这些问题早就心中有数了, 如果遇到不懂的问题,你可以用Google找到答案。若你实在找不到答案,可以在文章的评论中向我求助。你也可以在这找到一些答案Java线程问答Top 12

50道Java线程面试题

下面是Java线程相关的热门面试题,你可以用它来好好准备面试。

1) 什么是线程?

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。Java在语言层面对多线程提供了卓越的支持,它也是一个很好的卖点。欲了解更多详细信息请点击这里

2) 线程和进程有什么区别?

线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。更多详细信息请点击这里

3) 如何在Java中实现线程?

在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。更多详细信息请点击这里.

4) 用Runnable还是Thread?

这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用Runnable接口来实现线程,问题是,那个方法更好呢?什么情况下使用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好了。更多详细信息请点击这里

6) Thread 类中的start() 和 run() 方法有什么区别?

这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。更多讨论请点击这里

7) Java中Runnable和Callable有什么不同?

Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。我的博客有更详细的说明。

8) Java中CyclicBarrier 和 CountDownLatch有什么不同?

CyclicBarrier 和 CountDownLatch 都可以用来让一组线程等待其它线程。与 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。点此查看更多信息和示例代码

9) Java内存模型是什么?

Java内存模型规定和指引Java程序在不同的内存架构、CPU和操作系统间有确定性地行为。它在多线程的情况下尤其重要。Java内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。比如,先行发生关系确保了:

  • 线程内的代码能够按先后顺序执行,这被称为程序次序规则。
  • 对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则。
  • 前一个对volatile的写操作在后一个volatile的读操作之前,也叫volatile变量规则。
  • 一个线程内的任何操作必需在这个线程的start()调用之后,也叫作线程启动规则。
  • 一个线程的所有操作都会在线程终止之前,线程终止规则。
  • 一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则。
  • 可传递性

我强烈建议大家阅读《Java并发编程实践》第十六章来加深对Java内存模型的理解。

10) Java中的volatile 变量是什么?

volatile是一个特殊的修饰符,只有成员变量才能使用它。在Java并发程序缺少同步类的情况下,多线程对成员变量的操作对其它线程是透明的。volatile变量可以保证下一个读取操作会在前一个写操作之后发生,就是上一题的volatile变量规则。点击这里查看更多volatile的相关内容。

11) 什么是线程安全?Vector是一个线程安全类吗? (详见这里)

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。

12) Java中什么是竞态条件? 举个例子说明。

竞态条件会导致程序在并发情况下出现一些bugs。多线程对一些资源的竞争的时候就会产生竞态条件,如果首先要执行的程序竞争失败排到后面执行了,那么整个程序就会出现一些不确定的bugs。这种bugs很难发现而且会重复出现,因为线程间的随机竞争。一个例子就是无序处理,详见答案

13) Java中如何停止一个线程?

Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程。点击这里查看示例代码。

14) 一个线程运行时发生异常会怎样?

这是我在一次面试中遇到的一个很刁钻的Java面试题, 简单的说,如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理。

15) 如何在两个线程间共享数据?

你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。这篇教程《Java线程间通信》(涉及到在两个线程间共享对象)用wait和notify方法实现了生产者消费者模型。

16) Java中notify 和 notifyAll有什么区别?

这又是一个刁钻的问题,因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。我的博客有更详细的资料和示例代码。

17) 为什么wait, notify 和 notifyAll这些方法不在thread类里面?

这是个设计相关的问题,它考察的是面试者对现有系统和一些普遍存在但看起来不合理的事物的看法。回答这些问题的时候,你要说明为什么把这些方法放在Object类里是有意义的,还有不把它放在Thread类里的原因。一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。你也可以查看这篇文章了解更多。

18) 什么是ThreadLocal变量?

ThreadLocal是Java里一种特殊的变量。每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法,比如你可以用ThreadLocal让SimpleDateFormat变成线程安全的,因为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。其次,你在没有使用高代价的同步或者不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是ThreadLocalRandom类,它在多线程环境中减少了创建代价高昂的Random对象的个数。查看答案了解更多。

19) 什么是FutureTask?

在Java并发程序中FutureTask表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FutureTask也是调用了Runnable接口所以它可以提交给Executor来执行。

20) Java中interrupted 和 isInterruptedd方法的区别?

interrupted()isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。而非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。无论如何,一个线程的中断状态有有可能被其它线程调用中断来改变。

21) 为什么wait和notify方法要在同步块中调用?

主要是因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。

22) 为什么你应该在循环中检查等待条件?

处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。因此,当一个等待线程醒来时,不能认为它原来的等待状态仍然是有效的,在notify()方法调用之后和等待线程醒来之前这段时间它可能会改变。这就是在循环中使用wait()方法效果更好的原因,你可以在Eclipse中创建模板调用wait和notify试一试。如果你想了解更多关于这个问题的内容,我推荐你阅读《Effective Java》这本书中的线程和同步章节。

23) Java中的同步集合与并发集合有什么区别?

同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5之前程序员们只有同步集合来用且在多线程并发的时候会导致争用,阻碍了系统的扩展性。Java5介绍了并发集合像ConcurrentHashMap,不仅提供线程安全还用锁分离和内部分区等现代技术提高了可扩展性。更多内容详见答案

24) Java中堆和栈有什么不同?

为什么把这个问题归类在多线程和并发面试题里?因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。对象都在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈,如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用了,它要求线程从主存中读取变量的值。
更多内容详见答案

25) 什么是线程池? 为什么要使用它?

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。更多内容详见这篇文章

26) 如何写代码来解决生产者消费者问题?

在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型,这篇教程有实现它。

27) 如何避免死锁?


Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。这篇教程有代码示例和避免死锁的讨论细节。

28) Java中活锁和死锁有什么区别?

这是上题的扩展,活锁和死锁类似,不同之处在于处于活锁的线程或进程的状态是不断改变的,活锁可以认为是一种特殊的饥饿。一个现实的活锁例子是两个人在狭小的走廊碰到,两个人都试着避让对方好让彼此通过,但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是,活锁和死锁的主要区别是前者进程的状态可以改变但是却不能继续执行。

29) 怎么检测一个线程是否拥有锁?

我一直不知道我们竟然可以检测一个线程是否拥有锁,直到我参加了一次电话面试。在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。你可以查看这篇文章了解更多。

30) 你如何在Java中获取线程堆栈?

对于不同的操作系统,有多种方法来获得Java进程的线程堆栈。当你获取线程堆栈时,JVM会把所有线程的状态存到日志文件或者输出到控制台。在Windows你可以使用Ctrl + Break组合键来获取线程堆栈,Linux下用kill -3命令。你也可以用jstack这个工具来获取,它对线程id进行操作,你可以用jps这个工具找到id。

31) JVM中哪个参数是用来控制线程的栈堆栈小的

这个问题很简单, -Xss参数用来控制线程的堆栈大小。你可以查看JVM配置列表来了解这个参数的更多信息。

32) Java中synchronized 和 ReentrantLock 有什么不同?

Java在过去很长一段时间只能通过synchronized关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具有可扩展性。你可以查看这篇文章了解更多

33) 有三个线程T1,T2,T3,怎么确保它们按顺序执行?

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。你可以查看这篇文章了解更多。

34) Thread类中的yield方法有什么作用?

Yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU,执行yield()的线程有可能在进入到暂停状态后马上又被执行。点击这里查看更多yield方法的相关内容。

35) Java中ConcurrentHashMap的并发度是什么?

ConcurrentHashMap把实际map划分成若干部分来实现它的可扩展性和线程安全。这种划分是使用并发度获得的,它是ConcurrentHashMap类构造函数的一个可选参数,默认值为16,这样在多线程情况下就能避免争用。欲了解更多并发度和内部大小调整请阅读我的文章How ConcurrentHashMap works in Java

36) Java中Semaphore是什么?

Java中的Semaphore是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,比如数据库连接池。更多详细信息请点击这里

37)如果你提交任务时,线程池队列已满。会时发会生什么?

这个问题问得很狡猾,许多程序员会认为该任务会阻塞直到线程池队列有空位。事实上如果一个任务不能被调度执行那么ThreadPoolExecutor’s submit()方法将会抛出一个RejectedExecutionException异常。

38) Java线程池中submit() 和 execute()方法有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。更多详细信息请点击这里

39) 什么是阻塞式方法?

阻塞式方法是指程序会一直等待该方法完成期间不做其他事情,ServerSocket的accept()方法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。更多详细信息请点击这里

40) Swing是线程安全的吗? 为什么?

你可以很肯定的给出回答,Swing不是线程安全的,但是你应该解释这么回答的原因即便面试官没有问你为什么。当我们说swing不是线程安全的常常提到它的组件,这些组件不能在多线程中进行修改,所有对GUI组件的更新都要在AWT线程中完成,而Swing提供了同步和异步两种回调方法来进行更新。点击这里查看更多swing和线程安全的相关内容。

41) Java中invokeAndWait 和 invokeLater有什么区别?

这两个方法是Swing API 提供给Java开发者用来从当前线程而不是事件派发线程更新GUI组件用的。InvokeAndWait()同步更新GUI组件,比如一个进度条,一旦进度更新了,进度条也要做出相应改变。如果进度被多个线程跟踪,那么就调用invokeAndWait()方法请求事件派发线程对组件进行相应更新。而invokeLater()方法是异步调用更新组件的。更多详细信息请点击这里

42) Swing API中那些方法是线程安全的?

这个问题又提到了swing和线程安全,虽然组件不是线程安全的但是有一些方法是可以被多线程安全调用的,比如repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert() 和 append() 方法也是线程安全的。

43) 如何在Java中创建Immutable对象?

这个问题看起来和多线程没什么关系, 但不变性有助于简化已经很复杂的并发程序。Immutable对象可以在没有同步的情况下共享,降低了对该对象进行并发访问时的同步化开销。可是Java没有@Immutable这个注解符,要创建不可变类,要实现下面几个步骤:通过构造方法初始化所有成员、对变量不要提供setter方法、将所有的成员声明为私有的,这样就不允许直接访问这些成员、在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝。我的文章how to make an object Immutable in Java有详细的教程,看完你可以充满自信。

44) Java中的ReadWriteLock是什么?

一般而言,读写锁是用来提升并发程序性能的锁分离技术的成果。Java中的ReadWriteLock是Java 5 中新增的一个接口,一个ReadWriteLock维护一对关联的锁,一个用于只读操作一个用于写。在没有写线程的情况下一个读锁可能会同时被多个读线程持有。写锁是独占的,你可以使用JDK中的ReentrantReadWriteLock来实现这个规则,它最多支持65535个写锁和65535个读锁。

45) 多线程中的忙循环是什么?

忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。你可以查看这篇文章获得更多信息。

46)volatile 变量和 atomic 变量有什么不同?

这是个有趣的问题。首先,volatile 变量和 atomic 变量看起来很像,但功能却不一样。Volatile变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操作就不是原子性的。而AtomicInteger类提供的atomic方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一,其它数据类型和引用变量也可以进行相似操作。

47) 如果同步块内的线程抛出异常会发生什么?

这个问题坑了很多Java程序员,若你能想到锁是否释放这条线索来回答还有点希望答对。无论你的同步块是正常还是异常退出的,里面的线程都会释放锁,所以对比锁接口我更喜欢同步块,因为它不用我花费精力去释放锁,该功能可以在finally block里释放锁实现。

48) 单例模式的双检锁是什么?

这个问题在Java面试中经常被问到,但是面试官对回答此问题的满意度仅为50%。一半的人写不出双检锁还有一半的人说不出它的隐患和Java1.5是如何对它修正的。它其实是一个用来创建线程安全的单例的老方法,当单例实例第一次被创建时它试图用单个锁进行性能优化,但是由于太过于复杂在JDK1.4中它是失败的,我个人也不喜欢它。无论如何,即便你也不喜欢它但是还是要了解一下,因为它经常被问到。你可以查看how double checked locking on Singleton works这篇文章获得更多信息。

49) 如何在Java中创建线程安全的Singleton?

这是上面那个问题的后续,如果你不喜欢双检锁而面试官问了创建Singleton类的替代方法,你可以利用JVM的类加载和静态变量初始化特征来创建Singleton实例,或者是利用枚举类型来创建Singleton,我很喜欢用这种方法。你可以查看这篇文章获得更多信息。

50) 写出3条你遵循的多线程最佳实践

这种问题我最喜欢了,我相信你在写并发代码来提升性能的时候也会遵循某些最佳实践。以下三条最佳实践我觉得大多数Java程序员都应该遵循:

  • 给你的线程起个有意义的名字。
    这样可以方便找bug或追踪。OrderProcessor, QuoteProcessor or TradeProcessor 这种名字比 Thread-1. Thread-2 and Thread-3 好多了,给线程起一个和它要完成的任务相关的名字,所有的主要框架甚至JDK都遵循这个最佳实践。
  • 避免锁定和缩小同步的范围
    锁花费的代价高昂且上下文切换更耗费时间空间,试试最低限度的使用同步和锁,缩小临界区。因此相对于同步方法我更喜欢同步块,它给我拥有对锁的绝对控制权。
  • 多用同步类少用wait 和 notify
    首先,CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 这些同步类简化了编码操作,而用wait和notify很难实现对复杂控制流的控制。其次,这些类是由最好的企业编写和维护在后续的JDK中它们还会不断优化和完善,使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。
  • 多用并发集合少用同步集合
    这是另外一个容易遵循且受益巨大的最佳实践,并发集合比同步集合的可扩展性更好,所以在并发编程时使用并发集合效果更好。如果下一次你需要用到map,你应该首先想到用ConcurrentHashMap。我的文章Java并发集合有更详细的说明。

51) 如何强制启动一个线程?

这个问题就像是如何强制进行Java垃圾回收,目前还没有觉得方法,虽然你可以使用System.gc()来进行垃圾回收,但是不保证能成功。在Java里面没有办法强制启动一个线程,它是被线程调度器控制着且Java没有公布相关的API。

52) Java中的fork join框架是什么?

fork join框架是JDK7中出现的一款高效的工具,Java开发人员可以通过它充分利用现代服务器上的多处理器。它是专门为了那些可以递归划分成许多子模块设计的,目的是将所有可用的处理能力用来提升程序的性能。fork join框架一个巨大的优势是它使用了工作窃取算法,可以完成更多任务的工作线程可以从其它线程中窃取任务来执行。你可以查看这篇文章获得更多信息。

53) Java多线程中调用wait() 和 sleep()方法有什么不同?

Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。你可以查看这篇文章获得更多信息。

以上就是50道热门Java多线程和并发面试题啦。我没有分享所有题的答案但给未来的阅读者提供了足够的提示和线索来寻找答案。如果你真的找不到某题的答案,联系我吧,我会加上去的。这篇文章不仅可以用来准备面试,还能检查你对多线程、并发、设计模式和竞态条件、死锁和线程安全等线程问题的理解。我打算把这篇文章的问题弄成所有Java多线程问题的大合集,但是没有你的帮助恐怖是不能完成的,你也可以跟我分享其它任何问题,包括那些你被问到却还没有找到答案的问题。这篇文章对初学者或者是经验丰富的Java开发人员都很有用,过两三年甚至五六年你再读它也会受益匪浅。它可以扩展初学者尤其有用因为这个可以扩展他们的知识面,我会不断更新这些题,大家可以在文章后面的评论中提问,分享和回答问题一起把这篇面试题完善。

互联网大厂(BAT)职称解读

later阅读(469)评论(0)

 
 
1. 举个栗子。校招不论,单说社招。想知道阿里内部级别和薪资待遇的题主,或许正面临offer选择,就像这位纠结阿里系offer的同学W:
最近刚通过面试,但基本薪酬也是不升反小降。 级别只有P6+,连P7都没有,非常郁闷,打算拒绝算了。小本工作9年了,这算不算loser ?
奇了怪了,阿里系的P6和P7的范围到底是多少?
不过反过来说,阿里系面试还真是有点深度的,通过不易,但拿到这个级别总感觉是否自已混的太一般了。
郁闷。
这样的纠结实在太常见了,都是工作好几年的老程序员了,好不容易动心跳个槽,猎头开始保证得好好的,怎么拿到offer的薪酬却不尽如人意?是自己能力不够,还是被HR/猎头忽悠?
 
专心做技术的大都是心思单纯之人,却最容易吃亏。知己知彼方可百战不殆,看看对方的级别和待遇,谋定而后动,才能跳得更远,走得更稳。
 
2. 先看阿里的级别定义:
P序列=技术岗 M序列=管理岗
 
  • 阿里的非管理岗分为10级
  • 其中P6、P7、P8需求量最大,也是阿里占比最大的级别
前面栗子中郁闷的W同学拿到了P6+的offer,正处于最庞大但又最尴尬的级别中段,至于为什么差一点儿没拿到P7,难道是HR在省招聘费?
哦,江湖传言@Fenng是P7,@鬼脚七是P9,改日向我司 100offer-高端人才招聘网站 隔壁的P9求证。
(踌躇满志的程序员可以看看:从P1到P7——我在淘宝这7年
 
3. 再看阿里的级别对应薪资:
 
•阿里薪资结构:一般是12+1+3=16薪
•年底的奖金为0-6个月薪资,90%人可拿到3个月
•股票是工作满2年才能拿,第一次拿50%,4年能全部拿完
 
说到股票,真是要普及下常识,别被忽悠了。股票是公司用来奖励员工忠诚度的,所以阿里分年限行权,想要离职套现真的是难。更不要高额的税收了,首先,归属要收高达45%的个税,然后得到的还是限制性股票,还不能马上卖呢。好不容易可以出售的时候,还得交20%股票增值部分的个人所得税哦!
更重要的是,你必须先缴税,才能归属,缴税还必须用现金,不能sell to cover!So,拿的越多,先拿出的cash就越多,这里面的流动性风险你自己权衡吧。
 
  • 再说说级别分层和阿里类似的百度
1. 百度的技术级别:
百度有4万人,每年招聘应届生技术产品人员1000人左右,技术岗位级别和阿里类似,分为T序列12级,不赘述了,大概阿里的级别减1或2,就是百度的级别。
•主要集中在T5/T6,升T7很困难,T7升T8更困难;T7以上一般就不做coding了
•一般来说,在百度待3年能给到T5,很多人都等不到三年,原因下面说,社招过来的,一般是外面公司的技术骨干了
•T10是技术总监,十个左右;T11是首席科学家;T12基本没见过。
 
2. 再看百度薪资的大概范围:
 
 
•百度薪资结构:月薪*14.6(12+0.6+2),其他岗位月薪*14
•T5以上为关键岗位,另外有股票、期权
•T5、T6占比最大的级别,T8、T9占比最小
•级别越高,每档之间的宽幅越大
 
百度是一家业务定性,内部稳定,金字塔形的成熟公司。也就是说,大部分事情都是按部就班、驾轻就熟,所有人都比较轻松、稳定、舒服,尤其是对老员工而言。但是对于新员工来说,这意味着成长空间的极度压缩,机会少,上升慢。
 
百度工资高,福利好,但是这么多年期权已经基本发光了,只有总监以上才有,几十股几百股就算多了。问题就来了,百度新老员工的期权数量太悬殊,据说到百度楼下停车场一看,开卡宴的都是老员工,开捷达的都是新员工,其实很多新员工的贡献比老员工大得多,但是收入反而倒挂,于是很多新人等不到3年就跳了。
 
  • 最后谈谈最南边的腾讯
1. 腾讯的技术级别:
腾讯的分级和阿里/百度都不一样,分为T1/T2/T3/T4共4级,其中又细分为3级。
•员工仍然集中在中段,尤其是 T2.3 和 T3.1
•想从T2跨到T3,即从2.3升3.1是非常困难的
 
2. 了解薪酬和级别的关系:
 
• 腾讯标准薪资是14薪,但是通常能拿到16-20薪
• T3.1以上开始另外有股票
值得一提的是,腾讯是有淘汰制考核的。一般一年两次考核(6月、12月),实行末尾淘汰制,0-10%优秀,必须有5%的人转组(转组也可能出现没人接收的情况)或者被开除,这点比较狠。
升级也跟考核结果很有关系,要升一个小等级,必须最近两次考核得过一次A类考核结果。升 T3.1是内部晋升的第一道槛,要求架构在领域内优秀,被追问攻击时能无漏洞应答出来–据说只有30%的通过率。同时,腾讯好的一点在于,底层普通员工如果技术真的不错,照样升级,和是不是leader关系不大。leader的带队价值在T3.3时才显现出来。
 
总算是大致梳理了BAT的级别和薪资福利。无论你是向往BAT还是身居其中,把握每年的评级机会/跳槽机会(100offer 专业程序员拍卖平台),建立一条上升的职业曲线更为重要,因为,没有变化是一件很可怕的事情。
 
补充:
没有太大可比性。。。三巨头的薪资其实现在在整个互联网环境已经没太大竞争力,无非就是大公司光环了,对应届生可能还有点吸引力,对多年经验的、想跳槽的程序猿、来说,你要的不是钱,对不对,而是突破眼前发展的瓶颈,做一些更多的挑战。
仍然做个比较吧:
 
从整体情况看,土豪程度:阿里>腾讯>百度(不包含股票)【样本分析不够,有知友指出阿里更土豪,故做此修改;但其实我想说,真的到中高层了,企鹅公司还是给的很丰厚的,哈哈】
地域:阿里>腾讯>百度
机会与城战:均等,都是大公司,都是一个萝卜一个坑,资源有限,成长有限
技术性:百度>阿里>腾讯
 
个人评价:
1.阿里上市后,招人就很没节操了,明明只有P6的能力,偏要给到P7的title,这样招人相对容易,而且候选人相对心里满意~【注意,P7的title,但给到对应的薪资还是在P6+,因为P6+的薪资可能和P7-的薪资是有重叠的】
2.有几个阿里出来的朋友(P7、P8),提到新进来的很多P7,嘴上功夫厉害,动手能力了了(和当年冯大辉那些P7不可比拟),而那些本来P6的人,反反复复Pre不上去,所以其实内部怨气很重;内部环境恶劣,各种挤压和权斗,分派别,也影响到他们这些真的想做事做产品做技术的人,最后没办法,选择出来创业或者去到创业团队,感受阿里曾经也有的创业氛围。
3.相比之下,腾讯的人还是很稳定的,小马哥给钱还算是仗义的,尤其中高层,不太会动,但这样有一点弊端就是,上面的人不动,下面的人发展空间就有限,所以实际情况就是:铁打的营盘流水的兵
4.百度有一点大家都是知道的,就是李彦宏太小气!低Level的人不给股票或给的相当少,所以百度的人跳槽还是蛮厉害,真要说挖人,百度的人是最好挖的。
5.最后跟大家说一声,相信部分人也有了解,如果是为钱,可以去平安健康什么网络吧,人傻钱多速去的节奏,但不得不提醒,平安本身没啥互联网基因,按照他们这招人纯靠砸钱挖了很多人,包括阿里整个team挖走等等,搞了一年多也没啥令人瞩目的产品出现,这公司也就撑1~2年吧,啧啧。。。
 
结论:别去BAT啦,去创业团队吧,B或C轮公司最适合,理由:快速成长+大量期权+各种挑战,B轮/C轮公司绝大部分的命运就是被收购or上市,那么,拥有大量期权的你,怎么也能分到一笔可观的钱~~~
 
 
 

对于Java码农的学习建议

later阅读(119)评论(0)

这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是LZ你是如何学习Java的,能不能给点建议?

今天LZ是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。

在大家看之前,LZ要先声明两点。

1、由于LZ本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照搬。

2、下面对于【第一部分】的推荐内容,目的是让你尽快成为一个可以参加工作的Java开发者,更适用于处于待业状态,准备转行Java的同学。如果你是在校学生,务必要在学好基础(比如计算机系统、算法、编译原理等等)的前提下,再考虑去进行下面的学习。

第一部分:对于尚未做过Java工作的同学,包括一些在校生以及刚准备转行Java的同学。

一、Java基础

首先去找一个Java的基础教程学一下,或者看书。

学习Java基础的时候,应该尽量多动手,很多时候,你想当然的事情,等你写出来运行一下,你就会发现不是这么回事儿,不信你就试试。

学完以上内容以后,你应该对Java有一个基本的了解了,你可以用Java语言写出一些简单的程序,并且你用的是最简单的编辑器,比如记事本。

这个时候,不要急于进入下一部分,留下几天好好写一些程序,尽可能熟悉这些基础内容。

二、Web开发

等你写上几天程序以后,你往往会比较迷茫,因为你写的东西似乎看起来毫无用处,比如实现一个简单的计算器,读取一个文件等。这个时候你就应该去学着写一些让你觉得有意思的东西了,所以你应该学习更多的知识。

这些内容主要是Web开发相关的内容,包括HTML/CSS/JS(前端页面)、Servlet/JSP(J2EE)以及Mysql(数据库)相关的知识。

它们的学习顺序应该是从前到后,因此最先学习的应该是HTML/CSS/JS(前端页面),这部分内容你可以去上面的那个runoob网站上找。你可以试着自己写一些页面,当然,你可以尽你最大的努力让它变得最漂亮。这部分内容对于后端Java来说,理论上不是特别重要,但至少要达到可以自己写出一些简单页面的水平。

接下来,你需要学习的是Servlet/JSP(J2EE)部分,这部分是Java后端开发必须非常精通的部分,因此这部分是这三部分中最需要花精力的,而且这个时候,你要学会使用开发工具,而不能再使用记事本了,可以选择eclipse。

当你下载安装好eclipse以后,请视频中的教程一步一步去学习,一定要多动手。关于Servlet/Jsp部分视频的选择,业界比较认可马士兵的视频,因此推荐给大家。当然了,LZ本人并没有看过他的视频,所以不好说的太绝对,如果大家自己有更好的选择,可以坚持自己的,不要被LZ干扰。

原本LZ也是打算出教学视频的,但是由于时间问题,还是决定放弃了。但是如果你看视频的过程中遇到了问题,欢迎来LZ的交流群提问,或者去斗鱼观看LZ的直播提出你的问题,直播地址和群号都在LZ的个人博客左侧。

最后一步,你需要学会使用数据库,mysql是个不错的入门选择,而且Java领域里主流的关系型数据库就是mysql。这部分一般在你学习Servlet/Jsp的时候,就会接触到的,其中的JDBC部分就是数据库相关的部分。你不仅要学会使用JDBC操作数据库,还要学会使用数据库客户端工具,比如navicat,sqlyog,二选一即可。

三、开发框架

当你学会以上内容以后,这个时候你还不足以参加工作,你还需要继续深造。公司里为了提高开发的效率,会使用一些Java Web框架,因此你还需要学习一些开发框架。

目前比较主流的是SSM框架,即spring、springmvc、mybatis。你需要学会这三个框架的搭建,并用它们做出一个简单的增删改查的Web项目。你可以不理解那些配置都是什么含义,以及为什么要这么做,这些留着后面你去了解。但你一定要可以快速的利用它们三个搭建出一个Web框架,你可以记录下你第一次搭建的过程,相信我,你一定会用到的。

还要提一句的是,你在搭建SSM的过程中,可能会经常接触到一个叫maven的工具。这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识。在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的。

 

四、找工作

当你完成开发框架的学习以后,你就该找工作了,在校的找实习,毕业的找全职。与此同时,在找工作的同时,你不应该停下你的学习,准确的说,是你在以后都不能停下学习。

上面这些内容你只是囫囵吞枣的学会了使用,你可以逐步尝试着去了解更多的东西,网络是你最重要的老师。

第二部分:对于参加工作一年以内的同学。

恭喜你,这个时候,你已经拥有了一份Java的工作。这个阶段是你成长极快的阶段,而且你可能会经常加班。

但是加班不代表你就可以松懈了,永远记得LZ说的那句话,从你入行那一刻起,你就要不停的学习。在这一年里,你至少需要看完《Java编程思想》这本书。这本书的内容是帮助你对于Java有一个更加深入的了解,是Java基础的升级版。

这本书很厚,当初看这本书,LZ花了整整三个月。正常速度的话,应该可以在半年左右看完。LZ这里不要求过高,只要你在一年以内把这本书看完即可。当然了,LZ所说的看完,是充分吸收,而不是读一遍就完事了,因此有些内容你可能会看不止一遍。

总而言之,这个阶段的核心学习思想就是,在工作中实践,并且更加深入的了解Java基础。

第二部分:对于参加工作1年到2年的同学。

这部分时间段的同学,已经对Java有了一个更加深入的了解。但是对于面向对象的体会可能还不够深刻,编程的时候还停留在完成功能的层次,很少会去考虑设计的问题。

于是这个时候,设计模式就来了。LZ当时看的是《大话设计模式》这本书,并且写了完整版的设计模式博客。因此,LZ要求大家,最多在你工作一年的时候,必须开始写博客,而设计模式就是你博客的开端。

请记住,LZ所提的基本都是最低要求,因此不要有任何松懈的心理,否则五年后,你不要去羡慕别人高于你的工资,也不要去羡慕别人进入了某公司。

这一年,你必须对于设计模式了如指掌,《大话设计模式》可以作为你的开端。本站就有很多文章可以看。

此外,设计模式并不是你这一年唯一的任务,你还需要看一些关于代码编写优化的书。比如《重构 改善既有代码的设计》,《effective java》。

总而言之,这个阶段,你的核心任务就是提高你的代码能力,要能写出一手优雅的代码。

第三部分:对于参加工作2年到3年的同学

有的同学在这个时候觉得自己已经很牛逼了,于是忍不住开始慢慢松懈。请记住,你还嫩的多。

这个阶段,有一本书是你必须看的,它叫做《深入理解Java虚拟机》。这本书绝对是Java开发者最重要的书,没有之一。在LZ眼里,这本书的重要性还要高于《Java编程思想》。

这本书的内容是帮助你全面的了解Java虚拟机,在这个阶段,你一定已经知道Java是运行在JVM之上的。所以,对于JVM,你没有任何理由不了解它。

另外,在过去2年的工作当中,你肯定或多或少接触过并发。这个时候,你应该去更加深入的了解并发相关的知识,而这部分内容,LZ比较推荐《Java并发编程实战》这本书。只要你把这本书啃下来了,并发的部分基本已经了解了十之六七。

与此同时,这个阶段你要做的事情还远不止如此。这个时候,你应该对于你所使用的框架应该有了更深入的了解,对于Java的类库也有了更深入的了解。因此,你需要去看一些JDK中的类的源码,也包括你所使用的框架的源码。

这些源码能看懂的前提是,你必须对设计模式非常了解。否则的话,你看源码的过程中,永远会有这样那样的疑问,这段代码为什么要这么写?为什么要定义这个接口,它看起来好像很多余?

由此也可以看出,这些学习的过程是环环相扣的,如果你任何一个阶段拉下来了,那么你就真的跟不上了,或者说是一步慢步步慢。而且LZ很负责的告诉你,LZ在这个阶段的时候,所学习的东西远多于这里所罗列出来的。因此千万不要觉得你已经学的很多了,LZ所说的这些都只是最低要求,不光是LZ,很多人在这个时间段所学习的内容都远超本文的范围。

如果你不能跟上节奏的话,若干年后,如果不是程序猿市场还不错的话,你很可能不仅仅是工资比别人低,公司没别人好,而是根本就找不到工作。

总而言之,这个阶段,你需要做的是深入了解Java底层和Java类库(比如并发那本书就是Java并发包java.concurrent的内容),也就是JVM和JDK的相关内容。而且还要更深入的去了解你所使用的框架,方式比较推荐看源码或者看官方文档。

另外,还有一种学习的方式,在2年这个阶段,也应该启用了,那就是造轮子。

不要听信那套“不要重复造轮子”的论调,那是公司为了节省时间成本编造出来的。重复造轮子或许对别人没有价值,因为你造的轮子可能早就有了,而且一般情况下你造出来的轮子还没有现存的好。但是对别人没有价值,不代表对你自己没有价值。

一个造轮子的过程,是一个从无到有的过程。这个过程可以对你进行系统的锻炼,它不仅考察你的编码能力,还考察你的框架设计能力,你需要让你的轮子拥有足够好的扩展性、健壮性。

而且在造轮子的过程中,你会遇到各种各样的难题,这些难题往往又是你学习的契机。当你把轮子造好的时候,你一定会发现,其实你自己收获了很多。

所以,这个阶段,除了上面提到的了解JVM、JDK和框架源码以外,也请你根据别人优秀的源码,去造一个任何你能够想象出来的轮子。

第四部分:参加工作3年到4年的同学

这个阶段的同学,提升已经是很难了,而且这个阶段的学习往往会比较多样化。

因为在前3年的过程中,你肯定或多或少接触过一些其它的技术,比如大数据、分布式缓存、分布式消息服务、分布式计算、软负载均衡等等。这些技术,你能精通任何一项,都将是你未来面试时巨大的优势,因此如果你对某一项技术感兴趣的话,这个时候可以深入去研究一下。这项技术不一定是你工作所用到的,但一定是相关的。

而且在研究一门新技术时,切忌朝三暮四。有的同学今天去整整大数据,搞搞Hadoop、hbase一类的东西。过不了一段时间,就觉得没意思,又去研究分布式缓存,比如redis。然后又过不了一段时间,又去研究分布式计算,比如整整Mapreduce或者storm。

结果到最后,搞得自己好像什么都会一样,在简历上大言不惭的写上大数据、分布式缓存、分布式计算都了解,其实任何一个都只是浮于表面。到时候面试官随便一问,就把你给识破了。

一定要记住,作为一个程序猿,平日里所接触的技术可能会很多,但是想要让一门技术成为你的优势,那么一定是你对这门技术的了解强过绝大多数人才行。

因此在这个阶段,你就不能再简单的去学习前3年的内容了,虽然前面的学习如果还不够深入的话依旧要继续,但这个时候你应该更多的考虑建立你的优势,也可以称为差异性。

差异性相信不难理解,就是让你自己变得与众不同。你前面三年的学习足够你成为一名基本合格的Java开发者,但你离成为一名优秀的Java开发者还有很大的距离。

所谓优秀,即能别人所不能。而你前三年所学习的内容,是很多做过几年的Java开发都能够掌握的。那么为了让自己有差异性,你就需要另辟蹊径,找一个方向深入研究下去,以期在将来,你能够成为这个领域的专家,比如分布式计算领域的专家,大数据领域的专家,并发领域的专家等等。

此外,你除了建立你的差异性之外,还要去弥补你基础上的不足,直到现在,LZ都没有提及基础知识。原因是基础是很枯燥无味的,学的太早不仅容易懵逼,而且懵逼的同时还容易产生心理阴影,以至于以后再不想去研究这些基础。但基础又是你深入研究一些领域时所必须掌握的,比如你去研究分布式计算,你不懂算法你玩个毛毛?比如你去做分布式缓存,你对计算机系统的内存不了解,你如何去做缓存?

如果你的基础本来就非常强,那么恭喜你,相信你在之前的工作中已经充分体会到了这些基础对你的帮助。但LZ相信大部分人的基础都很薄弱,哪怕是科班毕业的人,很多人也不敢说自己当初的基础学的多么强大,比如算法、计算机系统原理、编译原理这些。

但是每个人时间都是有限的,而且这些基础的书籍每一本读下来,没个一年半载的,还真拿不下来,因此还是要有所抉择的。虽然艺多不压身,但问题是艺多是有代价的,是需要你付出时间和精力的,而LZ个人更赞成在同等代价的情况下获取最大的收获。

首先,LZ比较推崇的基础书籍有三本,分别是《深入理解计算机系统》,《tcp/ip详解 卷一、二、三》,《数据结构与算法》。其中TCP/IP有三本书,但我们这里把这三本看成是一本大书。

这三本分别适合三种人,《深入理解计算机系统》比较适合一直从事Java Web开发和APP后端开发工作的人群。《tcp/ip详解 卷一、二、三》比较适合做网络编程的人群,比如你使用netty去开发的话,那么就要对TCP/IP有更深入的了解。而《数据结构与算法》这本书,则比较适合做计算研究工作的人,比如刚才提到的分布式计算。

另外,LZ要强调的是,这里所说的适合,并不是其它两本对你就没有用。比如你做Java Web和APP后端开发,《tcp/ip详解 卷一、二、三》这本书对你的作用也是很大的。这里只是分出个主次关系而已,你要是时间足够的话,能把三本都精读那当然最好不过了。但如果时间有限的话,那么就先挑对你帮助最大的书去读。

理论上来讲,这一年你能把这三本其中一本精读下来,就已经非常厉害了。有了基础,有了前面的工作经验,你就可以去开拓属于你的领域了。

在这一年里,一定要规划好自己的领域,建立好自己的优势,制造出差异性。如果你对自己的领域不够清晰的话,随着你工作的时间日益增多,你接触的技术会越来越多,这个时候,你很容易被淹死在技术的海洋里,看似接触的技术越来越多,会用的也越来越多,但你毫无优势。

有的同学可能会问,“LZ,我也不知道我的领域是什么啊?怎么办呢?”

对于这种人,LZ只想说,“卧槽,这还问我?要不干脆我替你学习得了,好不好?”

第五部分:参加工作4年到5年的同学

经过前面一年的历练,相信你在自己所钻研的领域已经有了自己一定的见解,这个时候,技术上你应该已经遇到瓶颈了。

这个时候不要着急提高自己的技术,已经是时候提高你的影响力了,你可以尝试去一些知名的公司去提高你的背景,你可以发表一些文章去影响更多的人。当然,你也可以去Github创建一个属于你的开源项目,去打造自己的产品。这次的开源项目不同于之前的造轮子,你这个时候是真的要去尽量尝试造出来真正对别人有价值的轮子。

技术学到这个阶段,很容易遇到瓶颈,而且往往达到一定程度后,你再深入下去的收效就真的微乎其微了,除非你是专门搞学术研究的。然而很可惜,大部分程序猿做不到这一步,那是科学家做的事情。

这个时候提高影响力不仅仅是因为技术上容易遇到瓶颈,更多的是影响力可以给你创造更多的机会。程序猿在某种程度上和明星很像,一个好的电视剧和电影就可以成就一批明星,程序猿有的时候也是,一个好的项目就可以成就一群程序猿。

比如国内几个脍炙人口的项目,像淘宝、支付宝、QQ、百度、微信等等。这每一个项目,都成就了一批程序猿。LZ敢说,这里面任何一个项目,如果你是它的核心开发,光是这样一个Title,就已经是你非常大的优势。更何况还不止如此,Title说到底也是个名头,更重要的是,这种项目在做的时候,对你的历练一定也是非常给力的。

而你如果想要参与这样的项目,除了靠运气之外,影响力也是很重要的一个手段。比如你在分布式计算领域有一定的影响力,那么如果有什么好的关于分布式计算的项目,对方就很可能会邀请你。就算人家不邀请你,你自己主动去面试的时候,对方如果知道你在这个领域的影响力,也肯定会起到很大的作用,而这个作用,甚至可能会超过你现在的技术能力。

所以,在这个阶段,你最大的任务是提高自己的影响力,为自己未来的十年工作生涯那一天做准备。如果你能够靠你的影响力和以前积累的技术,参与到一个伟大的项目当中,那么你后面的五年也就有着落了。

当然了,LZ现在满打满算,做程序猿也就4年半不到,因此关于4年到5年这一部分,LZ的见解不一定是对的,就算是对的,也不一定是适合任何人的。所以,希望大家自己有的判断力,去决定到底该如何度过这一年。

结语

本文到此就基本结束了,整篇文章很长,但其实主要就说了两部分内容,一个是社招面试的准备,一个是Java生涯的学习。

关于这两部分,LZ已经给出了自己的见解,但是还是那句话,每个人吸收知识的时候,都要有抽取精华,去除糟粕的能力。LZ所说的,可能有些是对的,有些是错的,有些是适合你的,有些是不太适合你的,你要自己能够判断。

其实你在生活和工作当中也是一样的,你身边的人形形色色,有的人你喜欢,有的人你很讨厌。但其实你喜欢的人也有缺点,你讨厌的人也有优点。你要学会从你讨厌的人身上学会他的优点,千万不要一棒子打死,这只会让你失去很多学习成长的机会。

好了,说了这么多了,就到此为止吧,希望本文可以帮助到作为程序猿或即将成为程序猿的你。

阿里Java面试总结

later阅读(450)评论(0)

引言

其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来。LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容基本上忘得一干二净,所以写这篇文章其实是很有难度的。

但是,最近问LZ的人实在是太多了,为了避免重复回答,给自己省点力气,干脆就在这里统一回复了。

其实之前LZ写过一篇文章,但是那篇文章更多的是在讨论“面试前该不该刷题”这个话题,而这篇文章将会更加聚焦在面试前如何准备,以及工作当中如何学习这个话题上,而且会尽量写出一些干货。

第一个问题:阿里面试都问什么?

这个是让LZ最头疼的一个问题,也是群里的猿友们问的最多的一个问题。

说实话,LZ只能隐约想起并发、JVM、分布式、TCP/IP协议这些个关键字,具体的问题真的是几乎都没记住。而且就算LZ记住了,也告诉你了,你也背会了,但LZ觉得,在面试中,你被问到一模一样问题的可能性依然很小。

甚至,就算你运气好被问到了,你也照着背下来了,也不一定就能对你的面试起到正面的作用,因为面试官万一多问一句,你可能就露馅了,那还不如干脆点说不会更好。

LZ参加的是阿里的社招面试,而社招不同于校招,问题的范围其实是很随机的。因为能参加一些比较知名的互联网公司社招的人,70%以上都会有个3-5年的经验。这倒不是说一两年经验的同学没有机会进这些公司,而是因为这种公司,大部分情况下只招一些比较资深的开发和应届生,而不招那些处于中间阶段的人。而1-2年经验的同学,往往就刚好处于这个尴尬的阶段。

对于能有3-5年经验的这部分人中,每个人的经历又都不同,所擅长的点也不一样,因此这就会导致每个人的问题和范围都不太一样。

很少说有哪个知名的互联网公司,比如BAT、京东、360、搜狐、网易等这些公司,其社招面试还有固定的问题和模式,让你可以像应届生面试一样,在面试前靠临时抱佛脚度过这一关。

大部分公司在社招的时候,不光是阿里,其它公司也都一样(因为LZ在一年多前也参加过很多其它知名互联网公司的面试,详情见《记录2015年年初跳槽的经历!》),基本上都分为两个阶段的提问。

第一个阶段是主语言本身以及它的高级特性,第二个阶段是讲述自己的项目,并在中间穿插着问题。

所以,LZ不妨就这两个阶段,谈谈社招面试的准备,而不是去把阿里面试的过程背一遍。说实话,LZ也确实记不住,所以不要再问LZ阿里面试都会问哪些问题了,你看看上面那个连接里的文章,也会发现,LZ里面也基本上没有写具体的问题,原因是一样的,真的记不住啊。(就是因为记忆力的问题,导致LZ从小偏科,文科成绩一直堪忧,-_-)

社招面试如何准备

LZ会分为四个部分来谈论这个问题,由于LZ本身是Java出身,因此关于主语言的问题,都是与Java相关,其它语言的同学可以选择性忽略。此外,面试的时候一般面试官的问题都是环环相扣,逐渐深入的,这点在下面大家可以更明显的感受出来。

1、主语言本身以及它的高级特性。

主语言当然就是你平日里拿来赚钱的家伙。不要告诉LZ你没有主语言,你会N多种语言,或者是你精通N多种语言,你要非这么说的话,你可以来杭州试试,LZ保证不打死你,最多打残。

LZ的主语言很显然是Java,那么对于Java来说,它的语言本身以及它的高级特性,都有哪些比较容易在面试中问到呢?

一般情况下,主要有以下知识点很容易被问到。(PS:以下所列举的,都是一些Java相对而言比较高级一点的知识点,因为这里谈的是社招,而不是校招)

1)Java的数据结构相关的类实现原理,比如LinkedList,ArrayList,HashMap,TreeMap这一类的。以下简单模拟一个数据结构的连环炮。

比如,面试官先问你HashMap是不是有序的?

你肯定回答说,不是有序的。那面试官就会继续问你,有没有有顺序的Map实现类?

你如果这个时候说不知道的话,那这个问题就到此结束了。如果你说有TreeMap和LinkedHashMap。

那么面试官接下来就可能会问你,TreeMap和LinkedHashMap是如何保证它的顺序的?

如果你回答不上来,那么到此为止。如果你依然回答上来了,那么面试官还会继续问你,你觉得它们两个哪个的有序实现比较好?

如果你依然可以回答的话,那么面试官会继续问你,你觉得还有没有比它更好或者更高效的实现方式?

如果你还能说出来的话,那么就你所说的实现方式肯定依然可以问你很多问题。

以上就是一个面试官一步一步提问的例子。所以,如果你了解的不多,千万不要敷衍,因为可能下一个问题你就暴露了,还不如直接说不会,把这个问题结束掉,赶紧切换到你熟悉的领域。

2)Java并发包当中的类,它们都有哪些作用,以及它们的实现原理,这些类就是java.concurrent包下面的。与上面一样,咱们也简单的模拟一个并发包的连环炮。

比如面试官可能会先问你,如果想实现所有的线程一起等待某个事件的发生,当某个事件发生时,所有线程一起开始往下执行的话,有什么好的办法吗?

这个时候你可能会说可以用栅栏(Java的并发包中的CyclicBarrier),那么面试官就会继续问你,你知道它的实现原理吗?

如果你继续回答的话,面试官可能会继续问你,你还知道其它的实现方式吗?

如果你还能说出很多种实现方式的话,那么继续问你,你觉得这些方式里哪个方式更好?

如果你说出来某一个方式比较好的话,面试官依然可以继续问你,那如果让你来写的话,你觉得还有比它更好的实现方式吗?

如果你这个时候依然可以说出来你自己更好的实现方式,那么面试官肯定还会揪着这个继续问你。

为什么说面试的时候要引导面试官,原因就在这了。因为面试官的提问很多时候都是有迹可循的,你如果抓住了他的轨迹,能够猜到他下面很可能会问什么,那你在回答的时候就可以往你想要谈的方向去说。这样面试时就会显得更加从容,更加的游刃有余。

3)IO包和NIO包中的内容。这部分里面NIO会是重点,IO包大部分都会比较熟悉,因此可能会直接略过,直接问你NIO的内容。

IO包和NIO包的内容相对来说不是很多,首先NIO模型要熟悉,特别是其中的selector一定要非常清楚它的职责和实现原理。其实NIO的核心是IO线程池,一定要记住这个关键点。有的时候,面试官可能也会问你IO包的设计模式(装饰器模式),为什么要这样设计?

有的面试官还会问你有没有更好的设计,这个时候如果你不知道请果断说自己现在的水平有限,想不出来更好的设计,千万不要信口开河,随意YY。

4)Java的虚拟机的内容。这部分主要包括三部分,GC、类加载机制,以及内存。

一个GC部分简单的连环炮。

面试官可以先问你什么时候一个对象会被GC?

接着继续问你为什么要在这种时候对象才会被GC?

接着继续问你GC策略都有哪些分类?

你如果说出来了,继续问你这些策略分别都有什么优劣势?都适用于什么场景?

你继续说出来了以后,给你举个实际的场景,让你选择一个GC策略?

你如果选出来了,继续问你,为什么要选择这个策略?

下面是关于类加载机制的简单连环炮。

首先肯定是先问你Java的类加载器都有哪些?

回答了这些以后,可能会问你每个类加载器都加载哪些类?

说完以后,可能会问你这些类加载之间的父子关系是怎样的?

你在回答的时候可能会提到双亲委派模型,那么可以继续问你什么是双亲委派模型?

你解释完了以后,可能会继续问你,为什么Java的类加载器要使用双亲委派模型?

你回答完以后,可能会继续问你如何自定义自己的类加载器,自己的类加载器和Java自带的类加载器关系如何处理?

再来一个关于内存的连环炮。

首先肯定就是问你内存分为哪几部分,这些部分分别都存储哪些数据?

然后继续问你一个对象从创建到销毁都是怎么在这些部分里存活和转移的?

接着可能会问你,内存的哪些部分会参与GC的回收?

完事以后,可能还会问你Java的内存模型是怎么设计的?

你回答了以后,还会继续问你为什么要这么设计?

问完以后,还可能会让你结合内存模型的设计谈谈Volatile关键字的作用?

你在谈的时候,肯定会提到可见性,那么接着可见性这三个字,还可以继续问你并发的内容。

基本上Java语言本身以及语言稍微高级点的内容就是以上部分,如果你能把以上四部分了解的非常透彻,那基本上Java这部分就没啥问题了,因为光以上的内容就够你跟面试官聊很久了。你聊这些聊得久了,自然问你其它问题的时间就会短点。

你从LZ写这些问题的过程也应该能感受出来,很多时候,面试官都是顺着一条线一路问下去的,如果你觉得这条线你不熟悉的话,就要及时拐弯,引导面试官去问其它方面的问题。千万不要一直往下深入,直到自己跳不出来为止,那就尴了个尬了。

2、讲述自己的项目,并在中间穿插着问题

这一部分是面试过程中必问,也是聊得最久的一个阶段。除非你前面的语言部分非常扎实,扎实到面试官问了一两个小时,依旧没有探出你对语言本身的了解到底有多深。否则的话,你一定逃不过自己的项目这一关,而且一般情况下聊得时间不会太短。

这一部分内容,一般的模式就是你自己去讲你做过的项目,然后面试官会冷不丁的让你去解释其中某一部分,比如让你解释当时为什么要这么做,或者问你现在觉得有没有更好的办法。而这些穿插的问题,大部分与你的项目所用到的技术有关。而你需要做的,就是充分、再充分的去总结自己做过的项目(尤其是最近的一两个项目),挖掘出一个甚至N个亮点,以备于到时候可以让面试官产生眼前一亮的感觉。如果你能达到这种效果的话,基本上离你成功就不远了。

这部分内容由于和每个人自己的经历息息相关,因此这里也没法列举可能问到的问题。这篇文章《程序员面经:面试前到底该不该刷题以及面试前该如何准备》是LZ之前写的,里面大概讨论了下如何在面试前总结,有兴趣的可以去了解一下。

3、额外的加分项

上面两个阶段基本上是必问的,还有一些加分项。这些加分项中,有些内容面试官也会问你(比如TCP/IP协议、算法),但更多的是会先问你了解不了解,你了解的话再继续聊,不了解的话就直接略过了,不至于因为这种问题而直接把你打入地狱。

下面LZ列举一下这些加分项,如果可以的话,这些加分项还是要争取一下的。

1、计算机系统原理。

2、网络通信协议(TCP/IP,HTTP等)。

3、数据结构与算法。

4、著名开源项目的源码。

5、你自己有很棒的开源项目。

6、你的个人博客。

7、待评论区补充。

这几项当中,对于前1-3项,如果你之前就比较了解,只是由于时间问题忘记了的话,还是可以临时抱佛脚一下的。至于后面4-6项,就需要你日常的积累了,不是一时半会儿能做到的。如果你平日里没有积累,那么后面这三个加分项只能抛弃了。

4、与你职位相关的内容

其实这最后一项是对前面三项的补充,你应该尽量去主攻和你面试的职位相关的内容。比如你面试一个实时计算的职位,那么你的算法最好要厉害,对于著名的实时计算开源项目要熟悉,最好阅读过源码,而且还要对分布式系统有一定的见解。

因此,这个第4部分没有具体的内容,只是提醒你,如果你很明确自己的面试职位,最好在面试前准备的时候,尽量朝职位的需求方向靠拢,这样成功的可能性更大。

欢聚时代(yy)面试回顾

later阅读(111)评论(0)

####1. 准备
欢聚时代是我开始认真面试的第一家公司。我让我一个朋友内推的。投递的是me直播Java开发工程师的职位。反馈也比较快,投了之后两天就有结果了。然后就约了一个时间去面试。yy搬到了番禺广场,不得不说,真的有点远并且有点偏哎。好处就是周围租房的选择比较多。yy在番禺广场买下来了一整栋楼,大概40多层,一个很大的www.yy.com logo,还是很有气势的。

我的面试安排在下午三点开始,去了之后先要在前台登记,让我拿出面试邀请邮件,可是发我谷歌邮箱了,手机上没翻墙打不开。。尴尬,最后打电话确认后才让我上去。我的面试在33楼进行,等了大概20分钟,终于等来了第一位面试官。

####2. 一面
一面的面试官是个中年男子,看上去也很沉稳干练的那种。一开始让我介绍自己做过的项目,没有自我介绍环节了。我就讲了我做过的一个项目。我说的是我们做的一个公众号估值系统的项目,这个项目主要是如何去获取一个公众号所有的文章数,每篇文章的阅读数和点赞数。我们是通过fiddler进行抓包分析,伪造http请求的方式来实现。这个做起来挺有难度的。key失效一直是一个很头疼的大问题。我讲了大概十五分钟左右,一些细节说的很详细,面试官也很认真的听着。有时候可能我说的太细了,比如我说请求的时候,必须要伪造http的header,里面需要加一些参数,比如hostrefereruser-agentorigin这些,我会解析一下这些头具体什么意思,他就频繁点头,嗯嗯嗯,意思我知道,继续往下说。讲完之后,他就问我那这个高并发体现在哪里,我就说客户端生成key的时候,相当于一个生产者消费者模式,如果使用用户多的时候,客户端的压力是比较大的,客户端会有一个无界队列保存请求。有个排队的过程。。blabala。。说了好久,项目大概聊了四十分钟。我觉得都答的挺好的,没有什么失误。面试官也比较满意,就聊了一些其他方面的。

他接下来我问我动态代理是什么,了解吗?我就说要代理的这个类是运行时动态生成的,被代理的类必须要实现一个接口,有这么几个角色,被代理的类,代理类,代理接口。代理的实现由jdk动态代理和cglib代理两种。cglib代理不需要有代理接口,直接通过修改字节码的方式,jdk动态代理是通过反射特性来进行的。。那么反射就是jdk的特性,它有这么几个关键的类,fieldconstructor,Method,底层又是。。。我还想说下去,面试官说好了好了,明白了,这个问题到此为止。感觉他就是只是大概了解一下你懂不懂,不想深入探讨。好吧,那这个问题就过。

后来就问我们为什么要用vertx,我就说了一下vertx的特性,高性能,高并发,异步无锁编程等等。他也没问啥很难的问题。

后来问我数据库的知识,我就扯到了主从复制技术的原理,讲了一会儿。面试官也比较满意,第一面就算过了

面试官最后问我有没有要问他的,我就问了这个职位相关的情况。还问了他们直播相关的情况,比如第一次进入直播页,如何快速定位到当前直播流,我参加过infoq举办的全球架构师峰会,在里面打酱油听过一些,百度开放云也讲了他们直播的技术,当是他们讲的是一个追赶播放的过程,说要申请技术专利,我就给面试官讲了,他就给我分析了一下这个他们这么做的。balabala,就说完了。他说欢聚云也在做直播这块,但是还没有开放成服务等等。第一面就结束了。

####3. 二面
二面面试官一进来就说,你们一面的时候聊了什么,我说主要聊了项目吧,他说那好,我们继续聊项目吧。。。我晕,又让我重复同样的话,这时候心累啊,不想再说的和一面的时候一样细。我就尽量精简的讲了一下。讲完就问了几个问题,你们这个客户端是干嘛用的,我一听,他还是没用听明白,生成key的哎,我又细细讲了一下,他懂了。又问客户端鼠标自动点击是如何做的,我说开始用了java robot类,后来换成按键精灵了,他问两者有什么区别,为什么要换,这个太好答了。我就说了一些原因。后来他质疑,你们这种不能实现完全的自动化哦,要测一个公众号,先要关注这个号,再去抓取文章,效率很低,谈不上高并发。。我惊出了一身汗。。他怎么知道必须要关注才可以。。我们也是摸索了好久才发现这个问题。。。不得不说,这个面试官还是很牛的。我就重重的说了声..,是的,必须要先关注,完全正确。但是我们可以一次关注几千个公众号,把常见的公众号都关注了,微信的上限是2000个,那我们就关注2000个,这时候分析的话,并发量还是比较高的。我也承认了,这个问题也是我们这个产品没有推向外面的主要原因,做不到完全的自动化。只是给我们内部投资部用。项目大概聊完了,很多细节都忘了,面试已经过了好几天了。

接下来就问我性能调优的问题,说线上系统由问题了,你怎么快速查找问题出在那里。这种问题我也经验不多,实际去排查的次数很少。都是看书看博客学习别人的做法。对于此类问题,你说出个top命令,面试官会满意一大半,再说说jmap,jstack,jconsole,jstat的用法和区别,面试官多半会满意的,你说出从定位问题到解决问题的整个流程,一般来说还是可以的了。这里我遇到了两个坑,面试官对我的回答可能还想深入了解一下,问我top会打印出四种不同的线程情况,你知道是哪四种吗,我。。。不知道。继续问,top后面加个参数,logxxx是什么意思,我也不知道。。。问这么细,其实那个参数是啥我也没听清,这两个问题到现在我还没去了解。写完这篇博客,我就去好好研究一下top命令。这两个问题就跪了。我嘴贱,多说了jconsole,坑,哦,你们还用jconsole,你是直接通过jconsole能连远程服务器吗,这个我知道不能,要通过socket连,那你知道怎么配的吗。。什么原理。。囧,我没试过。答不上来了。典型的不作死就不会死。自己给自己挖坑跳,也是一个教训。

后来问我vertx,我说一些。但是我说了这么一句:对于不耗时的请求,event loop会自己转发到对应的handler上,对于耗时的请求,会转发到event bus上由他来转发处理。他就抓住问,他如何判断这个请求是耗时还是不耗时的呢。这个问题我也不太能说明白,我就说比如文件上传咯,数据库操作(漏洞很多),最后感觉答得很一般。

后来问vertx如何做到支持多语言的呢,我大概说底层都是netty,上层封装了一些不同语言的api,他继续往深挖,扛不住了。。

再就是问多线程,实现方式由几种,synchronize和lock有什么区别,synchronize底层怎么实现的,他就是在对象监视器里保存对象锁的(markword)。这个有准备《Java并发编程的艺术》这本书我都看完了,答得不是问题。说了reenterLock,主要区别就是condition实现的多路选择通知机制。我把volatile说成原子变量了。。口误,后面解释了一下,原子变量是atomic包下的那些。他追问实现原理,我就说了cas,一个新值和旧值的比较过程。旧值没变的时候就更新,变了的话继续循环直到成功。这里说的不严谨,应该是如果变了的话,旧值就变成最新的这个,而不是旧值,被他追问了,幸好及时纠正了。然后我就自己展开话题说了cas的缺点,aba问题,循环时间长开销大,只能保证一个变量的线程安全。。说完他没有反应。。大概是他也没思考过这些问题,没让我详细解释,这个问题就过了。我还想深入展开的呢。。过了就过了。

接下来就是hashmap的实现,看了代码,详细的解释了一下,又问了concurrentHashMap,准备的比较多,没啥问题。

还问了大概用到的技术,具体细节忘了。

####4. 三面
三面技术官应该是一个比较资深的类似架构师的角色吧。刚上来比较客气,聊了下家常,问我为什么离职,我就说原来公司业务出了问题,个人发展受限,想寻求更好的平台,他就说是啊,现在创业太难了,资本的钱都烧完了,创业公司的日子不好过了。大概聊了一会这些话题。

三面主要了解一下技术背景。我们用groovy多,spring, tomcat,java用的比较少,他也了解到了,也许有些担心我java用的太少了。
问问groovy的特性,java与groovy的区别。为什么要用。

让说说自己的优点,优秀员工为什么选择你(前一家公司的时候,被评为优秀员工,简历里写上去了,这也没啥用),我就说了自己的一些优势。没啥亮点。。

其它的实在想不起来了。感觉聊得一般般吧,总觉得差点什么。。好了就这样吧。这种感觉很奇妙。

####5. HR沟通
第二天hr打电话来了,说你通过面试了。我们来聊一些基本问题。无非就是说些为什么离职,自己的优势。期望薪资等等。最后来了一句比较郁闷的。。。她说我们这个是给我们的比邻的子公司招的研发,不是欢聚时代的。。尼玛,逗我吗,心中那个不爽。。我朋友帮我内推的时候明明是me直播,不知道怎么搞的。她问我接不接受,我说我需要考虑一下。。那就后面再联系吧。。就先挂了电话。大概就是这样吧。

吐槽,这样做事的方式让人很不能理解,起码开始就应该说清楚。不要浪费双方时间。哎,算了吧。我要去北京了。

流水账终于完了,文笔不好,写的随意,将就着看吧。哈哈