脚本之家(jb51.cc)Java面试题栏目主要收集Java工程师面试题,Java人员面试专属面试题。
写在前面技术源于分享,所以今天抽空把自己之前用java做过的小游戏整理贴出来给大家参考学习。java确实不适合写桌面应用,这里只是通过这个游戏让大家理解oop面向对象编程的过程,纯属娱乐。代码写的很简单,也很容易理解,并且注释写的很清楚了,还有问题,自己私下去补课学习。完整代码敌飞机12345678910111213141516171819202122232425262728293031323334353637import java.util.Random;   敌飞机: 是飞行物,也是敌人 public class Airplane extends FlyingObject implements Enemy {    private int speed = 3;  //移动步骤     /** 初始化数据 */    public Airplane(){        this.image = ShootGame.airplane;        width = image.getWidth();        height = image.getHeight();        y = -height;                 Random rand = new Random();        x = rand.nextInt(ShootGame.WIDTH - width);    }     /** 获取分数 */    @Override    public int getScore() {         return 5;    }     /** //越界处理 */    @Override    public     boolean outOfBounds() {          return y>ShootGame.HEIGHT;    }     /** 移动 */    @Override    public void step() {          y += speed;    } }分数奖励123456789/** * 奖励 */ public interface Award {     int DOUBLE_FIRE = 0;  //双倍火力     int LIFE = 1;   //1条命     /** 获得奖励类型(上面的0或1) */     int getType(); }蜜蜂12345678910111213141516171819202122232425262728293031323334353637383940414243import java.util.Random;  /** 蜜蜂 */ public class Bee extends FlyingObject implements Award{     private int xSpeed = 1;   //x坐标移动速度     private int ySpeed = 2;   //y坐标移动速度     private int awardType;    //奖励类型      /** 初始化数据 */     public Bee(){         this.image = ShootGame.bee;         width = image.getWidth();         height = image.getHeight();         y = -height;         Random rand = new Random();         x = rand.nextInt(ShootGame.WIDTH - width);         awardType = rand.nextInt(2);   //初始化时给奖励     }      /** 获得奖励类型 */     public int getType(){         return awardType;     }      /** 越界处理 */     @Override     public boolean outOfBounds() {         return y>ShootGame.HEIGHT;     }      /** 移动,可斜着飞 */     @Override     public void step() {               x += xSpeed;         y += ySpeed;         if(x > ShootGame.WIDTH-width){               xSpeed = -1;         }         if(x < 0){             xSpeed = 1;         }     } }子弹类:是飞行物体1234567891011121314151617181920212223242526/** * 子弹类:是飞行物 */ public class Bullet extends FlyingObject {     private int speed = 3;  //移动的速度      /** 初始化数据 */     public Bullet(int x,int y){         this.x = x;         this.y = y;         this.image = ShootGame.bullet;     }      /** 移动 */     @Override     public void step(){            y-=speed;     }      /** 越界处理 */     @Override     public boolean outOfBounds() {         return y<-height;     }  }敌人的分数1234567/** * 敌人,可以有分数 */ public interface Enemy {     /** 敌人的分数  */     int getScore(); }飞行物(敌机,蜜蜂,子弹,英雄机)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475import java.awt.image.BufferedImage;  /** * 飞行物(敌机,蜜蜂,子弹,英雄机) */ public abstract class FlyingObject {     protected int x;    //x坐标     protected int y;    //y坐标     protected int width;    //宽     protected int height;   //高     protected BufferedImage image;   //图片      public int getX() {         return x;     }      public void setX(int x) {         this.x = x;     }      public int getY() {         return y;     }      public void setY(int y) {         this.y = y;     }      public int getWidth() {         return width;     }      public void setWidth(int width) {         this.width = width;     }      public int getHeight() {         return height;     }      public void setHeight(int height) {         this.height = height;     }      public BufferedImage getImage() {         return image;     }      public void setImage(BufferedImage image) {         this.image = image;     }      /**     * 检查是否出界     * @return true 出界与否     */     public abstract boolean outOfBounds();      /**     * 飞行物移动一步     */     public abstract void step();      /**     * 检查当前飞行物体是否被子弹(x,y)击(shoot)中     * @param Bullet 子弹对象     * @return true表示被击中了     */     public boolean shootBy(Bullet bullet){         int x = bullet.x;  //子弹横坐标         int y = bullet.y;  //子弹纵坐标         return this.x<x && x<this.x+width && this.y<y && y<this.y+height;     }  }英雄机123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106import java.awt.image.BufferedImage;  /** * 英雄机:是飞行物 */ public class Hero extends FlyingObject{      private BufferedImage[] images = {};  //英雄机图片     private int index = 0;                //英雄机图片切换索引      private int doubleFire;   //双倍火力     private int life;   //命      /** 初始化数据 */     public Hero(){         life = 3;   //初始3条命         doubleFire = 0;   //初始火力为0         images = new BufferedImage[]{ShootGame.hero0, ShootGame.hero1}; //英雄机图片数组         image = ShootGame.hero0;   //初始为hero0图片         width = image.getWidth();         height = image.getHeight();         x = 150;         y = 400;     }      /** 获取双倍火力 */     public int isDoubleFire() {         return doubleFire;     }      /** 设置双倍火力 */     public void setDoubleFi
一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选。1、字符串不变性下面这张图展示了这段代码做了什么String s = "abcd";s = s.concat("ef");2、equals()方法、hashCode()方法的区别HashCode被设计用来提高性能。equals()方法与hashCode()方法的区别在于:如果两个对象相等(equal),那么他们一定有相同的哈希值。如果两个对象的哈希值相同,但他们未必相等(equal)。3、Java异常类的层次结构图中红色部分为受检查异常。它们必须被捕获,或者在函数中声明为抛出该异常。4、集合类的层次结构注意Collections和Collection的区别。(Collections包含有各种有关集合操作的静态多态方法)5、Java同步Java同步机制可通过类比建筑物来阐明。6、别名别名意味着有多个变量指向同一可被更新的内存块,这些别名分别是不同的对象类型。7、堆和栈图解表明了方法和对象在运行时内存中的位置。8、Java虚拟机运行时数据区域图解展示了整个虚拟机运行时数据区域的情况。我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
面试的时候经常会遇见诸如:“java中的HashMap是怎么工作的”,“HashMap的get和put内部的工作原理”这样的问题。本文将用一个简单的例子来解释下HashMap内部的工作原理。首先我们从一个例子开始,而不仅仅是从理论上,这样,有助于更好地理解,然后,我们来看下get和put到底是怎样工作的。我们来看个非常简单的例子。有一个”国家”(Country)类,我们将要用Country对象作为key,它的首都的名字(String类型)作为value。下面的例子有助于我们理解key-value对在HashMap中是如何存储的。1. Country.javapackage org.arpit.javapostsforlearning;public class Country {String name;long population;public Country(String name, long population) {super();this.name = name;this.population = population;}public String getName() {return name;}public void setName(String name) {this.name = name;}public long getPopulation() {return population;}public void setPopulation(long population) {this.population = population;}// If length of name in country object is even then return 31(any random number) and if odd then return 95(any random number).// This is not a good practice to generate hashcode as below method but I am doing so to give better and easy understanding of hashmap.@Overridepublic int hashCode() {if(this.name.length()%2==0)return 31;elsereturn 95;}@Overridepublic boolean equals(Object obj) {Country other = (Country) obj;if (name.equalsIgnoreCase((other.name)))return true;return false;}}2. HashMapStructure.java(main class)import java.util.HashMap;import java.util.Iterator;public class HashMapStructure {/*** @author Arpit Mandliya*/public static void main(String[] args) {Country india=new Country("India",1000);Country japan=new Country("Japan",10000);Country france=new Country("France",2000);Country russia=new Country("Russia",20000);HashMap<country,string> countryCapitalMap=new HashMap<country,string>();countryCapitalMap.put(india,"Delhi");countryCapitalMap.put(japan,"Tokyo");countryCapitalMap.put(france,"Paris");countryCapitalMap.put(russia,"Moscow");Iterator<country> countryCapitalIter=countryCapitalMap.keySet().iterator();//put debug point at this linewhile(countryCapitalIter.hasNext()){Country countryObj=countryCapitalIter.next();String capital=countryCapitalMap.get(countryObj);System.out.println(countryObj.getName()+"----"+capital);}}}现在,在第23行设置一个断点,在项目上右击->调试运行(debug as)->java应用(java application)。程序会停在23行,然后在countryCapitalMap上右击,选择“查看”(watch)。将会看到如下的结构:从上图可以观察到以下几点:1. 有一个叫做table大小是16的Entry数组。2. 这个table数组存储了Entry类的对象。HashMap类有一个叫做Entry的内部类。这个Entry类包含了key-value作为实例变量。我们来看下Entry类的结构。Entry类的结构:static class Entry implements Map.Entry{final K key;V value;Entry next;final int hash;...//More code goes here} `3. 每当往hashmap里面存放key-value对的时候,都会为它们实例化一个Entry对象,这个Entry对象就会存储在前面提到的Entry数组table中。现在你一定很想知道,上面创建的Entry对象将会存放在具体哪个位置(在table中的精确位置)。答案就是,根据key的hashcode()方法计算出来的hash值(来决定)。hash值用来计算key在Entry数组的索引。4. 现在,如果你看下上图中数组的索引10,它有一个叫做HashMap$Entry的Entry对象。5. 我们往hashmap放了4个key-value对,但是看上去好像只有2个元素!!!这是因为,如果两个元素有相同的hashcode,它们会被放在同一个索引上。问题出现了,该怎么放呢?原来它是以链表(LinkedList)的形式来存储的(逻辑上)。上面的country对象的key-value的hash值是如何计算出来的。<code>Japan的Hash值是95,它的长度是奇数。 India的Hash值是95,它的长度是奇数。 Russia的Hash值是31,它的长度是偶数。 France,它的长度是偶数。  </code>下图会清晰的从概念上解释下链表。所以,现在假如你已经很好地了解了hashmap的结构,让我们看下put和get方法。Put :让我们看下put方法的实现:/*** Associates the specified value with the specified key in this map. If the* map previously contained a mapping for the key, the old value is* replaced.** @param key* key with which the specified value is to be associated* @param value* value to be associated with the specified key* @return the previous value associated with <tt>key</tt>, or <tt>null</tt>* if there was no mapping for <tt>key</tt>. (A <tt>null</tt> return* can also indicate that the map previously associated* <tt>null</tt> with <tt>key</tt>.)*/public V put(K key, V value) {if (key == null)return putForNullKey(value);int hash = hash(key.hashCode());int i = indexFor(hash, table.length);for (Entry<k , V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;}现在我们一步一步来看下上面的代码。对key做null检查。如果key是null,会被存储到table[0],因为null的hash值总是0。key的hashcode()方法会被调用,然后计算hash值。hash值用来找到存储Entry对象的数组的索引。有时候hash函数可能写的很不好,所以JDK的设计者添加了另一个叫做hash()的方法,它接收刚才计算的hash值作为参数。indexFor(hash,table.length)用来计算在table数组中存储Entry对象的精确的索引。在我们的例子中已经看到,如果两个key有相同的hash值(也叫冲突),他们会以链表的形式来存储。所以,这里我们就迭代链表。如果在刚才计算出来的索引位置没有元素,直接把Entry对象放在那个索引上。如果索引上有元素,然后会进行迭代,一直到Entry->next是null。当前的Entry对象变成链表的下一个节点。如果我们再次放入同样的key会怎样呢?逻辑上,它应该替换老的value。事实上,它确实是这么做的。在迭代的过程中,会调用equals()方法来检查key的相等性(key.equals(k)),如果这个方法返回true,它就会用当前Entry的value来替换之前的value。Get:现在我们来看下get方法的实现:/*** Returns the value to which the specified key is mapped, or {@code null}* if this map contains no mapping for the key.** <p>* More formally, if this map contains a mapping from a key {@code k} to a* value {@code v} such that {@code (key==null ? k==null :* key.equals(k))}, then this method returns {@code v}; otherwise it returns* {@code null}. (There can be at most one such mapping.)** &l
会在不适合使用java的地方不用java!作为一名软件开发者,要追求的,应该是不断地提升自己分析问题把握事物关键点,实事求是地给出切实可行且能“一剑封喉”的优雅解决方案的能力,再提升一点境界,就是要不断提升自己创新的能力(即创造新东西、提出新思路、解决新问题的能力)。我个人认为,花费大量的时间去"精通"某种语言、某个平台和某些工具,其实是本末倒置。所以,不要追这种"精通",看上去学富五车很牛逼,其实孔乙己一个罢了。我读书时候,我的老师是这么教导我的说你们啊,编程要做到,将来无论什么时候,看到任何一个东西都能在脑子里想出来,如何用编程来将其实现做到这一步,你们就基本上算是懂编程了其实不管是学习编程语言还是学习外语都是一样的你应该不断滴challenge你自己,看看有哪些还是你不会做,不能做的然后想想怎么做出来,随着你能做的越来越多,慢慢你的能力就提升了至于精通不精通,这个是别人说的,你自己说了不算感觉不到 Java 的存在,只是认为自己在实现某些逻辑,而不是在写 Java举例来说,大多数中国人,都是称自己在“说话”,而不是在“说中文”。 而你会说,你在“说英文”,而不是在“说话”。这里的“说话”,就是所谓的精通的境界我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
这个问题来自于QQ网友,一句两句说不清楚,索性写个文章。我刚开始做Web开发的时候,根本没有前端,后端之说。原因很简单,那个时候服务器端的代码就是一切:接受浏览器的请求,实现业务逻辑,访问数据库,用JSP生成HTML,然后发送给浏览器。即使后来Javascript在浏览器中添加了一些AJAX的效果,那也是锦上添花,绝对不敢造次。因为页面的HTML主要还是用所谓“套模板”的方式生成:美工生成HTML模板,程序员用JSP,Veloctiy,FreeMaker等技术把动态的内容添加上去,仅此而已。那个时候最流行的图是这个样子:在最初的J2EE体系中,这个表示层可不仅仅是浏览器中运行的页面,还包括Java写的桌面端,只是Java在桌面端太不争气, 没有发展起来。每个程序员都是所谓“全栈”工程师,不仅要搞定HTML, JavaScript, CSS,还要实现业务逻辑,编写访问数据库的代码。等到部署的时候,就把所有的代码打成一个WAR包,往Tomcat指定的目录一扔,测试一下没问题,收工回家!不差钱的公司会把程序部署到Weblogic,Websphere这样的应用服务器中,还会用上高大上的EJB。虽然看起来生活“简单”又“惬意”,但实际上也需要实现那些多变的、不讲逻辑的业务需求,苦逼的本质并没有改变。1. 前后端的分离随着大家对浏览器页面的视觉和交互要求越来越高,“套模板”的方式渐渐无法满足要求,这个所谓的表示层慢慢地迁移到浏览器当中去了,一大批像Angular, ReactJS之类的框架崛起,前后端分离了!后端的工程师只负责提供接口和数据,专注于业务逻辑的实现,前端取到数据后在浏览器中展示,各司其职。像Java这样的语言很适合去实现复杂的业务逻辑,尤其是一些MIS系统,行业软件如税务、电力、烟草、金融,通信等等。  所以剥离表示层,只做后端挺合适的。 但是如果仅仅是实现业务逻辑,那后端也不会需要这么多技术了,搞定SSH/SSM就行了。 2. 后端技术互联网,尤其是移动互联网开始兴起以后,海量的用户呼啸而来,一个单机部署的小小War包肯定是撑不住了,必须得做分布式。 原来的单个Tomcat得变成Tomcat的集群,前边弄个Web服务器做请求的负载均衡,不仅如此,还得考虑状态问题,session的一致性。业务越来越复杂,我们不得不把某些业务放到一个机器(或集群)上,把另外一部分业务放到另外一个机器(或集群)上,虽然系统的计算能力,处理能力大大增强,但是这些系统之间的通信就变成了头疼的问题,消息队列(MQ),RPC框架(如Dubbo)应运而生,为了提高通信效率,各种序列化的工具(如Protobuf)也争先空后地问世。单个数据库也撑不住了,那就做数据库的读写分离,如果还不行,就做分库和分表,把原有的数据库垂直地切一切,或者水平地切一切, 但不管怎么切,都会让应用程序的访问非常麻烦,因为数据要跨库做Join/排序,还需要事务,为了解决这个问题,又有各种各样“数据访问中间件”的工具和产品诞生。为了最大程度地提高性能,缓存肯定少不了,可以在本机做缓存(如Ehcache),也可以做分布式缓存(如Redis),如何搞数据分片,数据迁移,失效转移,这又是一个超级大的主题了。互联网用户喜欢上传图片和文件,还得搞一个分布式的文件系统(如FastDFS),要求高可用,高可靠。数据量大了,搜索的需求就自然而然地浮出水面,你得弄一个支持全文索引的搜索引擎(如Elasticsearch ,Solr)出来。林子大了,什么鸟都有,必须得考虑安全,数据的加密/解密,签名、证书,防止SQL注入,XSS/CSRF等各种攻击。3. “大后端”前面提到了这么多的系统,还都是分布式的,每次上线,运维的同学说:把这么多系统协调好,把老子都累死了。得把持续集成做好,能自动化地部署,自动化测试(其实前端也是如此),后来出现了一个革命化的技术docker, 能够让开发、测试、生成环境保持一致,系统原来只是在环境(如Ngnix, JVM,Tomcat,MySQL等)上部署代码,现在把代码和环境一并打包, 运维的工作一下子就简化了。公司自己购买服务器比较贵,维护也很麻烦,又难于弹性地增长,那就搞点虚拟的服务器吧,硬盘、内存都可以动态扩展(反正是虚拟的), 访问量大的时候多用点,没啥访问量了就释放一点,按需分配,很方便,这就是云计算的一个场景。随着时间的推移,各个公司和系统收集的数据越来越多,都堆成一座大山了,难道就放在那里白白地浪费硬盘空间吗?有人就惊奇地发现,咦,我们利用这些数据搞点事情啊, 比如把数据好好分析一下,预测一下这个用户的购买/阅读/浏览习惯,给他推荐一点东西嘛。可是这么多数据,用传统的方式计算好几天甚至好几个月才能出个结果,到时候黄花菜都凉了,所以也得利用分布式的技术,想办法把计算分到各个计算机去,然后再把计算结果收回来, 时势造英雄,Hadoop及其生态系统就应运而生了。之前听说过一个大前端的概念,把移动端和网页端都归结为“前端”,我这里造个词“大后端”,把那些用户直接接触不到的、发生在服务器端的都归结进来。4. 怎么学?现在无论是前端还是后端,技术领域多如牛毛,都严重地细分了,所以我认为真正的全栈工程师根本不存在,因为一个人精力有限,不可能搞定这么多技术领域,太难了。培训机构所说的“全栈”,我认为就是前后端还在拉拉扯扯,藕断丝连,没有彻底分离的时候的“全栈”工程师。那么问题来了, 后端这么多东西,我该怎么学?Java后端学习流程首先,我个人比较推崇的学习方法是:先学java前端,也就是HTML,css,js,因为学习java以后肯定是往java ee方向发展的,学习完前端,在学习后端很多东西比计较容易理解!其中J2SE是关键,如果学好了java se 部分,基础扎实了,后面进阶学习也比较轻松!补充说明一下:我觉得学习java比较合适的方法是先把所有的知识点过一遍,然后把所有的知识点串起来,边做开发边补充,就像写文章一样,先写好框架,然后再去润色填充。因为前期在学习的时候你不知道用在哪里,不知道用途,没有学习的目的,所以很多概念就很难理解,时间久了也容易遗忘。但是如果你直接从实践开始学习,很多知识点都充串联起来了,而且会印象深刻,当然前提条件是你已经入门,已经能写一些简单的程序,我个人现在也是按照这个方式在学习了,感觉很有效。说明:本文介绍的内容过于详尽,这里我补充一些基本的学习路线,相对比较简略,但是比较可行:基础语法。也就是我们常说,各种编程语言都有的部分,数据类型,数组,for循环,do-while,switch……等等,是学习任何编程语言的基础,很关键;面对对象:①类和对象;②Java的三大特性(封装、继承、多态);工具类:①异常和异常处理;②集合框架(主要是List和Map);常用的流(stream):①输入流;②输出流;③缓冲流;网络与线程:①Socket ; ②多线程(Thread,Runnable);数据操作:①Mysql、Oracle; ②JDBC;web基础:①Html/css;②Javascript;③JQuery;框架。只要学会上面的前7条,基本上从前台到后台开发常见的应用还是没太大问题的,当然学习了框架以后,那就最好了,但关键还是要学好基础,说实话,像下面这个表格中所列的知识点,真正能全面掌握还是有难度的,所以凡事还是要踏踏实实的静下心学习,不要只看学习的进度,要看学习的效果。第一阶段技术名称技术内容J2SE(java基础部分)java开发前奏计算机基本原理,Java语言发展简史以及开发环境的搭建,体验Java程序的开发,环境变量的设置,程序的执行过程,相关反编译工具介绍,java开发工具Eclipse的安装和使用,javadoc的说明。Java基础语法Java语法格式,常量和变量,变量的作用域,方法和方法的重载,运算符,程序流程控制,数组和操作数组的类,对数组循环遍历以及针对数组的常用查找、排序算法原理,最后使用Java程序进行功能实现。面向对象编程理解对象的本质,以及面向对象,类与对象之间的关系,如何用面向对象的思想分析和解决显示生活中的问题,并java程序的手段编写出来。如何设计类,设计类的基本原则,类的实例化过程,类元素:构造函数、this关键字、方法和方法的参数传递过程、static关键字、内部类,Java的垃圾对象回收机制。对象的三大特性:封装、继承和多态。子类对象的实例化过程、方法的重写和重载、final关键字、抽象类、接口、继承的优点和缺点。对象的多态性:子类和父类之间的转换、父类指向子类的引用、抽象类和接口在多态中的应用、多态优点。常用设计模式如单利、模版等模式。什么是异常 异常的捕捉和抛出 异常捕捉的原则 finally的使用,package的应用 import关键字。多线程应用多线程的概念,如何在程序中创建多线程(Thread、Runnable),线程安全问题,线程的同步,线程之间的通讯、死锁问题的剖析。javaAPI详解JavaAPI介绍、String和StringBuffer、各种基本数据类型包装类,System和Runtime类,Date和DateFomat类等。常用的集合类使用如下:Java Collections Framework:Collection、Set、List、ArrayList、Vector、LinkedList、Hashset、TreeSet、Map、HashMap、TreeMap、Iterator、Enumeration等常用集合类API。IO技术什么是IO,File及相关类,字节流InputStream和OutputStream,字符流Reader和Writer,以及相应缓冲流和管道流,字节和字符的转化流,包装流,以及常用包装类使用,分析java的IO性能。网络编程Java网络编程,网络通信底层协议TCP/UDP/IP,Socket编程。网络通信常用应用层协议简介:HTTP、FTP等,以及WEB服务器的工作原理。java高级特性递归程序,Java的高级特性:反射、代理和泛型、枚举、Java正则表达式API详解及其应用。 第二阶段技术名称技术内容数据库技术Oracle 基础管理Oracle背景简介,数据库的安装,数据库的用户名和密码,客户端登录数据库服务SQLPLUS,数据库基本概。SQL语句数据库的创建,表的创建,修改,删除,查询,索引的创建,主从表的建立,数据控制授权和回收,事务控制,查询语句以及运算符的详解,sql中的函数使用。多表连接和子查询等值和非等值连接,外连接,自连接;交叉连接,自然连接,using子句连接,完全外连接和左右外连接,子查询使用以及注意事项。触发器、存储过程触发器和存储过程使用场合, 通过实例进行详解。数据库设计优化WHERE子句中的连接顺序,选择最有效率的表名顺序,SELECT子句中避免使用 ‘ * ‘ 计算记录条数等等。数据备份与移植移植技巧,备份方案;导入导出等。 第三阶段技术名称技术内容jdbc技术JDBC基础JDBC Connection、Statement、PreparedStatement、CallableStatement、ResultSet等不同类的使用。连接池技术了解连接池的概念,掌握连接池的建立、治理、关闭和配置。ORM与DAO封装对象关系映射思想,jdbc的dao封装,实现自己的jdbc。可以把第四阶段的知识提前一点,特别是对哪些刚开始接触面向对象编程的同学,我刚开始就学java se,感觉入门很不容易。先学web部分,有利于理解面向对象的概念,另外,web部分相对比较简单,也比较直观,写完直接就可以看见效果,有助于提升大家的学习积极性。第四阶段技术名称技术内容web基础技术(项目实战)Xml技术使用jdom和dom4j来对xml文档的解析和生成操作,xml 的作用和使用场合。html/cssJava掌握基本的html标签的格式和使用,css层叠样式表对div的定义,实现对网站布局的基本实现。Javascript了解javascript的基本语法以及相关函数的使用,并结合html页面实现流程控制和页面效果展示。什么是异常 异常的捕捉和抛出 异常捕捉的原则 finally的使用,package的应用 import关键字。jsp/servletServlet和SP 技术、上
Java学习这一部分是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。在大家看之前,我要先声明两点。1、由于我本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照搬。2、下面对于【第一部分】的推荐内容,目的是让你尽快成为一个可以参加工作的Java开发者,更适用于处于待业状态,准备转行Java的同学。如果你是在校学生,务必要在学好基础(比如计算机系统、算法、编译原理等等)的前提下,再考虑去进行下面的学习。第一部分:对于尚未做过Java工作的同学,包括一些在校生以及刚准备转行Java的同学。一、Java基础首先去找一个Java的基础教程学一下,这里可以推荐一个Java学习交流的QQ群(群号码:589809992)你可以到这个群里找相应的视频教程。学习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部分视频的选择,业界比较认可马士兵的视频,因此推荐给大家。当然了,我本人并没有看过他的视频,所以不好说的太绝对,如果大家自己有更好的选择,可以坚持自己的,不要被我干扰。原本我也是打算出教学视频的,但是由于时间问题,还是决定放弃了。但是如果你看视频的过程中遇到了问题,欢迎来我的交流群提问(群号码:589809992),最后一步,你需要学会使用数据库,mysql是个不错的入门选择,而且Java领域里主流的关系型数据库就是mysql。这部分一般在你学习Servlet/Jsp的时候,就会接触到的,其中的JDBC部分就是数据库相关的部分。你不仅要学会使用JDBC操作数据库,还要学会使用数据库客户端工具,比如navicat,sqlyog,二选一即可。三、开发框架当你学会以上内容以后,这个时候你还不足以参加工作,你还需要继续深造。公司里为了提高开发的效率,会使用一些Java Web框架,因此你还需要学习一些开发框架。目前比较主流的是SSM框架,即spring、springmvc、mybatis。你需要学会这三个框架的搭建,并用它们做出一个简单的增删改查的Web项目。你可以不理解那些配置都是什么含义,以及为什么要这么做,这些留着后面你去了解。但你一定要可以快速的利用它们三个搭建出一个Web框架,你可以记录下你第一次搭建的过程,相信我,你一定会用到的。还要提一句的是,你在搭建SSM的过程中,可能会经常接触到一个叫maven的工具。这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识。在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的。四、找工作当你完成开发框架的学习以后,你就该找工作了,在校的找实习,毕业的找全职。与此同时,在找工作的同时,你不应该停下你的学习,准确的说,是你在以后都不能停下学习。上面这些内容你只是囫囵吞枣的学会了使用,你可以逐步尝试着去了解更多的东西,网络是你最重要的老师。第二部分:对于参加工作一年以内的同学。恭喜你,这个时候,你已经拥有了一份Java的工作。这个阶段是你成长极快的阶段,而且你可能会经常加班。但是加班不代表你就可以松懈了,永远记得我说的那句话,从你入行那一刻起,你就要不停的学习。在这一年里,你至少需要看完《Java编程思想》这本书。这本书的内容是帮助你对于Java有一个更加深入的了解,是Java基础的升级版。这本书很厚,当初看这本书,我花了整整三个月。正常速度的话,应该可以在半年左右看完。我这里不要求过高,只要你在一年以内把这本书看完即可。当然了,我所说的看完,是充分吸收,而不是读一遍就完事了,因此有些内容你可能会看不止一遍。总而言之,这个阶段的核心学习思想就是,在工作中实践,并且更加深入的了解Java基础。第三部分:对于参加工作1年到2年的同学。这部分时间段的同学,已经对Java有了一个更加深入的了解。但是对于面向对象的体会可能还不够深刻,编程的时候还停留在完成功能的层次,很少会去考虑设计的问题。于是这个时候,设计模式就来了。我当时看的是《大话设计模式》这本书,并且写了完整版的设计模式博客。因此,我要求大家,最多在你工作一年的时候,必须开始写博客,而设计模式就是你博客的开端。请记住,我所提的基本都是最低要求,因此不要有任何松懈的心理,否则五年后,你不要去羡慕别人高于你的工资,也不要去羡慕别人进入了某公司。这一年,你必须对于设计模式了如指掌,《大话设计模式》可以作为你的开端。此外,设计模式并不是你这一年唯一的任务,你还需要看一些关于代码编写优化的书。比如《重构 改善既有代码的设计》,《effective java》。总而言之,这个阶段,你的核心任务就是提高你的代码能力,要能写出一手优雅的代码。第四部分:对于参加工作2年到3年的同学有的同学在这个时候觉得自己已经很牛逼了,于是忍不住开始慢慢松懈。请记住,你还嫩的多。这个阶段,有一本书是你必须看的,它叫做《深入理解Java虚拟机》。这本书绝对是Java开发者最重要的书,没有之一。在我眼里,这本书的重要性还要高于《Java编程思想》。这本书的内容是帮助你全面的了解Java虚拟机,在这个阶段,你一定已经知道Java是运行在JVM之上的。所以,对于JVM,你没有任何理由不了解它。另外,在过去2年的工作当中,你肯定或多或少接触过并发。这个时候,你应该去更加深入的了解并发相关的知识,而这部分内容,我比较推荐《Java并发编程实战》这本书。只要你把这本书啃下来了,并发的部分基本已经了解了十之六七。与此同时,这个阶段你要做的事情还远不止如此。这个时候,你应该对于你所使用的框架应该有了更深入的了解,对于Java的类库也有了更深入的了解。因此,你需要去看一些JDK中的类的源码,也包括你所使用的框架的源码。这些源码能看懂的前提是,你必须对设计模式非常了解。否则的话,你看源码的过程中,永远会有这样那样的疑问,这段代码为什么要这么写?为什么要定义这个接口,它看起来好像很多余?由此也可以看出,这些学习的过程是环环相扣的,如果你任何一个阶段拉下来了,那么你就真的跟不上了,或者说是一步慢步步慢。而且我很负责的告诉你,我在这个阶段的时候,所学习的东西远多于这里所罗列出来的。因此千万不要觉得你已经学的很多了,我所说的这些都只是最低要求,不光是我,很多人在这个时间段所学习的内容都远超本文的范围。如果你不能跟上节奏的话,若干年后,如果不是程序猿市场还不错的话,你很可能不仅仅是工资比别人低,公司没别人好,而是根本就找不到工作。总而言之,这个阶段,你需要做的是深入了解Java底层和Java类库(比如并发那本书就是Java并发包java.concurrent的内容),也就是JVM和JDK的相关内容。而且还要更深入的去了解你所使用的框架,方式比较推荐看源码或者看官方文档。另外,还有一种学习的方式,在2年这个阶段,也应该启用了,那就是造轮子。不要听信那套“不要重复造轮子”的论调,那是公司为了节省时间成本编造出来的。重复造轮子或许对别人没有价值,因为你造的轮子可能早就有了,而且一般情况下你造出来的轮子还没有现存的好。但是对别人没有价值,不代表对你自己没有价值。一个造轮子的过程,是一个从无到有的过程。这个过程可以对你进行系统的锻炼,它不仅考察你的编码能力,还考察你的框架设计能力,你需要让你的轮子拥有足够好的扩展性、健壮性。而且在造轮子的过程中,你会遇到各种各样的难题,这些难题往往又是你学习的契机。当你把轮子造好的时候,你一定会发现,其实你自己收获了很多。所以,这个阶段,除了上面提到的了解JVM、JDK和框架源码以外,也请你根据别人优秀的源码,去造一个任何你能够想象出来的轮子。第五部分:参加工作3年到4年的同学这个阶段的同学,提升已经是很难了,而且这个阶段的学习往往会比较多样化。因为在前3年的过程中,你肯定或多或少接触过一些其它的技术,比如大数据、分布式缓存、分布式消息服务、分布式计算、软负载均衡等等。这些技术,你能精通任何一项,都将是你未来面试时巨大的优势,因此如果你对某一项技术感兴趣的话,这个时候可以深入去研究一下。这项技术不一定是你工作所用到的,但一定是相关的。而且在研究一门新技术时,切忌朝三暮四。有的同学今天去整整大数据,搞搞Hadoop、hbase一类的东西。过不了一段时间,就觉得没意思,又去研究分布式缓存,比如redis。然后又过不了一段时间,又去研究分布式计算,比如整整Mapreduce或者storm。结果到最后,搞得自己好像什么都会一样,在简历上大言不惭的写上大数据、分布式缓存、分布式计算都了解,其实任何一个都只是浮于表面。到时候面试官随便一问,就把你给识破了。一定要记住,作为一个程序猿,平日里所接触的技术可能会很多,但是想要让一门技术成为你的优势,那么一定是你对这门技术的了解强过绝大多数人才行。因此在这个阶段,你就不能再简单的去学习前3年的内容了,虽然前面的学习如果还不够深入的话依旧要继续,但这个时候你应该更多的考虑建立你的优势,也可以称为差异性。差异性相信不难理解,就是让你自己变得与众不同。你前面三年的学习足够你成为一名基本合格的Java开发者,但你离成为一名优秀的Java开发者还有很大的距离。所谓优秀,即能别人所不能。而你前三年所学习的内容,是很多做过几年的Java开发都能够掌握的。那么为了让自己有差异性,你就需要另辟蹊径,找一个方向深入研究下去,以期在将来,你能够成为这个领域的专家,比如分布式计算领域的专家,大数据领域的专家,并发领域的专家等等。此外,你除了建立你的差异性之外,还要去弥补你基础上的不足,直到现在,我都没有提及基础知识。原因是基础是很枯燥无味的,学的太早不仅容易懵逼,而且懵逼的同时还容易产生心理阴影,以至于以后再不想去研究这些基础。但基础又是你深入研究一些领域时所必须掌握的,比如你去研究分布式计算,你不懂算法你玩个毛毛?比如你去做分布式缓存,你对计算机系统的内存不了解,你如何去做缓存?如果你的基础本来就非常强,那么恭喜你,相信你在之前的工作中已经充分体会到了这些基础对你的帮助。但我相信大部分人的基础都很薄弱,哪怕是科班毕业的人,很多人也不敢说自己当初的基础学的多么强大,比如算法、计算机系统原理、编译原理这些。但是每个人时间都是有限的,而且这些基础的书籍每一本读下来,没个一年半载的,还真拿不下来,因此还是要有所抉择的。虽然艺多不压身,但问题是艺多是有代价的,是需要你付出时间和精力的,而我个人更赞成在同等代价的情况下获
最近换了个公司,从三月底开始面,面到四月底,面了有快二十家公司。我是一个喜欢总结经验的人,每经过一场面试,我在回来的路上都会仔细回想今天哪些问题可以答的更好,或者哪些问题是自己之前没遇到过的,或者是哪个知识点今天又问了等等。四月中旬的时候,我就在构思要写一篇面经,主要是想着可能对那些跟我相同处境的人有点帮助,再者就是稍微记录下这为期一个月的面试过程。个人介绍:首先介绍下我面试时的自身条件情况,我把自己的情况分为优势和劣势来说可能更有利于你们比较自身情况。劣势:1.15年7月毕业后开始到上海工作,面试的时候是17年3月到4月,一年多的经验,勉强算两年经验。分析:一年多经验我认为是比较尴尬的,处于一个不上不下的位置,很多公司比较喜欢招三年经验的,或者直接招应届生来培养。2.毕业于一个非985/211,勉强上一本的高校。分析:这个相对影响较小,因为有工作经验后,公司对学校的要求就没那么高了,只要是本科就基本没问题,但是还是有个别叼毛公司只要985/211。3.前一家公司是传统电信行业,加入项目组时,项目已经上线有段时间了,我们的任务就是有需求就开发,有bug就优化,其他时间就聊骚,各干各的,工作一年多跟在养老一样,用一句话说就是编程5分钟,扯淡2小时,项目经验严重不足,没开发过很难的需求。分析:这一点是最伤的,公司招有经验的就想看你都干了些什么牛批的东西,结果你告诉面试官我写的需求都是垃圾。优势:1.大学时拿过比较多的奖,每年都是校级优秀学生,毕业时是市级优秀毕业生,拿过省级ACM二等奖等。分析:大学的荣誉对一个有工作经验的人来说,公司不一定会看重,但是可能会对面试官产生微妙的影响,特别是ACM奖,我碰到过有的面试官也是搞过ACM的,有共同的话题聊起来总是比较容易的,但是也要注意不能把这一栏篇幅写的过于多,只能当作点缀用,我当时是放在简历最后一栏,简要的写了最主要的几个奖。2.良好的沟通交流能力。分析:这个能力不会是关键性的,但是可以加分。3.较强的学习能力和逻辑思维能力。分析:有些公司和面试官还是比较看重一个人的学习能力的,经验代表着你现在在什么级别,而学习能力则代表着你将来能到达什么级别。学习过程:看了我的优劣势介绍,你会发现我的优势相对于我的劣势来说,简直不值一提。我自己对此也有清晰的认识,因此从过完年之后,我就开始抓紧空闲时间学习。学习的过程如下:1.看面试题正常人第一步肯定都会看面试题,我也不例外,在看的过程中,我发现有些文章写的不错,对我帮助不小值得推荐,如下:Java面试题全集(上)很多基础的东西,建议先看。各大公司Java后端开发面试题总结面试心得与总结—BAT、网易、蘑菇街关于Java面试,你应该准备这些知识点2.深入学习在看面试题的过程,你会遇到一些自己没接触过的或者以前没深入学习过的知识,例如最常问的HashMap内部实现原理,这就促使你得开始去看jdk的源码或者是学习一些新的东西。看源码是很重要的一步,起步很难,但是会让你收益良多,看源码的过程如果碰到无法理解的地方,可以百度看下别人的理解。我学习源码的过程中,看过几个人的关于源码的文章写的很不错,如下:五月的仓颉占小狼zhangshixi的Core java系列3.熟悉项目找出自己工作以来开发过的最叼的功能,将整个功能的流程和涉及的东西吃透。项目是面试中必问的环节,一般是以一个功能点为基础展开问,因此你必须对这个功能有很深的认识,不能有模糊的地方。如果有时间,能把涉及到的知识点也搞懂最好。4.做面试题有不少公司是有面试的,如果你没有准备过,很容易在各种小地方犯错,建议去一些面试题网站多做些题目,我自己是用的牛客网。5.学习记录把自己每天的学习时间和学习内容记录下来,可以让自己更有动力的学习,学习是一个枯燥的过程,你必须让自己时刻保持有动力。投简历、约面试环节1.在哪些网站投?拉勾网、BOSS直聘、猎聘网。2.是否该海投?投简历分为两个情况。1)没有社招面试经验:建议采取海投的方式,只要职位要求跟自己比较匹配都可以投,累计面试经验。这个环节可以把投简历的网站增加两家:智联和无忧。2)自认为社招面试经验已经足够:投那些职位匹配、公司满意的职位。公司评价可以去看准网、百度、知乎等查询。3.一天约几家面试合适?最理想的情况为2家面试,上午一般在10点左右,下午一般在2点左右。建议把理想的公司放下午,因为下午的时间比较充足,可以让公司更充分的了解你。我开始面的时候,每次都是上午面的不好,下午面的不错。4.投简历经常没下文?我当初也没想到简历筛选这关有这么难,可能是我的简历确实亮点不多,再者HR很多都不是行内人,因此他们看得最直接的就是你上家的公司和你毕业的学校,如果你不是从牛逼的公司/学校出来,可能会碰到和我一样的情况,应对的办法就是多投。5.是否该裸辞?我一开始是边上班边投,然后利用调休时间,或者请假去面试。后来,面试机会越来越多,请假太频繁了,自己都不好意思了,并且自己也已经有足够的信心,这个时候我选择了裸辞。裸辞还有一个原因是,在面试过程中你会发现,有的公司要人要的紧,如果你的辞职流程过长可能会导致你错过这个公司。6.注意事项1)面试前一天把路线和时间算好,最好别迟到。2)背个书包,带好简历、充电宝、纸巾、雨伞。面试环节1.笔试常见的问题?面试常见的问题上面给的面试题链接基本都有。我只提几点:1)写SQL:写SQL很常考察group by、内连接和外连接。2)手写代码:手写代码一般考单例、排序、线程、消费者生产者。我建议排序算法除了冒泡排序,最好还能手写一种其他的排序代码。试想:如果一般面试者都写的冒泡排序,而你写的是快速排序/堆排序,肯定能给面试官留下不错的印象。2.面试流程?1)让你自我介绍2)问Java基础知识3)问项目4)情景问题,例如:你的一个功能上了生产环境后,服务器压力骤增,该怎么排查。5)你有什么想问面试官的3.面试常问的知识点?1)集合相关问题(必问):HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。HashMap和Hashtable的区别。ArrayList、LinkedList、Vector的区别。HashMap和ConcurrentHashMap的区别。HashMap和LinkedHashMap的区别。HashMap是线程安全的吗。ConcurrentHashMap是怎么实现线程安全的。2)线程相关问题(必问):创建线程的3种方式。什么是线程安全。Runnable接口和Callable接口的区别。wait方法和sleep方法的区别。synchronized、Lock、ReentrantLock、ReadWriteLock。介绍下CAS(无锁技术)。什么是ThreadLocal。创建线程池的4种方式。ThreadPoolExecutor的内部工作原理。分布式环境下,怎么保证线程安全。Java学习交流QQ群:589809992 我们一起学Java!3)JVM相关问题:介绍下垃圾收集机制(在什么时候,对什么,做了什么)。垃圾收集有哪些算法,各自的特点。类加载的过程。 双亲委派模型。有哪些类加载器。能不能自己写一个类叫java.lang.String。4)设计模式相关问题(必问):先问你熟悉哪些设计模式,然后再具体问你某个设计模式具体实现和相关扩展问题。5)数据库相关问题,针对Mysql(必问):给题目让你手写SQL。有没有SQL优化经验。Mysql索引的数据结构。SQL怎么进行优化。SQL关键字的执行顺序。有哪几种索引。什么时候该(不该)建索引。Explain包含哪些列。Explain的Type列有哪几种值。6)框架相关问题:Hibernate和Mybatis的区别。Spring MVC和Struts2的区别。Spring用了哪些设计模式。Spring中AOP主要用来做什么。Spring注入bean的方式。什么是IOC,什么是依赖注入。Spring是单例还是多例,怎么修改。Spring事务隔离级别和传播性。介绍下Mybatis/Hibernate的缓存机制。Mybatis的mapper文件中#和$的区别。Mybatis的mapper文件中resultType和resultMap的区别。Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的,其内部是怎么实现的。Java学习交流QQ群:589809992 我们一起学Java!7)其他遇到问题:介绍下栈和队列。IO和NIO的区别。接口和抽象类的区别。int和Integer的自动拆箱/装箱相关问题。 常量池相关问题。==和equals的区别。重载和重写的区别。String和StringBuilder、StringBuffer的区别。静态变量、实例变量、局部变量线程安全吗,为什么。 try、catch、finally都有return语句时执行哪个。介绍下B树、二叉树。ajax的4个字母分别是什么意思。xml全称是什么。分布式锁的实现。分布式session存储解决方案。常用的linux命令。一些经验:1.先投一些普通公司,等面出了心得再去投理想的公司。2.不熟悉的技术不要主动提。3.对于那种实习期6个月还打8折的公司,除非你没有其他选择了,否则不要去。4.小公司喜欢在薪水上压你,开的时候适当提高。5.不要去参加招聘会,纯粹是浪费时间。6.把面试当作一次技术的交流,不要太在意是否能被录取。7.公司一般面完就决定是否录取了,让你回去等消息这种情况一般没戏,无论你自己觉得面的有多好。8.尽量少通过电话面试,效果不好。9.在面试的日子里,要保持每天学习,无论是学习新东西还是复习旧东西。10.拿到offer了,问问自己这个公司让自己100%满意了吗,如果不是,请继续努力找更好的。11.通过面试官可以大概判断这家公司的情况。12.拉勾投的简历很多会被筛掉,但是拉勾还是面试机会的最主要来源。13.理想的公司可以多投几次,我有好几次都是第一次投被筛掉,多投几次就过的经验。我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
这是我自己早前听课时整理的Java全套知识,适用于初学者,也可以适用于中级进阶的人,你们可以下载,我认为是比较系统全面的,可以抵得上市场上90%的学习资料。讨厌那些随便乱写的资料还有拿出来卖钱的人!在这里我免费的分享出来供大家使用!在这个平台真的可以学习到不少的东西!有很多的人都在无私的奉献着他们的智慧与知识。希望对于Java学习者有所帮助! 如果你觉得好的话,就在评论出给予回应,谢谢。这是我劳动成果!希望给予鼓励!点击下载之前的链接有人说失效了!现在我又重新更新了!这次打不开的就直接来我的QQ群吧:589809992
社区中并不缺少有关软件工程师职业发展的文章,甚至可以说是泛滥。很多人都能在这个话题上说两句,三五年工作经验的编程老鸟也好,架构师也好,技术 VP 也好,CTO 也好,都有各自的看法与实践经验。没有哪一套方法是适用于所有人的,这一套软件工程师职业发展纲要,也不过是在你踽踽前行的路上,迷茫时可用来参考借鉴。你的核心竞争力,永远是你的自身实力。切记!一、专业技能学习捷径1、爱上你的编码神器众所周知,软件工程师要做的工作就是写代码,准确地说,你的目标应该是写出满足业务需求并且无法找出 Bug 的代码,而不是写一大堆没用的文字。既然你的任务是写出高质量的代码,那么你首先应该训练的就是打字速度,你需要掌握键盘盲打技能,甚至还要爱上你的“编码神器”,并做到将此工具的用法烂熟于心,闭上眼睛都能正确敲中你想要的快捷键。2、熟悉底层技术原理当你完全驾驭了计算机的输入设备以后,你需要进一步了解计算机的内部工作原理,不是让你把机器大卸八块,而是你需要全面了解计算机的组成结构与工作原理。如果你不是计算机科班出生也没关系,在网上买一本关于计算机组成原理的书自学即可。你无需做到精通,能全面了解即可,因为接下来你需要在编程的世界中,慢慢去体会计算机的工作感受,你就是计算机的管理者。3、深入一门编程语言好了,现在是时候学习一门编程语言了,最好的选择是 Java,为什么呢?原因很简单,因为市场需求量最大,我敢保证,你学 Java 肯定比学 PHP 更容易找到工作(希望 PHP 程序员们淡定一些,其实我始终认为 PHP 是世界上最好的编程语言)。当你在学习 Java 时,首先需要掌握它啰里吧嗦的编程语法,此时没有什么比写一个“Hello World”来得更爽快一些。随后你需要深刻理解的是 Java 的面向对象概念(每次我说到面向对象,总会被一些单身汉吐槽,其实我想说,对象是可以 new 出来的),这些概念看上去比较虚,但是它们却能撑起一个强大的软件架构。所以,在面向对象技术上面花再多功夫都不为过,因为它能训练我们对业务的抽象能力,就像当初我们学习数学一样,它能训练我们的逻辑思维能力。4、选择一位对的老师看书、看视频、看源码、看技术文档,其实这些都是较为低效的学习方法,掌握编程技能的捷径就是拜一位资深的程序员为师,你可以尊称他为“码神”,记得一定要把他伺候好,让他愿意传授一些编程技能给你,其实也就是一个微笑外加一顿小龙虾的事情,他就能被你征服。一定要看他写的代码,思考为什么他会这样写,一定要将你不理解的地方记录下来,并且在下班之前紧紧地抓住他,让他一次给你讲个够,此时你一定会有一种打通任督二脉的畅快之感。所谓“师傅领进门,修行在个人”,你需要比你师傅更加努力,甚至十倍于他人的付出,才能在编程之路上尝到甜头。此时你需要学习更加高深的武功,研究更加优秀的源码,实践更有挑战的项目,还需要花整块时间,系统地看技术文档以及技术参考书。假如你想成为架构师,不妨看看我所著的《架构探险》这本书,也许它会对你的专业技能有所帮助。5、乐于分享你的技能你最好要让自己变成一位豁达开朗之人,千万不要吝啬,一定要懂得分享你所学的专业技能。可以尝试做点自己的开源项目,并让这个开源项目变得更加开放,不妨结合开源,写点技术博客,并厚着脸皮给你身边的朋友阅读。这件事情一定要持之以恒,不要担心有人吐槽你,你肯定会被吐槽,那是因为大家在关注你,此时你需要更加努力,让自己变得足够专业。当你成为真正的“大神”时,就不会有人再吐槽你了,他们只会吐槽自己的技术不如你,此时你将得到的是无限的膜拜和称赞。相信我,这绝不是奇迹。在学习专业技能之路上,多一点自信,多一点勤奋,多一点思考,再争取一点机会,你就会成功。二、不可或缺的软技能1、软技能 ≠ 务虚如果将专业技能比喻为“硬技能”,那么在我们的职场中,与专业性无关的技能就可以归纳为“软技能”了。但每当我提到软技能时,难免会让人误解为这是“务虚”的一种功夫,我们虽然是“吃软饭的”(做软件开发的),但我们却十分讨厌虚伪。没错!我也很厌恶虚伪之人,尤其是在职场中遇到这样的人物,我从心底鄙视他们,但我从来不会和他们发生任何冲突,反而还能和他们愉快地共事,这种本领靠的就是软技能。软件工程师每天都在和机器打交道,机器是没有感情的,你告诉它是0,它一定不会认为是1。但我们与人打交道却不一样,你告诉他是真,他却可能认为是假。与人打交道,正是软件工程师们最为欠缺的方面,有些软件工程师甚至害怕与人交流,害怕在公开场合讲话,害怕抛头露面,害怕做一些组织性的工作。如果你也有以上这些心里负担,那么恭喜你!因为你即将从本文中找到克服这些困难的灵丹妙药,至少我希望是这样。需要强调的是,软技能是一种职场必备的核心技能,我敢直言,如果缺乏这方面的技能,你的职业生涯将会变得非常糟糕。软技能包括的方面非常广泛,沟通、协调、组织、气场这些都是最基本的软技能,甚至情商也是一种软技能,会不会讲话,听不听得明白,这些都是软技能。那么我们不妨先从沟通这项软技能开始吧,因为我认为他是软件工程师最重要的软技能之一。2、口语流利 ≠ 会沟通很多人都容易将沟通理解为讲话,说一个人语言很流利,很会讲话,口若悬河,夸夸其谈,其实并非他的沟通能力很强。我认为,沟通可以理解为两方面,即“沟”和“通”。“沟”指的是你将心中所想很清晰地表达出来给对方听,考验的是你的表达能力;“通”指的是让你确信对方是否真明白你所表达的意思,考验的是你的倾听能力。所以,我们很多时候都是在“沟”,往往忽略了“通”,从而形成了“沟而不通”的情况,因此,现在全世界人民都在提倡如何“有效沟通”。还是用一个示例来说话吧。当领导交给你一项棘手的工作,但你不知道如何开始进行这项工作,此时你应该如何应对当前的挑战呢?绝大多数人会硬着头皮去做,他们希望通过自己的努力,可以顺利完成任务,但结果往往却无法让领导满意。少数人会主动向领导咨询,以寻求领导对自己的帮助。此时应该如何与领导对话呢?似乎并非很多人都清楚。下面这段话是我的套路,仅供参考。我:勇哥(他是我的领导),最近我遇到了一点麻烦的事情,想听听您的看法(勾起领导的兴趣,让他认真听我说下去,记得一定要说“您”,而不是“你”)。领导:哦?说来听听(证明领导此时不忙,他有时间让我占用,如果他此时很忙,你应该能感受出来的)。我:感谢您对我的信任,昨天您交给我一项任务,回到家我一直都在想这项任务,我在想……(一定要对领导表示感激,是他给了我这次锻炼自己的机会,并强调我是“回到家”都在思考,而不是只在在公司里思考,道理你懂的)领导:可能是我没说清楚,你把这项任务想复杂了,其实……(可见这是一位 nice 的领导,跟着他,你能学到很多东西)我:我还想再清楚一下,您期待这项工作的结果是怎样的?(一定要明确领导想要的结果,他只会为结果买单)领导:我希望……(领导娓娓道来,此处省略1万字,你千万不要打断领导的讲话,他讲累了自然就会停,你只需要认真听他怎么讲)我:好的,我明白了,您希望我……(一定要学会复述领导讲过的话,而且要用自己的理解来表达,不要当复读机)领导:没错,就是这样。(领导表示认可了,此时你应该表示给领导一个微笑,让他感到欣慰)我:感谢勇哥!如果我在执行过程中遇到问题,可以再向您请教吗?(一定要感谢,而且要表现出虚心向领导请教,为下一次求救做好准备)领导:当然,随时交流。(你真心拿他当领导,他才会无条件帮助你,你不懂得用好这位领导,那是你自己的损失)沟通是不是很有趣?其实沟通是一门学问,我们花一辈子时间都在学习,都在改进自己的沟通方式,目的仅为愉快地和身边的人一起“玩耍”,让此生感到愉悦。当你已经掌握了必备的专业技能,也具备了让你脱颖而出的软技能,那么接下来你将思考的是自己该走那条路了,继续做软件工程师,还是做软件工程师的 leader?下面这段话将告诉你答案。三、正确制定职业路线1、给自己提几个问题首先要澄清的是:我并非职业导师,更不是人生教父,所有的路都由你自己选择,我的责任是告诉你,我认为行之有效的方法。当你正走在职场的十字路口徘徊,思考走技术,还是走管理?我的答案只有一个:根据你自己的优势来决定。合理利用好自己的优势,会让自己走的更加顺畅,让自己无怨无悔。还是举一个例子来说明吧。前段时间有位朋友在微信上私聊我,他也遇到了这个问题,继续做技术,还是转管理?我当时是这样问他的,但我希望你可以用这样的方式来问自己。我:你工作多久了?朋友:时间不长,写了10年的代码。我:那相当资深啊,现在还对写代码有激情吗?朋友:喜欢写,周末有时都会宅在家里写。我:那你还在纠结什么呢?朋友:我都工作10年了,身边的人要么当 CTO,要么做总监,自己却还在撸代码,我现在到底该不该转管理?我:你为什么会考虑转管理?说说你在管理上的优势吧。朋友:我觉得自己对技术有一定深度,可以帮助团队解决一些技术难题。我:如果你团队中有位小伙伴遇到一个很棘手的技术问题,没辙了,你会做些什么?朋友:撸起袖子,就地帮他解决掉。我:建议你走技术专家路线,这条路也许更加适合你。朋友:……2、转管理之前,先理解管理当我们在纠结是否应该转管理时,不妨首先理解一下什么是管理?以及什么是管理者?只有当我们正确理解了这些概念以后,再来思考自己是否具备这样的特征,才能顺利帮助自己转型。管理(management)是协调和监督他人的工作,从而使他人的工作可以有效率且有成效地完成。效率(efficiency)指的是以尽可能少的投入,以获得尽可能多的产出,效率常常被说成“正确地做事”,即不浪费资源。成效(effectiveness)常常被称为“做正确的事”,即做那些可以实现目标的工作活动。管理者(manager)就是完成所有管理工作,并使组织目标能够实现的人。管理者的工作包括计划(planning)、组织(organizing)、领导(leading)和控制(controlling)四种职能。以上都是管理学告诉我们的知识,如果你想成为一名管理者,那么你必须首先正确理解这些概念的真实含义,才能完全驾驭管理者的岗位,否则你会从管理岗位上摔下来,自己一定伤得不轻。如果你想成为一名优秀的管理者,那么你需要做些什么呢?亲自且专业地给团队激励。激励团队完成你无法独立完成的任务。对问题提供指导和指引。对团队的表现给予反馈。帮助团队改善绩效。使团队对组织的改变知情。改善团队小伙伴们的生活。如果团队和你共事过,那么团队应该觉得他们是幸运的,因为你能够让他们更加愉快和高效地工作。写在最后不论选择技术还是管理,在任何时候都不要放弃你的硬技能,因为它是你的“生存之本”,同时你也需要具备强大的软技能,因为它是你的“发展之源”。学习硬技能其实是有捷径的,你无需一味地学习这些知识点,更多的其实是与人交流以及加以应用。软技能其实是可以训练的,你只需抓住一切可以抓住的机会,有意识地加以训练和反思,你就能悟出很多宝贵的经验。软件开发是一门艺术,你需要能够静得下心,不断地优化和雕琢你的作品,因此你需要具备工匠精神。如果你想成为一名工匠领袖,那么你就应该比他人思考得更多、更高、更深、更全面,你需要更多的软技能。你只有认识到自己的优势,才能正确地选择自己的职业路线。祝你成功!我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。原文:https://my.oschina.net/huangyong/blog/1633257#comment-list
引如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。很多人都对其中的一些概念不够明确,如同步、并发等等,让我们先建立一个数据字典,以免产生误会。多线程:指的是这个程序(一个进程)运行时产生了不止一个线程并行与并发:并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。 并发与并行线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。好了,让我们开始吧。我准备分成几部分来总结涉及到多线程的内容:扎好马步:线程的状态内功心法:每个对象都有的方法(机制)太祖长拳:基本线程类九阴真经:高级多线程控制类扎好马步:线程的状态先来两张图:  各种状态一目了然,值得一提的是"Blocked"和"Waiting"这两个状态的区别:线程在Running的过程中可能会遇到阻塞(Blocked)情况对Running状态的线程加同步锁(Synchronized)使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。从jdk源码注释来看,blocked指的是对monitor的等待(可以参考下文的图)即该线程位于等待区。线程在Running的过程中可能会遇到等待(Waiting)情况线程可以主动调用object.wait或者sleep,或者join(join内部调用的是sleep,所以可看成sleep的一种)进入。从jdk源码注释来看,waiting是等待另一个线程完成某一个操作,如join等待另一个完成执行,object.wait()等待object.notify()方法执行。Waiting状态和Blocked状态有点费解,我个人的理解是:Blocked其实也是一种wait,等待的是monitor,但是和Waiting状态不一样,举个例子,有三个线程进入了同步块,其中两个调用了object.wait(),进入了waiting状态,这时第三个调用了object.notifyAll(),这时候前两个线程就一个转移到了Runnable,一个转移到了Blocked。从下文的monitor结构图来区别:每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态Blocked,从jstack的dump中来看是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是Waiting,表现在jstack的dump中是 “in Object.wait()”。此外,在runnable状态的线程是处于被调度的线程,此时的调度顺序是不一定的。Thread类中的yield方法可以让一个running状态的线程转入runnable。内功心法:每个对象都有的方法(机制)synchronized, wait, notify 是任何对象都具有的同步工具。让我们先来了解他们 他们是应用于同步问题的人工线程调度工具。讲其本质,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。再讲用法:synchronized单独使用:代码块:如下,在多线程环境下,synchronized块中的方法获取了lock实例的monitor,如果实例相同,那么只有一个线程能执行该块内容直接用于方法: 相当于上面代码中用lock来锁定的效果,实际获取的是Thread1类的monitor。更进一步,如果修饰的是static方法,则锁定该类所有实例。synchronized, wait, notify结合:典型场景生产者消费者问题/*** 生产者生产出来的产品交给店员*/public synchronized void produce(){if(this.product >= MAX_PRODUCT){try{wait();System.out.println("产品已满,请稍候再生产");}catch(InterruptedException e){e.printStackTrace();}return;}this.product++;System.out.println("生产者生产第" + this.product + "个产品.");notifyAll(); //通知等待区的消费者可以取出产品了}/*** 消费者从店员取产品*/public synchronized void consume(){if(this.product <= MIN_PRODUCT){try{wait();System.out.println("缺货,稍候再取");}catch (InterruptedException e){e.printStackTrace();}return;}System.out.println("消费者取走了第" + this.product + "个产品.");this.product--;notifyAll(); //通知等待去的生产者可以生产产品了}volatile多线程的内存模型:main memory(主存)、working memory(线程栈),在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。 针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。太祖长拳:基本线程类基本线程类指的是Thread类,Runnable接口,Callable接口Thread 类实现了Runnable接口,启动一个线程的方法:Thread类相关方法:关于中断:它并不像stop方法那样会中断一个正在运行的线程。线程会不时地检测中断标识位,以判断线程是否应该被中断(中断标识值是否为true)。终端只会影响到wait状态、sleep状态和join状态。被打断的线程会抛出InterruptedException。Thread.interrupted()检查当前线程是否发生中断,返回booleansynchronized在获锁的过程中是不能被中断的。中断是一个状态!interrupt()方法只是将这个状态置为true而已。所以说正常运行的程序不去检测状态,就不会终止,而wait等阻塞方法会去检查并抛出异常。如果在正常运行的程序中添加while(!Thread.interrupted()) ,则同样可以在中断后离开代码体Thread类最佳实践:写的时候最好要设置线程名称 Thread.name,并设置线程组 ThreadGroup,目的是方便管理。在出现问题的时候,打印线程栈 (jstack -pid) 一眼就可以看出是哪个线程出的问题,这个线程是干什么的。如何获取线程中的异常Runnable与Thread类似Callablefuture模式:并发模式的一种,可以有两种形式,即无阻塞和阻塞,分别是isDone和get。其中Future对象用来存放该线程的返回值以及状态九阴真经:高级多线程控制类以上都属于内功心法,接下来是实际项目中常用到的工具了,Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者编写高效、易维护、结构清晰的Java多线程程序。1.ThreadLocal类用处:保存线程的独立变量。对一个线程类(继承自Thread)当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。主要方法是get()和set(T a),set之后在map里维护一个threadLocal -> a,get时将a返回。ThreadLocal是一个特殊的容器。2.原子类(AtomicInteger、AtomicBoolean……)如果使用atomic wrapper class如atomicInteger,或者使用自己保证原子的操作,则等同于synchronized该方法可用于实现乐观锁,考虑文中最初提到的如下场景:a给b付款10元,a扣了10元,b要加10元。此时c给b2元,但是b的加十元代码约为:AtomicReference对于AtomicReference 来讲,也许对象会出现,属性丢失的情况,即oldObject == current,但是oldObject.getPropertyA != current.getPropertyA。这时候,AtomicStampedReference就派上用场了。这也是一个很常用的思路,即加上版本号3.Lock类lock: 在java.util.concurrent包内。共有三个实现:ReentrantLockReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLock主要目的是和synchronized一样, 两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。区别如下:lock更灵活,可以自由定义多把锁的枷锁解锁顺序(synchronized要按照先加的后解顺序)提供多种加锁方案,lock 阻塞式, trylock 无阻塞式, lockInterruptily 可打断式, 还有trylock的带超时时间版本。本质上和监视器锁(即synchronized是一样的)能力越大,责任越大,必须控制好加锁和解锁,否则会导致灾难。和Cond
最近有些网友问我如何自学 Java 后端,还有些是想从别的方向想转过来,但都不太了解 Java 后端究竟需要学什么,究竟要从哪里学起,哪些是主流的 Java 后端技术等等,导致想学,但又很迷茫,不知从何下手。我就以过来人的经历,写在这篇博客里,不一定都对,但都是我根据自己的经历总结出来的,供你们的参考。Java 基础Java 是一门纯粹的面向对象的编程语言,所以除了基础语法之外,必须得弄懂它的 oop 特性:封装、继承、多态。此外还有泛型、反射的特性,很多框架的技术都依赖它,比如 Spring 核心的 Ioc 和 AOP,都用到了反射,而且 Java 自身的动态代理也是利用反射实现的。此外还有 Java 一些标准库也是非常常见,比如集合、I/O、并发,几乎在 Web 开发中无处不在,也是面试经常会被问到的,所以在自学 Java 后端之前,不妨先打好这些基础,另外还有 Java8 的一些新特性,也要重点关注,比如 Lambda 表达式、集合的 Stream 流操作、全新的 Date API 等等,关于新特性,我也写了几篇关于这方面的博客,请自行找吧,就不贴出来了。关于书籍推荐,我是不建议初学者一开始就拿着「Java 编程思想」啃的,因为当初我就是那个当天下午决定自学 Java,晚上就抱着这本书啃的人,说实话,我当时真的不懂它在说啥,因为我没有一点的面向对象语言编程的基础,而这本书又写得太博大精深了,在当时的我来说,完全是天书,但是我认为它仍然是 Java 界的圣经,每读一次都有所收获。我在这里推荐你们一开始先看「Java 核心技术」,这本书讲得比较通俗易懂,初学者比较能接受。关于视频推荐,我当初就是听某客的毕向东老师讲的 Java 基础教程(可以关注我的微信公众号获取),毕老师讲的实在是太生动有趣了,不知不觉把我带进 Java 的坑里无法自拔,有时候我会听他视频时笑出声来,也许是我那段自学阶段最有趣的时刻了。数据库关于 sql 方面:SQL 教程、MySQL 教程我是了解了一些基础语法之后,就直接跟着视频的老师做一些表操作实战练习了,比如单表查询、多表查询等。我建议学 sql 切勿眼高手低,需多加练习,不要只看懂了就行,因为工作中写得一手简练的 sql 是非常重要的。在这里我说下我在项目一直秉承着 sql 语句是能避免多表查询就避免多表查询,能够分开多条语句就分开多条语句,因为这里涉及到多表查询性能和数据库扩展的问题。关于 JDBC 方面:JDBC 教程、 JDBC 获取连接对象源码分析你需要弄懂 JDBC API 的用法,其实它只是一组规范接口,所有数据库驱动只要实现了 JDBC,那么我们就可以通过标准的 API 调用相应的驱动,完全不用知道驱动是怎么实现的,这就是面向接口编程的好处。而且对于 JDBC 我是直接看视频去理解的,跟着视频做了一个基于 Apache Dbutils 工具做了一个具有事务性的小工具,我特意用思维导图总结了一下:jdbc-utils源码地址:jdbc-utilsWeb 基础曾经开源中国创始人红薯写了一篇文章「初学 Java Web 开发,请远离各种框架,从 Servlet 开发」,我觉得他说的太对了,在如今 Java 开发中,很多开发者只知道怎么使用框架,但根本不懂 Web 的一些知识点,其实框架很多,但都基本是一个套路,所以在你学习任何框架前,请把 Web 基础打好,把 Web 基础打好了,看框架真的是如鱼得水。关于 Http 协议,这篇文章就写得很清楚:Http协议关于 Web 基础这方面数据推荐,我当时是看的是「Tomcat 与 Java Web 开发技术详解」,很详细地讲解了整个 Java Web 开发的技术知识点,但现在看来,我觉得里面讲的有一些技术确实有点老旧了,不过可以了解一下 Java Web 开发的历史也是不错的。所以在 Web 基础这方面我都是看某客的崔老师讲的「超全面 Java Web 视频教程」,讲得很详细很生动,还有实战项目!关于 JSP,你只要了解它其实就是一个 Servlet 就行了,关于它的一些标签用法,我认为可以直接忽略,因为现在互联网几乎没哪间公司还用 JSP,除了一些老旧的项目。现在都是流行前后端分离,单页应用,后端只做 API 接口的时代了,所以时间宝贵,把这些时间重点放在 Servlet 规范上面吧。关于 Tomcat,它是一个 Web 容器,我们写的后端项目都要部署到Web容器才能运行,它其实是一个遵循 Http,通过 Socket 通信与客户端进行交互的服务端程序:Tomcat结构及处理请求过程Web 主流框架Java Web 框架多如牛毛,等你有一定经验了,你也可以写一个 Web 框架,网上很多说 Spring、Struts2、Hibernate 是 Java 三架马车,我只想说,那是很久远的事情了,我严重不推荐 Struts2、Hibernate,相信我,一开始只需要上手 Spring、SpringMVC、Mybatis 就可以了,特别是 Spring 框架,其实 Spring 家族的框架都是很不错的。但是提醒一点就是,千万不要沉迷于各种框架不能自拔,以会多种用法而沾沾自喜,导致知其然而不知其所以然。Spring其核心思想就是 IOC 和 AOP:谈谈对 Spring IOC 的理解Spring 面向切面编程SpringMVC 它的思想是全部请求统一用一个 Servlet 去做请求转发与控制,这个 Servlet 叫 DispatcherServlet:SpringMVC 初始化过程SpringMVC 处理请求过程Mybatis 它可实现动态拼装 sql,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集:mybatis 入门教程Mybatis 深入浅出系列Web 框架进阶使用了 SSM 框架后,你会觉得框架也不过这么回事,如果你对 Spring 有过大概了解,你也会产生想写一个「山寨版」Spring 的心思了,一个轻量级 Web 框架主要具备以下功能:可读取用户自定义配置文件,并以此来初始化框架;具备 Bean 容器,管理项目的类的对象生命周期;具备依赖注入,降低类之间的耦合性;具备 AOP 功能,使项目可进行横向编程,可不改变原有代码的情况增加业务逻辑;具备 MVC 框架模式。其实除了 SSM 之外,Web 框架可谓是百家齐放,其中以 Spring 全家桶最为耀眼,在这里我极力推荐两个 Spring 家族框架:SpringBoot 和 SpringCloud。SpringBoot 弥补了 Spring 配置上的缺点,再也不用为繁杂的 xml 费劲精力了,堪称是 Java 后端开发的颠覆者,推荐书籍「Java EE 开发的颠覆者:SpringBoot实战」SpringBoot 构建 web 项目SpringBoot 自动化配置源码分析自定义 SpringBoot Starterspring-boot-starter-tutorialSpringCloud 是一个微服务架构,能够将项目按照业务分成一个个微服务,每个微服务都可独立部署,服务之间互相协调。当一个项目越来越大时,随之而来的是越来越难以维护,此时将项目拆分成若干个微服务、单独维护、单独部署,也可以降低项目不同业务间的耦合度。推荐书籍「Spring Cloud 与 Docker 微服务架构实战」,这本书将 Docker 与微服务完美地结合在一起,堪称完美!Spring Cloud 中文官网史上最简单的 Spring Cloud 教程我写的有关于 Spring Cloud 的博客:SpringCloud微服务架构之服务注册与发现SpringCloud微服务架构之服务消费者SpringCloud微服务架构之断路器SpringCloud微服务架构之服务网关其它技术Redis:一个高性能的 key-value 数据库,当有并发量很高的请求时,将数据缓存在 Redis 中,将提高服务器的响应性能,大大减轻数据库的压力。redis 中文官网redis 教程Git:世界上最先进的分布式版本控制系统,建议所有初学者从命令行开始使用 Git!Git 官网最全 Git 教程Git 的一些常用命令Maven:一个用于构建项目的工具,将项目间的依赖通过 xml 完美地组织到一起,可通过编译插件将项目编译成字节码文件。还有类似的 Gradle 也是不错的选择。maven 的 pom.xml 文件详解Linux:至少要求常用的命令会用,能够在 linux 环境下部署项目。Linux 命令大全最全的 SSH 连接远程终端教程Docker:简直是项目部署神器啊,来不及解释了,看我 Docker 系列博客,开启 Docker 之旅吧!推荐书籍「Docker 技术入门与实战」,中国首部 Docker 著作!Docker 实战(一)Docker 实战(二)Docker 实战(三)docker-deploy-tutorial开发工具工欲善其事,必先利其器,以下是我推荐的一些开发工具:Intellij IDEA:Java 开发最好的 IDE,这个是公认的,我一开始是用 Eclipse 的,后来用了 Intellij IDEA,才发现 Eclipse 就是一坨屎,所以我以过来人劝你们不要使用 Eclipse,直接 Intellij IDEA!IntelliJ IDEA 使用教程Iterm2:macOS 最好用的终端!Iterm2 使用指南Chrome:人生苦短,请用 Chrome,来不及解释了,快上车!Postman:很好用的一个接口调试工具。Postman 官网我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
基础并发编程的模型分类在并发编程需要处理的两个关键问题是:线程之间如何通信 和 线程之间如何同步。通信通信 是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存 和 消息传递。在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。同步同步 是指程序用于控制不同线程之间操作发生相对顺序的机制。在共享内存的并发模型里,同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。Java 的并发采用的是共享内存模型,Java 线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。JAVA 内存模型的抽象在 Java 中,所有实例域、静态域 和 数组元素存储在堆内存中,堆内存在线程之间共享。局部变量、方法定义参数 和 异常处理器参数 不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。Java 线程之间的通信由 Java 内存模型(JMM)控制。JMM 决定了一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM 定义了线程与主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每一个线程都有一个自己私有的本地内存,本地内存中存储了该变量以读/写共享变量的副本。本地内存是 JMM 的一个抽象概念,并不真实存在。JMM 抽象示意图:从上图来看,如果线程 A 和线程 B 要通信的话,要如下两个步骤:1、线程 A 需要将本地内存 A 中的共享变量副本刷新到主内存去2、线程 B 去主内存读取线程 A 之前已更新过的共享变量步骤示意图:举个例子:本地内存 A 和 B 有主内存共享变量 X 的副本。假设一开始时,这三个内存中 X 的值都是 0。线程 A 正执行时,把更新后的 X 值(假设为 1)临时存放在自己的本地内存 A 中。当线程 A 和 B 需要通信时,线程 A 首先会把自己本地内存 A 中修改后的 X 值刷新到主内存去,此时主内存中的 X 值变为了 1。随后,线程 B 到主内存中读取线程 A 更新后的共享变量 X 的值,此时线程 B 的本地内存的 X 值也变成了 1。整体来看,这两个步骤实质上是线程 A 再向线程 B 发送消息,而这个通信过程必须经过主内存。JMM 通过控制主内存与每个线程的本地内存之间的交互,来为 Java 程序员提供内存可见性保证。重排序在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三类:1、编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。2、指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。3、内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。从 Java 源代码到最终实际执行的指令序列,会分别经历下面三种重排序:上面的这些重排序都可能导致多线程程序出现内存可见性问题。对于编译器,JMM 的编译器重排序规则会禁止特定类型的编译器重排序(不是所有的编译器重排序都要禁止)。对于处理器重排序,JMM 的处理器重排序规则会要求 Java 编译器在生成指令序列时,插入特定类型的内存屏障指令,通过内存屏障指令来禁止特定类型的处理器重排序(不是所有的处理器重排序都要禁止)。JMM 属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。处理器重排序现代的处理器使用写缓冲区来临时保存向内存写入的数据。写缓冲区可以保证指令流水线持续运行,它可以避免由于处理器停顿下来等待向内存写入数据而产生的延迟。同时,通过以批处理的方式刷新写缓冲区,以及合并写缓冲区中对同一内存地址的多次写,可以减少对内存总线的占用。虽然写缓冲区有这么多好处,但每个处理器上的写缓冲区,仅仅对它所在的处理器可见。这个特性会对内存操作的执行顺序产生重要的影响:处理器对内存的读/写操作的执行顺序,不一定与内存实际发生的读/写操作顺序一致!举个例子:假设处理器A和处理器B按程序的顺序并行执行内存访问,最终却可能得到 x = y = 0。具体的原因如下图所示:处理器 A 和 B 同时把共享变量写入在写缓冲区中(A1、B1),然后再从内存中读取另一个共享变量(A2、B2),最后才把自己写缓冲区中保存的脏数据刷新到内存中(A3、B3)。当以这种时序执行时,程序就可以得到 x = y = 0 的结果。从内存操作实际发生的顺序来看,直到处理器 A 执行 A3 来刷新自己的写缓存区,写操作 A1 才算真正执行了。虽然处理器 A 执行内存操作的顺序为:A1 -> A2,但内存操作实际发生的顺序却是:A2 -> A1。此时,处理器 A 的内存操作顺序被重排序了。这里的关键是,由于写缓冲区仅对自己的处理器可见,它会导致处理器执行内存操作的顺序可能会与内存实际的操作执行顺序不一致。由于现代的处理器都会使用写缓冲区,因此现代的处理器都会允许对写-读操作重排序。内存屏障指令为了保证内存可见性,Java 编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序。JMM 把内存屏障指令分为下列四类:屏障类型指令示例说明LoadLoad BarriersLoad1; LoadLoad; Load2确保 Load1 数据的装载,之前于 Load2 及所有后续装载指令的装载。StoreStore BarriersStore1; StoreStore; Store2确保 Store1 数据对其他处理器可见(刷新到内存),之前于 Store2 及所有后续存储指令的存储。LoadStore BarriersLoad1; LoadStore; Store2确保 Load1 数据装载,之前于 Store2 及所有后续的存储指令刷新到内存。StoreLoad BarriersStore1; StoreLoad; Load2确保 Store1 数据对其他处理器变得可见(指刷新到内存),之前于 Load2 及所有后续装载指令的装载。StoreLoadBarriers 会使该屏障之前的所有内存访问指令(存储和装载指令)完成之后,才执行该屏障之后的内存访问指令。HAPPENS-BEFOREJSR-133 内存模型使用 happens-before 的概念来阐述操作之间的内存可见性。在 JMM 中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在 happens-before 关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。与程序员密切相关的 happens-before 规则如下:程序顺序规则:一个线程中的每个操作,happens-before 于该线程中的任意后续操作。监视器锁规则:对一个监视器的解锁,happens-before 于随后对这个监视器的加锁。volatile 变量规则:对一个 volatile 域的写,happens-before 于任意后续对这个 volatile 域的读。传递性:如果 A happens-before B,且 B happens-before C,那么 A happens-before C。注意,两个操作之间具有 happens-before 关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before 仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)。happens-before 与 JMM 的关系如下图所示:如上图所示,一个 happens-before 规则对应于一个或多个编译器和处理器重排序规则。数据依赖性如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型:名称代码示例说明写后读a = 1; b = a;写一个变量之后,再读这个位置。写后写a = 1; a = 2;写一个变量之后,再写这个变量。读后写a = b; b = 1;读一个变量之后,再写这个变量。上面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变。前面提到过,编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。注意,这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。AS-IF-SERIAL 语义as-if-serial 语义的意思指:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守 as-if-serial 语义。为了遵守 as-if-serial 编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是如果操作之间没有数据依赖关系,这些操作就可能被编译器和处理器重排序。举个例子:double pi = 3.14; //Adouble r = 1.0; //Bdouble area = pi * r * r; //C上面三个操作的数据依赖关系如下图所示:如上图所示,A 和 C 之间存在数据依赖关系,同时 B 和 C 之间也存在数据依赖关系。因此在最终执行的指令序列中,C 不能被重排序到 A 和 B 的前面(C 排到 A 和 B 的前面,程序的结果将会被改变)。但 A 和 B 之间没有数据依赖关系,编译器和处理器可以重排序 A 和 B 之间的执行顺序。下图是该程序的两种执行顺序:在计算机中,软件技术和硬件技术有一个共同的目标:在不改变程序执行结果的前提下,尽可能的开发并行度。编译器和处理器遵从这一目标,从 happens-before 的定义我们可以看出,JMM 同样遵从这一目标。重排序对多线程的影响举例:class Demo {int a = 0;boolean flag = false;public void write() {a = 1; //1flag = true; //2}public void read() {if(flag) { //3int i = a * a; //4}}}由于操作 1 和 2 没有数据依赖关系,编译器和处理器可以对这两个操作重排序;操作 3 和操作 4 没有数据依赖关系,编译器和处理器也可以对这两个操作重排序。1、当操作 1 和操作 2 重排序时,可能会产生什么效果?如上图所示,操作 1 和操作 2 做了重排序。程序执行时,线程 A 首先写标记变量 flag,随后线程 B 读这个变量。由于条件判断为真,线程 B 将读取变量 a。此时,变量 a 还根本没有被线程 A 写入,在这里多线程程序的语义被重排序破坏了!2、当操作 3 和操作 4 重排序时会产生什么效果(借助这个重排序,可以顺便说明控制依赖性)。在程序中,操作 3 和操作 4 存在控制依赖关系。当代码中存在控制依赖性时,会影响指令序列执行的并行度。为此,编译器和处理器会采用猜测(Speculation)执行来克服控制相关性对并行度的影响。以处理器的猜测执行为例,执行线程 B 的处理器可以提前读取并计算 a * a,然后把计算结果临时保存到一个名为重排序缓冲(reorder buffer ROB)的硬件缓存中。当接下来操作 3 的条件判断为真时,就把该计算结果写入变量 i 中。从图中我们可以看出,猜测执行实质上对操作3和4做了重排序。重排序在这里破坏了多线程程序的语义!在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果(这也是 as-if-serial 语义允许对存在控制依赖的操作做重排序的原因);但在多线程程序中,
Java知识点汇总,从基础到常用的API、还有常用的集合类,总结的很详细。图片是从论坛里面找到的,整理下来以便常复习。这是目前看到的比较详细完整的思维导图。1.Java基础知识 2.面向对象 3.常用API 4.集合IO 5.多线程、网络编程、反射、设计模式 我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
摘要: 以架构师的眼光来讲述高并发架构前言高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等。为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适合自己业务场景的高并发处理方案。在电商相关产品开发的这些年,我有幸的遇到了并发下的各种坑,这一路摸爬滚打过来有着不少的血泪史,这里进行的总结,作为自己的归档记录,同时分享给大家。服务器架构业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。 一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序流畅运行的强大后盾。服务器这块多是需要运维人员来配合搭建,具体我就不多说了,点到为止。大致需要用到的服务器架构如下:服务器均衡负载(如:nginx,阿里云SLB)资源监控分布式数据库主从分离,集群DBA 表优化,索引优化,等分布式nosqlredis主从分离,集群mongodb主从分离,集群memcache主从分离,集群cdnhtmlcssjsimage并发测试高并发相关的业务,需要进行并发的测试,通过大量的数据分析评估出整个架构可以支撑的并发量。测试高并发可以使用第三方服务器或者自己测试服务器,利用测试工具进行并发请求测试,分析测试数据得到可以支撑并发数量的评估,这个可以作为一个预警参考,俗话说知己自彼百战不殆。第三方服务:阿里云性能测试并发测试工具:Apache JMeterVisual Studio性能负载测试Microsoft Web Application Stress Tool实战方案通用方案日用户流量大,但是比较分散,偶尔会有用户高聚的情况;场景: 用户签到,用户中心,用户订单,等服务器架构图: 说明:场景中的这些业务基本是用户进入APP后会操作到的,除了活动日(618,双11,等),这些业务的用户量都不会高聚集,同时这些业务相关的表都是大数据表,业务多是查询操作,所以我们需要减少用户直接命中DB的查询;优先查询缓存,如果缓存不存在,再进行DB查询,将查询结果缓存起来。更新用户相关缓存需要分布式存储,比如使用用户ID进行hash分组,把用户分布到不同的缓存中,这样一个缓存集合的总量不会很大,不会影响查询效率。方案如:用户签到获取积分计算出用户分布的key,redis hash中查找用户今日签到信息如果查询到签到信息,返回签到信息如果没有查询到,DB查询今日是否签到过,如果有签到过,就把签到信息同步redis缓存。如果DB中也没有查询到今日的签到记录,就进行签到逻辑,操作DB添加今日签到记录,添加签到积分(这整个DB操作是一个事务)缓存签到信息到redis,返回签到信息注意这里会有并发情况下的逻辑问题,如:一天签到多次,发放多次积分给用户。我的博文[大话程序猿眼里的高并发]有相关的处理方案。用户订单这里我们只缓存用户第一页的订单信息,一页40条数据,用户一般也只会看第一页的订单数据用户访问订单列表,如果是第一页读缓存,如果不是读DB计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户订单信息,返回订单信息如果不存在就进行DB查询第一页的订单数据,然后缓存redis,返回订单信息用户中心计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户信息,返回用户信息如果不存在进行用户DB查询,然后缓存redis,返回用户信息其他业务上面例子多是针对用户存储缓存,如果是公用的缓存数据需要注意一些问题,如下注意公用的缓存数据需要考虑并发下的可能会导致大量命中DB查询,可以使用管理后台更新缓存,或者DB查询的锁住操作。我的博文[大话Redis进阶]对更新缓存问题和推荐方案的分享。以上例子是一个相对简单的高并发架构,并发量不是很高的情况可以很好的支撑,但是随着业务的壮大,用户并发量增加,我们的架构也会进行不断的优化和演变,比如对业务进行服务化,每个服务有自己的并发架构,自己的均衡服务器,分布式数据库,nosql主从集群,如:用户服务、订单服务;消息队列秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求场景:定时领取红包,等服务器架构图:说明:场景中的定时领取是一个高并发的业务,像秒杀活动用户会在到点的时间涌入,DB瞬间就接受到一记暴击,hold不住就会宕机,然后影响整个业务;像这种不是只有查询的操作并且会有高并发的插入或者更新数据的业务,前面提到的通用方案就无法支撑,并发的时候都是直接命中DB;设计这块业务的时候就会使用消息队列的,可以将参与用户的信息添加到消息队列中,然后再写个多线程程序去消耗队列,给队列中的用户发放红包;方案如:定时领取红包一般习惯使用 redis的 list当用户参与活动,将用户参与信息push到队列中然后写个多线程程序去pop数据,进行发放红包的业务这样可以支持高并发下的用户可以正常的参与活动,并且避免数据库服务器宕机的危险附加: 通过消息队列可以做很多的服务。 如:定时短信发送服务,使用sset(sorted set),发送时间戳作为排序依据,短信数据队列根据时间升序,然后写个程序定时循环去读取sset队列中的第一条,当前时间是否超过发送时间,如果超过就进行短信发送。一级缓存高并发请求连接缓存服务器超出服务器能够接收的请求连接量,部分用户出现建立连接超时无法读取到数据的问题;因此需要有个方案当高并发时候时候可以减少命中缓存服务器;这时候就出现了一级缓存的方案,一级缓存就是使用站点服务器缓存去存储数据,注意只存储部分请求量大的数据,并且缓存的数据量要控制,不能过分的使用站点服务器的内存而影响了站点应用程序的正常运行,一级缓存需要设置秒单位的过期时间,具体时间根据业务场景设定,目的是当有高并发请求的时候可以让数据的获取命中到一级缓存,而不用连接缓存nosql数据服务器,减少nosql数据服务器的压力比如APP首屏商品数据接口,这些数据是公共的不会针对用户自定义,而且这些数据不会频繁的更新,像这种接口的请求量比较大就可以加入一级缓存;服务器架构图:合理的规范和使用nosql缓存数据库,根据业务拆分缓存数据库的集群,这样基本可以很好支持业务,一级缓存毕竟是使用站点服务器缓存所以还是要善用。静态化数据高并发请求数据不变化的情况下如果可以不请求自己的服务器获取数据那就可以减少服务器的资源压力。对于更新频繁度不高,并且数据允许短时间内的延迟,可以通过数据静态化成JSON,XML,HTML等数据文件上传CDN,在拉取数据的时候优先到CDN拉取,如果没有获取到数据再从缓存,数据库中获取,当管理人员操作后台编辑数据再重新生成静态文件上传同步到CDN,这样在高并发的时候可以使数据的获取命中在CDN服务器上。CDN节点同步有一定的延迟性,所以找一个靠谱的CDN服务器商也很重要其他方案对于更新频繁度不高的数据,APP,PC浏览器,可以缓存数据到本地,然后每次请求接口的时候上传当前缓存数据的版本号,服务端接收到版本号判断版本号与最新数据版本号是否一致,如果不一样就进行最新数据的查询并返回最新数据和最新版本号,如果一样就返回状态码告知数据已经是最新。减少服务器压力:资源、带宽分层,分割,分布式大型网站要很好支撑高并发,这是需要长期的规划设计 在初期就需要把系统进行分层,在发展过程中把核心业务进行拆分成模块单元,根据需求进行分布式部署,可以进行独立团队维护开发。分层将系统在横向维度上切分成几个部分,每个部门负责一部分相对简单并比较单一的职责,然后通过上层对下层的依赖和调度组成一个完整的系统比如把电商系统分成:应用层,服务层,数据层。(具体分多少个层次根据自己的业务场景)应用层:网站首页,用户中心,商品中心,购物车,红包业务,活动中心等,负责具体业务和视图展示服务层:订单服务,用户管理服务,红包服务,商品服务等,为应用层提供服务支持数据层:关系数据库,nosql数据库 等,提供数据存储查询服务分层架构是逻辑上的,在物理部署上可以部署在同一台物理机器上,但是随着网站业务的发展,必然需要对已经分层的模块分离部署,分别部署在不同的服务器上,使网站可以支撑更多用户访问分割在纵向方面对业务进行切分,将一块相对复杂的业务分割成不同的模块单元包装成高内聚低耦合的模块不仅有助于软件的开发维护,也便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展比如用户中心可以分割成:账户信息模块,订单模块,充值模块,提现模块,优惠券模块等分布式分布式应用和服务,将分层或者分割后的业务分布式部署,独立的应用服务器,数据库,缓存服务器当业务达到一定用户量的时候,再进行服务器均衡负载,数据库,缓存主从集群分布式静态资源,比如:静态资源上传cdn分布式计算,比如:使用hadoop进行大数据的分布式计算分布式数据和存储,比如:各分布节点根据哈希算法或其他算法分散存储数据网站分层-图1来自网络集群对于用户访问集中的业务独立部署服务器,应用服务器,数据库,nosql数据库。 核心业务基本上需要搭建集群,即多台服务器部署相同的应用构成一个集群,通过负载均衡设备共同对外提供服务, 服务器集群能够为相同的服务提供更多的并发支持,因此当有更多的用户访问时,只需要向集群中加入新的机器即可, 另外可以实现当其中的某台服务器发生故障时,可以通过负载均衡的失效转移机制将请求转移至集群中其他的服务器上,因此可以提高系统的可用性应用服务器集群nginx 反向代理slb… …(关系/nosql)数据库集群主从分离,从库集群通过反向代理均衡负载-图2来自网络异步在高并发业务中如果涉及到数据库操作,主要压力都是在数据库服务器上面,虽然使用主从分离,但是数据库操作都是在主库上操作,单台数据库服务器连接池允许的最大连接数量是有限的 当连接数量达到最大值的时候,其他需要连接数据操作的请求就需要等待有空闲的连接,这样高并发的时候很多请求就会出现connection time out 的情况 那么像这种高并发业务我们要如何设计开发方案可以降低数据库服务器的压力呢?如:自动弹窗签到,双11跨0点的时候并发请求签到接口双11抢红包活动双11订单入库等设计考虑:逆向思维,压力在数据库,那业务接口就不进行数据库操作不就没压力了数据持久化是否允许延迟?如何让业务接口不直接操作DB,又可以让数据持久化?方案设计:像这种涉及数据库操作的高并发的业务,就要考虑使用异步了客户端发起接口请求,服务端快速响应,客户端展示结果给用户,数据库操作通过异步同步如何实现异步同步?使用消息队列,将入库的内容enqueue到消息队列中,业务接口快速响应给用户结果(可以温馨提示高峰期延迟到账)然后再写个独立程序从消息队列dequeue数据出来进行入库操作,入库成功后刷新用户相关缓存,如果入库失败记录日志,方便反馈查询和重新持久化这样一来数据库操作就只有一个程序(多线程)来完成,不会给数据带来压力补充:消息队列除了可以用在高并发业务,其他只要有相同需求的业务也是可以使用,如:短信发送中间件等高并发下异步持久化数据可能会影响用户的体验,可以通过可配置的方式,或者自动化监控资源消耗来切换时时或者使用异步,这样在正常流量的情况下可以使用时时操作数据库来提高用户体验异步同时也可以指编程上的异步函数,异步线程,在有的时候可以使用异步操作,把不需要等待结果的操作放到异步中,然后继续后面的操作,节省了等待的这部分操作的时间缓存高并发业务接口多数都是进行业务数据的查询,如:商品列表,商品信息,用户信息,红包信息等,这些数据都是不会经常变化,并且持久化在数据库中高并发的情况下直接连接从库做查询操作,多台从库服务器也抗不住这么大量的连接请求数(前面说过,单台数据库服务器允许的最大连接数量是有限的)那么我们在这种高并发的业务接口要如何设计呢?设计考虑:还是逆向思维,压力在数据库,那么我们就不进行数据库查询数据不经常变化,我们为啥要一直查询DB?数据不变化客户端为啥要向服务器请求返回一样的数据?方案设计:数据不经常变化,我们可以把数据进行缓存,缓存的方式有很多种,一般的:应用服务器直接Cache内存,主流的:存储在memcache、redis内存数据库Cache是直接存储在应用服务器中,读取速度快,内存数
总结的很粗糙,以后时间富裕了好好修改一下。1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流),或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或者Writer(字符输出流)的子类。【首先需要明白的是:流是干什么的???(为了永久性的保存数据)  根据数据流向的不同分为输入流和输出流;  根据处理数据类型的不同分为字符流和字节流;】【然后需要明白的是输入模式和输出模式是谁流向谁:InputStream(字节输入流)和Reader(字符输入流)通俗的理解都是读(read)的。OutputStream(字节输出流)和Writer(字符输出流)通俗的理解都是写(writer)的。】最后下面搞清楚各种流的类型的该怎么用,谁包含谁,理清思路。2:InputStream类是字节输入流的抽象类,是所有字节输入流的父类,InputStream类具有层次结构如下图所示;3:java中的字符是Unicode编码的,是双字节的。InputStream是用来处理字节的,在处理字符文本时很不方便。Java为字符文本的输入提供了专门的一套类Reader。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。4:输出流OutputStream类是字节输入流的抽象类,此抽象类表示输出字节流的所有类的超类。5:Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。6:File类是IO包中唯一代表磁盘文件本身的对象。通过File来创建,删除,重命名文件。File类对象的主要作用就是用来获取文本本身的一些信息。如文本的所在的目录,文件的长度,读写权限等等。(有的需要记忆,比如isFile(),isDirectory(),exits();有的了解即可。使用的时候查看API)详细如下:File类(File类的概述和构造方法)A:File类的概述File更应该叫做一个路径文件路径或者文件夹路径路径分为绝对路径和相对路径绝对路径是一个固定的路径,从盘符开始相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下查看API指的是当前路径文件和目录路径名的抽象表示形式B:构造方法File(String pathname):根据一个路径得到File对象File(String parent, String child):根据一个目录和一个子文件/目录得到File对象File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象 File类(File类的创建功能)A:创建功能public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来(使用createNewFile()文件创建的时候不加.txt或者其他后缀也是文件,不是文件夹;使用mkdir()创建文件夹的时候,如果起的名字是比如aaa.txt也是文件夹不是文件;)注意事项:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。 File类(File类的重命名和删除功能)A:重命名和删除功能public boolean renameTo(File dest):把文件重命名为指定的文件路径public boolean delete():删除文件或者文件夹B:重命名注意事项如果路径名相同,就是改名。如果路径名不同,就是改名并剪切。C:删除注意事项:Java中的删除不走回收站。要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹 File类(File类的判断功能)A:判断功能public boolean isDirectory():判断是否是目录public boolean isFile():判断是否是文件public boolean exists():判断是否存在public boolean canRead():判断是否可读public boolean canWrite():判断是否可写public boolean isHidden():判断是否隐藏 File类(File类的获取功能)A:获取功能public String getAbsolutePath():获取绝对路径public String getPath():获取路径public String getName():获取名称public long length():获取长度。字节数public long lastModified():获取最后一次的修改时间,毫秒值public String[] list():获取指定目录下的所有文件或者文件夹的名称数组public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组 File类(文件名称过滤器的概述及使用)A:文件名称过滤器的概述public String[] list(FilenameFilter filter)public File[] listFiles(FileFilter filter) 1 package com.ningmeng;23 import java.io.File;45 public class Test {67 public static void main(String[] args) throws Exception{8 // TODO Auto-generated method stub9 File file=new File("aa.txt");//文件默认就创建在你创建的项目下面,刷新即可看到10 System.out.println(file.exists());//判断文件是否存在11 file.createNewFile();//创建文件,不是文件夹12 System.out.println(file.exists());//再次判断是否存在13 System.out.println(file.getName());//获取文件的名字14 System.out.println(file.getAbsolutePath());//获取文件的绝对路径15 System.out.println(file.getPath());//获取文件的相对路径16 System.out.println(file.getParent());//获取文件的父路径17 System.out.println(file.canRead());//文件是否可读18 System.out.println(file.canWrite());//文件是否可写19 System.out.println(file.length());//文件的长度20 System.out.println(file.lastModified());//文件最后一次修改的时间21 System.out.println(file.isDirectory());//判断文件是否是一个目录22 System.out.println(file.isHidden());//文件是否隐藏23 System.out.println(file.isFile());//判断文件是否存在24 }2526 }public String[] list():获取指定目录下的所有文件或者文件夹的名称数组public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组list()获取某个目录下所有的文件或者文件夹:1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("D:/");//指定文件目录9 String[] str=file.list();//获取指定目录下的所有文件或者文件夹的名称数组10 for(String s : str){//加强for循环遍历输出11 System.out.println(s);12 }1314 }15 }1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("D:/");//指定文件路径9 File[] f=file.listFiles();//获取指定目录下的所有文件或者文件夹的File数组10 for(File fi : f){//加强for循环遍历输出11 System.out.println(fi);12 }1314 }15 }案例演示:获取某种格式的文件比如获取某种后缀的图片,并输出文件名:1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("C:\Users\biehongli\Pictures\xuniji");9 String[] str=file.list();1011 for(String s : str){12 if(s.endsWith(".jpg") || s.endsWith(".png")){//如果后缀是这种格式的就输出13 System.out.println(s);14 }15 }161718 }19 }下面演示获取文件夹下面子目录里面的文件获取(并没有完全获取子目录的子目录等等,仅仅获取了子一级目录):1 package com.ningmeng;23 import java.io.File;45 public class FileTest {67 public static void main(String[] args){8 File file=new File("C:\Users\biehongli\Pictures\Camera Roll");910 File[] f=file.listFiles();1112 for(File fi : f){13 if(fi.isDirectory()){//判断如果是一个目录14 String[] s=fi.list();15 for(String str : s){16 if(str.endsWith(".jpg")){17
回头看看, 我进入Java 领域已经快15个年头了, 虽然学的也一般, 但是分享下我的心得,估计也能帮大家少走点弯路。[入门]我在2001年之前是C/C++阵营, 有C和面向对象的基础, 后来转到Java ,发现没有指针的Java真是好简单, 另外Java 的类库好用的让人哭啊。后来我就看《Thinking in Java》 ,《 Java 核心技术 》, 感觉也不吃力。如果我之前没学过别的语言,或者半路出家转到计算机行业, 我不会先看上面那两本, 相反我会选《Head First Java》, 这本书非常适合零基础的小白, 读起来轻松搞笑, 不信你看看第一页但是光看书也挺无趣的,不妨和视频结合着看, 我觉得传智播客的Java基础视频很不错 (唉, 给传智打了个广告), 网上一搜就有,真搜不到就来我的公众号获取吧(Java团长)注意:视频的好处就是能看到敲代码的过程, 代码是活的, 这点很爽。 如果视频只是按PPT讲编程, 果断扔掉。书也有书的好处,能写成书的, 肯定是作者经过系统化思考,梳理才能形成的东西, 所以系统性比较强。书还有其他优点, 例如可以随便的翻, 找到重点反复的看。所以混合着看经典书+优秀的视频 应该是最好的入门。Java 入门, 我不会去上培训班,白白浪费钱 ,自学就够了。自学过程中如果有实战经验丰富的高人指导一下, 给我绘出路线图, 指出攀登的方向,哪些地方有陷阱, 哪些地方不应该浪费时间, 我的自学就可以减少摸索,少走弯路,很不幸, 我当年没有遇到, 如果时光倒流, 我会想办法找一个来指导我。[实践]软件行业的一大特点就是光看不做永远都学不会,编码不到10万行都不好意思出去打招呼。所以实践,实践,实践!在校期间,我还是会尽可能的去找项目做(参见我的另一篇文章《从现在开始丰富你的简历》, 回复“简历”查看) , 实在没找到,也可以先把基础打好我上大学的时候用的是严蔚敏的《数据结构》, 当时我也把习题都做了一遍,考高级程序员的时候, 成绩非常好。后来我知道了一本更好的算法入门书《算法》, 如果时光能够重来, 我还是会这本书上提到的所有数据结构和算法用Java 都实现一遍, 课后作业也争取都做一遍。这是个非常重要的训练,因为我知道, 真的做了, 就会发现工作以后只要不是设计算法, 基本的数据结构没有能难住我的。【Java SE】对于Java集合框架, 不但要学会用, 我还会尝试着实现一遍,List, ArrayList, Set ,HashSet, Map ,HashSet 等等, 要是不知道怎么写, 看看JDK的源码就可以了, 那里有最好的老师。实现一遍能更好的明白面向对象的设计, 接口,抽象类, 具体类的关系, 怎么分离职责,会学习到设计模式中的模板方法, Iterator 等 。值得一提的是Iterator, 很有趣, 我还清楚的记得那一年自己实现集合框架中 Iterator 的时候的激动心情啊 :-)在实现Java 集合框架的时候, 可以顺便把泛型也学了, 不学不行,要不然实现不了啊。Java 世界里,万事万物都是对象, 大家都知道封装,继承,多态, 但是仅仅了解这些只是入了门, 不可能做出真正的面向对象的程序。有一本经典的书《敏捷软件开发, 原则,模式,实践》,里边详细的讲解了一个薪水支付案例,是迄今为止最好的面向对象设计的例子我会用Java 把它实现一遍, 真正的体会一下OOD, 了解怎么才能把合适的责任分给合适的类, 什么叫面向接口而不是面向实现编程, 什么是优先使用组合而不是继承。对于Java线程, 重点还是理解概念, 因为我知道在以后的工作中(除非从事系统级编程) ,自己写线程/线程池的机会是非常罕见的,都被类库,框架给封装好了。所以重点是理解,看书的话就当然是《Java并发编程实战》 ,一大群大牛写的啊。对于Java IO, 我觉得架构设计的很优雅,典型的学院派, 可就是不太实用, 打开读取一个文件都得用装饰者模式包装来包装去, 太累了。项目实战中呢,也就是读取个property 文件, xml 文件。 我还是重点去理解概念和设计吧。不过自己写个简单的xml 解析器倒是不错。至于 AWT, Swing , 简单看看就行了, 我不会去深入研究, Java 是典型的服务器端的语言, 开发客户端程序的极少, 你想想, 你用Swing/AWT搞个桌面程序出来, 还得让客户装个JRE才能运行, 是不是有点过分 ? 据我所知,也即是银行的一些应用在用Swing ,AWT了。 有人可能说 Applet, 它曾经流行过, 现在早都没人用了。所以我不会在Swing和AWT上浪费时间。Java Reflection 看起来没有集合框架,线程,OO等那么耀眼, 但它可是很多框架(SSH) 的基础啊(回复“反射”查看相关文章), 先把基础学会,后面的Java EE得用到它。想真正的学好Java ,不了解Java 虚拟机怎么可能? 《深入理解Java 虚拟机》一定得看,看完的目标就是写个简单的Java 反编译器。【做个有素养的Java码农】我记得08的时候, 我的IBM经理说设计模式是必备技能, 不懂设计模式的我们不能要了。所以设计模式是必学, 其实Java里边用的非常多,简直就是设计模式的活教材, 工厂方法,单例,模板方法, 装饰者,责任链都有体现。当然我会去先看一下轻松的《Head First Design》, 《设计模式》的作者之一 Eric Gamma 都大力推荐, 绝对不容错过。又过了几年, 我的IBM经理又说,现在我们默认设计模式大家都会了, 敏捷实践是必备技能 !所以, JUnit 我得会, 重构我得会, TDD,持续集成这些最最基本的敏捷实践也得知道, 要不然会被人鄙视啊。作为一个有追求的Java码农, 我写代码的时候要遵循Java 的编码规范,例如类名首字母大写, 报名要小写, 方法名要首字母小写...等等。作为代码洁癖, 我受不了脏代码, 我会不断的打磨自己的代码,直到它像一个工艺品。Java 的最佳实践 《effective java》 怎么能错过? 里边满满的全是JDK的作者们总结出来的java 编程最佳用法。不过翻译的实在是不咋滴, 很多句子都得仔细的琢磨一下才知道什么意思, 所以我打算录一系列视频讲解一下,敬请期待。【Java EE】走了这么远, 终于来到Java EE了, Java 不就是写服务器端的Web应用的吗?我会自己写个Web程序, 可以考虑把上面提到的经典的薪水支付案例改造成Web 版, 用最基础的技术Servlet/jsp/jdbc 。然后 研究struts, 自己写个简单mvc框架, 在自己的Web 程序中用起来, 这叫吃自己的狗粮。然后研究Hibenete , 自己写个简单的OR mapping框架, 再吃一次自己的狗粮。然后读一下经典的书《J2EE development without EJB》 , 对,就是spring 的作者Rod Johnson写的, 它颠覆了大家对于重量级EJB的认识, 开启了新的时代。有了这本书的铺垫, 自己写个简化的依赖注入也不是难事, 写好后还是在自己的Web程序中用起来, 最后一次吃自己的狗粮。等你做了就知道, 所有这些,都依赖Java Reflection。再往后走, 就应该是找真正的项目做, 或者去找实习了, 那是另外一个话题了,以后再聊。【阅读代码】熟读唐诗三百首,不会作诗也会吟模仿是最好的学习! 多看看大牛们的代码是怎么写的, 潜移默化,自己的武功也能提高。我身边要是有个好师傅, 跟着他,看着他编程, 提高的该有多快啊。在学习Java SE和Java EE的同时, 我会读一下这些源代码:JDK中的 Java Collection 源码 : 老祖宗的东西绝对经典JUnit 源码 : 看看Eric Gamma 和 Kent beck 是怎么通过模式来创建系统的 (回复"JUnit"查看)SpringSide : 以Spring Framework为核心的,Pragmatic风格的JavaEE应用参考示例,是JavaEE世界中的主流技术选型,最佳实践的总结与演示。国人开发的,大力推荐一下。此外我还是会研究下本世纪初著名的Jive论坛, 虽然非常古老, 虽然源码学院派十足, 但简直是设计模式的大本营, 都是活生生的应用的例子里边有个用代理模式实现权限控制, 让我记忆犹新。另外如果有余力的,有兴趣的话, 当然可以阅读Struts, Spring, hibernate的源码, 甚至参与进去开发了。如何学习Java ,这是我这么多年来的感受, 也只是我的一家之谈。 欢迎和我交流 。学习编程从来就不是一件容易的事情, 不可能看看视频,看看书就学会, 需要大量的编程和实践。 编程虽然是极为辛苦的脑力和体力劳动, 但其中蕴含的创造的乐趣也是无与伦比的。 希望每个人都能够享受这个过程,乐在其中。我有一个微信公众号,经常会分享一些Java技术相关的干货。如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
从事近十年的 JavaEE 应用开发工作,现任阿里巴巴公司系统架构师。对分布式服务架构与大数据技术有深入研究,具有丰富的 B/S 架构开发经验与项目实战经验,擅长敏捷开发模式。国内开源软件推动者之一,Smart Framework 开源框架创始人。热爱技术交流,乐于分享自己的工作经验。著有《架构探险——从零开始写Java Web框架》一书。我的十年技术之路和大家介绍下我目前所从事的工作。我目前从事分布式服务架构的设计与开发工作,在阿里的大数据平台上进行应用程序开发。我们整个系统架构采用了“前后端分离”的思想,前端关注数据展现,后端关注数据生产,通过 REST服务将前后端整合起来,所有的应用都是无状态的,可以做到水平扩展。我们将整个系统拆分成许多“微服务”,服务之间通过统一的接口来调用,每个服务是通过容器技术进行隔离,此外服务可发布到统一的服务管理平台上,可通过该平台监控每个服务的运行状态与生命周期事件,并为服务调用者提供了服务发现的能力,可对服务进行平滑升级。阿里有许多优秀的中间件与基础服务,可以快速帮助我们搭建应用系统,而且这些技术在阿里内部全是开源的,大家可以通过源码和文档学习到很多有价值的经验。阿里也提供了浓厚的技术氛围,每位同学都非常专注于自己的工作领域,大家对工作一丝不苟,相互配合,方向一致。我是如何走上技术这条路的?2006 年大学毕业,我离开了母校武汉理工大学,在院长薛胜军老师的推荐下,我来到了上海,这个对于我来说非常陌生的地方。我有幸加入了一家名为“动量软件”的创业公司,这家公司的老板曾经是亚信科技的 CTO,他也是普元软件的创始人兼 CTO,他的名字叫黄柳青,他也是薛老师的大学同学。于是就这样,我的老板成为了我的老师,我习惯叫他黄老师,包括公司其他资深的同事也成为了我的老师,因为我很想他们身上学到更多有价值的东西。刚开始工作的时候我学习了什么是云计算?什么是 SaaS、PaaS、IaaS?我们花了三年时间开发了一款名为 ODE 的 PaaS 平台,让用户可以在该平台上量身定制自己的软件,最终为客户提供基于 SaaS 的产品。确实很骄傲,那时我们已经在做云了,只是没想到后来云会在中国得到这么好的市场,可能当时只有黄老师一个人想到了吧。在 2008 年,我为公司拿回了“第一桶金”,这也是我从程序员转向项目经理的里程碑。当时我带领团队远赴深圳,为国信证券公司开发经纪人管理系统,这个项目对于我个人而言却是一笔至高无上的财富,我开始学习如何与人打交道,如何做需求分析,如何将需求转变为技术,如何带领团队小伙伴一起工作。学到了太多太多,但我依然选择在我工作第四个年头里离开了动量软件,我刚加入动量软件的时候,公司只有 5 个人(包括老板和前台),当我离开动量软件的时候,公司已经有 200 人左右了。感谢黄老师!我在他身上学到了很多,他的思想和态度直到今天都还在影响着我。我的第二份工作还是选择了我最熟悉的证券金融行业,同样也是一家创业型公司,在这家公司里我担任了技术经理,管理了整个技术团队,从项目的售前到售后,我都亲自带领团队来完成。虽然在这家公司我只做了两年,但在这短短的时间里,我学会了如何提高开发效率、如何培养技术团队、如何选拔技术人才、如何建立企业文化。但最后我发现了一个问题,越是想做好,越是很难做好,为了做成一件事情需要做很多的尝试,做事情缺乏正确并有效的方法。回想我工作的前六年时间里,我一直都是在创业公司里成长,虽然可以快速学到东西,但似乎很难学到更加规范的做事方法。于是我选择了新的工作机会,来到了 TCL 通讯,这是一家相当大的公司,公司的研发管理流程来源于法国阿里卡特公司。我在公司担任 Java 架构师职位,也算是整个 Java 团队的技术负责人,虽然团队并不是特别地大。我在这家公司做了三年,学到了如何整合现有资源、如何按标准流程去做事、如何设计系统架构、如何进行异地工作、如何跨团队工作、如何用英文来沟通。说实话,当时我没有任何的工作压力,可以按时上下班,从来都不会加班。虽然自己空闲的时间很多,但我并没有选择去浪费时间,而是开始写点技术博客,也正是因为这些技术文章,才改变了我后续的职业发展道路。我清楚的记得,那是在 2013 年 9 月 1 日,我在开源中国网站发表了我人生的第一篇博文,这篇文章影响了我后续两年。其实说句心里话,当我第一次写这篇文章时,我心里是没底的,这个框架只是根据自己的理解做出来的一个设想,当时甚至连一行代码都没写过。我的想法是先将这个思想发表出来,让大家讨论起来,我会做一个决策,然后再亲自做具体实现,最后我会将实现过程通过博文的方式展现给大家,后续大家会对我的实现进行点评,我会基于大家的建议进行改善。整个开源过程正好与敏捷的思想是一致的,有效沟通、小步快跑、拥抱变化、不断改进。也许就是我的技术文章吸引了很多广大读者,这里面不排除想邀请我加入的其它公司。我在 2014 年离开了 TCL 通讯,加入了易传媒。为什么我要放弃如此舒适的工作环境,去加入一家还在不断拼搏的企业呢?其实我看到的是未来互联网的发展趋势,广告程序化交易以及广告与大数据的结合,未来最值钱的一定是数据。抱着这样的信心,我加入了易传媒,担任系统架构师职位。当时易传媒正处于技术转型的初期,需要将 .Net 全部迁移到 Java,这件事情对于我而言是非常有挑战的。我的做法是:第一步定义开发规范与流程,第二步培养核心技术人员,第三步分阶段进行改造。仅半年时间,我们所有的产品成功地迁移到了 Java 平台,结果出乎大家的想象。公司市场也非常不错,产品得到了业界的认可,订单数源源不断,大家每天都很忙碌,但却很开心。而易传媒的“易家人”企业文化,让我所感动,不管是核心技术部门还是其它支持性部门,大家就像一家人一样,你的事情就是我的事情。直到 2015 年初,阿里巴巴与易传媒建立了合作关系,两家公司进行了深度合作,易传媒公司与阿里妈妈事业部进行了整合,新阿里妈妈从此诞生了,于是我也成为了阿里巴巴的一员,目前负责阿里妈妈大数据品牌营销产品的系统架构工作。就在两家公司整合的过程中,我完成了人生中的处女作《架构探险 —— 从零开始写 Java Web 框架》这本书,目前该书正在各大网上书店售卖,我真心希望这本书能对一些想成为架构师的程序员们有所帮助,由于我个人水平有限,又是第一次写书,写得不好的地方还请大家多多包涵。上面提到,写博客给我带来的收获颇多,那么我来分享下技术人如何写博客,又应该以怎样的态度对待。我认为技术人员写博客需要注意以下几点:思路要清晰,文章要有明确的大纲与标题。对于实战类型的文章,需要分步骤来描述。多用短句,少用长句,能一句话说明白,就不用两句话。对于不太好理解的内容,最好能打比方来说明。文章末尾需要有总结,用最精辟的语言归纳出这篇文章的主要内容。写博客首先是对自己所学知识的一个总结,此外,也为其他读者提供了很好的教程,知识得到了广播与传递。技术一条不归路,选择了这条路从未有过放弃的想法。做了十年的技术,我从来都没有放弃过它,相反,我非常热爱它,因为我一直以来都很喜欢学习,希望能学到更多的东西,这样遇到了具体的技术问题,可以随时从自己积累的知识库中找到最佳的解决方案。此外,目前我在公司虽然不怎么写代码了,但我还是会利用自己工作闲暇之余写一点开源项目或者代码框架等。工作过很多大大小小的公司,那么公司最值钱的东西是什么呢?我认为是实实在在做事情的程序员们。他们虽然工资不高,每天坐在位置上敲着代码,在很多人眼中被称为“屌丝”或“宅男”,但我认为恰恰就是这些人,他们才是公司最有价值的人。他们有自己的理想,希望能够通过自己的努力,从中得到那一点点所谓的成就感;他们需要理解产品经理真正的意图,把想法变成现实,让产品真正落地;他们更容易把握细节,而这些细节往往决定着产品的命运与成败;他们突如其来的跳槽,对我们的项目的交付有直接的影响;他们在一起工作的气氛,能体现技术公司的文化与底蕴。由此看来,对程序员的重视是相当有必要的,我们需要关心每一位程序员的职业发展,让他们在团队里能够充分地发挥出自己的能力。我们也需要对他们倍加关注,挖掘出有能力、肯吃苦、敢担当的人,给他们更多的机会,让他们成为技术领袖。互联网技术公司需要大量这样的程序员:他们是一群有着技术信仰的人,他们是一群热爱编程的人,他们是一群不解决问题睡不好觉的人;他们不是打杂的,不是外包,更不是工具;他们不喜欢被忽悠,不喜欢被冷落,更不喜欢被驱动;他们需要尊重,需要培养,更需要激情!具体说说程序员需要具备哪些素质。我个人是这样理解真正的程序员的:深爱技术,一天不写代码手就会痒,就喜欢那种成就感;为了一个问题可以废寝忘食,有时会在梦中都能写代码;代码洁癖症患者,喜欢优雅代码,写代码就像写诗一样;善于分析问题,能快速看清问题的本质,并动手解决它;喜欢研究优秀源码,学习大师的杰作,善于归纳与总结;有自己的开源项目或技术博客,喜欢学习,更喜欢分享;会关注技术圈子的新闻动态,时常会参加线下技术沙龙;知道软件开发不是一个人在战斗,更需要的是团队协作;保持良好健康的心态,用一颗积极向上的心去拥抱变化。十年的职场之路坚持不易,分享下我的「IT 职场」经验。时光飞逝,我事业中第一个十年已然结束了。在这十年里,让我收获了很多,跟大家分享一下我在 IT 职场方面的一些个人经验,不一定对每个人都实用,请大家仅作参考吧。大家既然都是做技术的,那我们不妨先从技术这个话题开始说起吧。我要与大家分享的第一点经验就是:1. 把技术当成工具技术这东西,其实一点都不神秘,它只不过是一个工具,用这个工具可以帮助我们解决实际问题,就这么简单。我们每天在面对技术,市面上也有很多技术,真的没有必要把这些技术都拿过来学习一遍,然后想办法找个场景去应用它。如果真的这样做了,那么只能说明技术不是工具,而是玩具,技术不是这样玩的。我们应该从另一个角度来看待技术,不妨从自己的实际工作环境出发,现在需要什么,我们就学什么,而不要漫无目的的追求一些新技术。当然,对于新技术还是需要有所关注的,至少需要知道这个新技术是干什么用的,而且还要善于总结,将有价值的技术收集起来,以备将来使用,当需要使用的时候再来深入研究。人的精力是有限的,人的生命也是短暂的,要善于利用自己的时间,合理地学习技术。不要把技术看得那么重要,别把它当回事儿,把它当工具就行了,它就像我们写字的笔一样,用铅笔能写字,用钢笔一样能写字。作为一名技术人员,除了学习与应用技术以外,还需要为自己做一个正确的职业规划,清晰认识自己究竟属于哪种技术人才,是技术专家类型的,还是技术管理类型的。路到底该怎么走?需要自己做出决定。在我们职业路线上,最重要的人莫过于老板(我指的老板可以是公司大老板,也可以是自己的顶头上司),对待自己的老板,我也有一些经验:2. 把老板当成情人大家应该非常清楚,情人是需要浪漫的,浪漫是需要惊喜的。老板其实跟情人一样,也是需要惊喜的。我们做下属的,要懂得找到合适的机会给老板带来惊喜。我们跟情人谈情说爱,这是一种很好的沟通方式,可别忽略了跟老板“谈情说爱”,我们需要与老板保持良好的沟通,这种沟通并不仅仅是溜须拍马。讲一个真实的故事吧。记得曾经我的一位同事,技术非常好,做东西非常快,质量也很高,同事们都觉得他是牛人,但他从来都不懂得在老板面前表现自己,老板也只是觉得他是可以做事的,但升职加薪的事情往往总是不会优先考虑他。大家很定会问:怎样在老板面前表现自己呢?其实方法有很多,由于篇幅有限,我先提供三招吧:第一招:在给老板做程序演示的时候,不要只是单纯的演示,不妨先用一个 PPT,简单表达一下自己的解决方案,然后再做演示,这样效果会好很多。老板会认为自己是花了心思的,是想把事情做得更好的。第二招:把自己每天的工作简单记录一下,每周汇总一次,以邮件的形式发送给老板,让老板知道自己每天在做什么。每月写一篇本月工作总结与下月工作计划,同样发邮件给老板。年底可以写一个年终工作总结,打印出来,悄悄地放在老板的桌子上。第三招:借汇报工作为理由,定期请老板出去吃饭,制造面对面单独沟通的机会。在谈话过程中,强调自己愿意帮助老板分担工作压力。对待老板其实很简单,只要能帮他做事,又能让他开心,他基本上就搞定了。老板搞定了,自己的职业发展才会平步青云。但千万别忽略了还有一群人,他们或许是自己的团队战友,或许是自己的竞争对手,
Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。在大家看之前,我要先声明两点。1、由于我本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照搬。2、下面对于【第一部分】的推荐内容,目的是让你尽快成为一个可以参加工作的Java开发者,更适用于处于待业状态,准备转行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部分视频的选择,业界比较认可马士兵的视频,因此推荐给大家。当然了,我本人并没有看过他的视频,所以不好说的太绝对,如果大家自己有更好的选择,可以坚持自己的,不要被我干扰。最后一步,你需要学会使用数据库,mysql是个不错的入门选择,而且Java领域里主流的关系型数据库就是mysql。这部分一般在你学习Servlet/Jsp的时候,就会接触到的,其中的JDBC部分就是数据库相关的部分。你不仅要学会使用JDBC操作数据库,还要学会使用数据库客户端工具,比如navicat,sqlyog,二选一即可。三、开发框架当你学会以上内容以后,这个时候你还不足以参加工作,你还需要继续深造。公司里为了提高开发的效率,会使用一些Java Web框架,因此你还需要学习一些开发框架。目前比较主流的是SSM框架,即spring、springmvc、mybatis。你需要学会这三个框架的搭建,并用它们做出一个简单的增删改查的Web项目。你可以不理解那些配置都是什么含义,以及为什么要这么做,这些留着后面你去了解。但你一定要可以快速的利用它们三个搭建出一个Web框架,你可以记录下你第一次搭建的过程,相信我,你一定会用到的。还要提一句的是,你在搭建SSM的过程中,可能会经常接触到一个叫maven的工具。这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识。在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的。四、找工作当你完成开发框架的学习以后,你就该找工作了,在校的找实习,毕业的找全职。与此同时,在找工作的同时,你不应该停下你的学习,准确的说,是你在以后都不能停下学习。上面这些内容你只是囫囵吞枣的学会了使用,你可以逐步尝试着去了解更多的东西,网络是你最重要的老师。第二部分:对于参加工作一年以内的同学。恭喜你,这个时候,你已经拥有了一份Java的工作。这个阶段是你成长极快的阶段,而且你可能会经常加班。但是加班不代表你就可以松懈了,永远记得我说的那句话,从你入行那一刻起,你就要不停的学习。在这一年里,你至少需要看完《Java编程思想》这本书。这本书的内容是帮助你对于Java有一个更加深入的了解,是Java基础的升级版。这本书很厚,当初看这本书,我花了整整三个月。正常速度的话,应该可以在半年左右看完。我这里不要求过高,只要你在一年以内把这本书看完即可。当然了,我所说的看完,是充分吸收,而不是读一遍就完事了,因此有些内容你可能会看不止一遍。总而言之,这个阶段的核心学习思想就是,在工作中实践,并且更加深入的了解Java基础。第三部分:对于参加工作1年到2年的同学。这部分时间段的同学,已经对Java有了一个更加深入的了解。但是对于面向对象的体会可能还不够深刻,编程的时候还停留在完成功能的层次,很少会去考虑设计的问题。于是这个时候,设计模式就来了。我当时看的是《大话设计模式》这本书,并且写了完整版的设计模式博客。因此,我要求大家,最多在你工作一年的时候,必须开始写博客,而设计模式就是你博客的开端。请记住,我所提的基本都是最低要求,因此不要有任何松懈的心理,否则五年后,你不要去羡慕别人高于你的工资,也不要去羡慕别人进入了某公司。这一年,你必须对于设计模式了如指掌,《大话设计模式》可以作为你的开端。此外,设计模式并不是你这一年唯一的任务,你还需要看一些关于代码编写优化的书。比如《重构 改善既有代码的设计》,《effective java》。总而言之,这个阶段,你的核心任务就是提高你的代码能力,要能写出一手优雅的代码。第四部分:对于参加工作2年到3年的同学有的同学在这个时候觉得自己已经很牛逼了,于是忍不住开始慢慢松懈。请记住,你还嫩的多。这个阶段,有一本书是你必须看的,它叫做《深入理解Java虚拟机》。这本书绝对是Java开发者最重要的书,没有之一。在我眼里,这本书的重要性还要高于《Java编程思想》。这本书的内容是帮助你全面的了解Java虚拟机,在这个阶段,你一定已经知道Java是运行在JVM之上的。所以,对于JVM,你没有任何理由不了解它。另外,在过去2年的工作当中,你肯定或多或少接触过并发。这个时候,你应该去更加深入的了解并发相关的知识,而这部分内容,我比较推荐《Java并发编程实战》这本书。只要你把这本书啃下来了,并发的部分基本已经了解了十之六七。与此同时,这个阶段你要做的事情还远不止如此。这个时候,你应该对于你所使用的框架应该有了更深入的了解,对于Java的类库也有了更深入的了解。因此,你需要去看一些JDK中的类的源码,也包括你所使用的框架的源码。这些源码能看懂的前提是,你必须对设计模式非常了解。否则的话,你看源码的过程中,永远会有这样那样的疑问,这段代码为什么要这么写?为什么要定义这个接口,它看起来好像很多余?由此也可以看出,这些学习的过程是环环相扣的,如果你任何一个阶段拉下来了,那么你就真的跟不上了,或者说是一步慢步步慢。而且我很负责的告诉你,我在这个阶段的时候,所学习的东西远多于这里所罗列出来的。因此千万不要觉得你已经学的很多了,我所说的这些都只是最低要求,不光是我,很多人在这个时间段所学习的内容都远超本文的范围。如果你不能跟上节奏的话,若干年后,如果不是程序猿市场还不错的话,你很可能不仅仅是工资比别人低,公司没别人好,而是根本就找不到工作。总而言之,这个阶段,你需要做的是深入了解Java底层和Java类库(比如并发那本书就是Java并发包java.concurrent的内容),也就是JVM和JDK的相关内容。而且还要更深入的去了解你所使用的框架,方式比较推荐看源码或者看官方文档。另外,还有一种学习的方式,在2年这个阶段,也应该启用了,那就是造轮子。不要听信那套“不要重复造轮子”的论调,那是公司为了节省时间成本编造出来的。重复造轮子或许对别人没有价值,因为你造的轮子可能早就有了,而且一般情况下你造出来的轮子还没有现存的好。但是对别人没有价值,不代表对你自己没有价值。一个造轮子的过程,是一个从无到有的过程。这个过程可以对你进行系统的锻炼,它不仅考察你的编码能力,还考察你的框架设计能力,你需要让你的轮子拥有足够好的扩展性、健壮性。而且在造轮子的过程中,你会遇到各种各样的难题,这些难题往往又是你学习的契机。当你把轮子造好的时候,你一定会发现,其实你自己收获了很多。所以,这个阶段,除了上面提到的了解JVM、JDK和框架源码以外,也请你根据别人优秀的源码,去造一个任何你能够想象出来的轮子。第五部分:参加工作3年到4年的同学这个阶段的同学,提升已经是很难了,而且这个阶段的学习往往会比较多样化。因为在前3年的过程中,你肯定或多或少接触过一些其它的技术,比如大数据、分布式缓存、分布式消息服务、分布式计算、软负载均衡等等。这些技术,你能精通任何一项,都将是你未来面试时巨大的优势,因此如果你对某一项技术感兴趣的话,这个时候可以深入去研究一下。这项技术不一定是你工作所用到的,但一定是相关的。而且在研究一门新技术时,切忌朝三暮四。有的同学今天去整整大数据,搞搞Hadoop、hbase一类的东西。过不了一段时间,就觉得没意思,又去研究分布式缓存,比如redis。然后又过不了一段时间,又去研究分布式计算,比如整整Mapreduce或者storm。结果到最后,搞得自己好像什么都会一样,在简历上大言不惭的写上大数据、分布式缓存、分布式计算都了解,其实任何一个都只是浮于表面。到时候面试官随便一问,就把你给识破了。一定要记住,作为一个程序猿,平日里所接触的技术可能会很多,但是想要让一门技术成为你的优势,那么一定是你对这门技术的了解强过绝大多数人才行。因此在这个阶段,你就不能再简单的去学习前3年的内容了,虽然前面的学习如果还不够深入的话依旧要继续,但这个时候你应该更多的考虑建立你的优势,也可以称为差异性。差异性相信不难理解,就是让你自己变得与众不同。你前面三年的学习足够你成为一名基本合格的Java开发者,但你离成为一名优秀的Java开发者还有很大的距离。所谓优秀,即能别人所不能。而你前三年所学习的内容,是很多做过几年的Java开发都能够掌握的。那么为了让自己有差异性,你就需要另辟蹊径,找一个方向深入研究下去,以期在将来,你能够成为这个领域的专家,比如分布式计算领域的专家,大数据领域的专家,并发领域的专家等等。此外,你除了建立你的差异性之外,还要去弥补你基础上的不足,直到现在,我都没有提及基础知识。原因是基础是很枯燥无味的,学的太早不仅容易懵逼,而且懵逼的同时还容易产生心理阴影,以至于以后再不想去研究这些基础。但基础又是你深入研究一些领域时所必须掌握的,比如你去研究分布式计算,你不懂算法你玩个毛毛?比如你去做分布式缓存,你对计算机系统的内存不了解,你如何去做缓存?如果你的基础本来就非常强,那么恭喜你,相信你在之前的工作中已经充分体会到了这些基础对你的帮助。但我相信大部分人的基础都很薄弱,哪怕是科班毕业的人,很多人也不敢说自己当初的基础学的多么强大,比如算法、计算机系统原理、编译原理这些。但是每个人时间都是有限的,而且这些基础的书籍每一本读下来,没个一年半载的,还真拿不下来,因此还是要有所抉择的。虽然艺多不压身,但问题是艺多是有代价的,是需要你付出时间和精力的,而我个人更赞成在同等代价的情况下获取最大的收获。首先,我比较推崇的基础书籍有三本,分别是《深入理解计算机系统》,《tcp/ip详解 卷一、二、三》,《数据结构与算法》。其中TCP/IP有三本书,但我们
快速排序概述快速排序算法借鉴的是二叉树前序遍历的思想,最终对数组进行排序。优点:对于数据量比较大的数组排序,由于采用的具有二叉树二分的思想,故排序速度比较快局限只适用于顺序存储结构的数据排序(数组 ,ArrayList等),不适用于链式的数据结构算法实现思路一.将目标数组转化为这样一个数组。数组中的某个位置左边的所有数据都比该位置的数据小,该位置右边的数据都比该位置数据大。实现思路:1.取出数组第0个数据  2.从数组最右边开始遍历,如果遍历位置的数据比第0个位置的数据小,将该位置的数据赋值给左边指针停留下的位置。 3.改变遍历方向,从左边开始开始遍历,如果发现左边的数据比第0个位置的数据大,将该位置的数据赋值给2步骤停留下来的位置,并变换方向。 4.循环2、3步骤直到左右遍历到的下标重合5.将取出的第0个位置的值赋值给循环结束后左右指针停留下的位置二. 借鉴前序遍历的思路,递归,最终完成排序。代码实现1 private void quickSort(int[] array, int start, int end) {2 if (start >= end) {3 return;4 }5 int key = array[start];6 int left = start;7 int right = end;8 boolean direction = true;9 L1:10 while (left < right) {11 if (direction) {12 for (int i = right; i > left; i--) {13 if (array[i] < key) {14 array[left++] = array[i];15 right = i;16 direction = !direction;17 continue L1;18 }19 }20 right = left;21 } else {22 for (int i = left; i < right; i++) {23 if (array[i] > key) {24 array[right--] = array[i];25 left = i;26 direction = !direction;27 continue L1;28 }29 }30 left = right;31 }32 }33 array[left] = key;34 quickSort(array, start, left - 1);35 quickSort(array, left + 1, end);3637 }结果测试1 @Test2 public void testQuickSort() {3 int[] array = new int[]{1, 3, 4, 10, 2, 5, 6, 9, 7, 8};4 quickSort(array, 0, array.length - 1);5 for (int i = 0; i < array.length; i++) {6 System.out.println(array[i]);7 }8 }结果打印1 12 23 34 45 56 67 78 89 910 10归并排序概述归并排序与快速排序相同,同样是借鉴二叉树的思想,时间复杂度O(n),与快速排序一样是大量数据排序的最优方式之一。思路分析归并排序是将目标数组分成左右两个数组,左右两个数组必须是有序的,然后对这两个数组合并从而实现排序。对于任意的数组都可以将所有的数据分成若干个数组,每个数组中都只有一个元素,然后两两合并。(因此,归并排序的内存开销会比快速排序多)代码实现1 private void mergeSort(int[] array, int left, int right) {2 if (left >= right) {3 return;4 }5 int mid = (left + right) >> 1;6 mergeSort(array, left, mid);7 mergeSort(array, mid + 1, right);8 merge(array, left, mid + 1, right);9 }1011 private void merge(int[] array, int left, int mid, int right) {12 int leftSize = mid - left;13 int rightSize = right - mid + 1;14 int[] leftArray = new int[leftSize];15 int[] rightArray = new int[rightSize];16 System.arraycopy(array, left, leftArray, 0, leftSize);17 System.arraycopy(array, mid, rightArray, 0, rightSize);18 int index=left;19 int leftIndex = 0;20 int rightIndex = 0;21 while (leftIndex<leftSize&&rightIndex<rightSize){22 if(leftArray[leftIndex]<rightArray[rightIndex]){23 array[index++] = leftArray[leftIndex++];24 }else {25 array[index++] = rightArray[rightIndex++];26 }27 }28 while (leftIndex<leftSize){29 array[index++] = leftArray[leftIndex++];30 }31 while (rightIndex<rightSize){32 array[index++] = rightArray[rightIndex++];33 }34 }测试代码1 @Test2 public void testMergeSort() {3 int[] array = new int[]{1, 3, 4, 10, 2, 5, 6, 9, 7, 8};4 mergeSort(array, 0, array.length - 1);5 for (int i = 0; i < array.length; i++) {6 System.out.println(array[i]);7 }8 }结果打印12345678910
以下Java面试题都是本人在面试的过程中收集的,本人抱着学习的态度找了下参考答案,有不足的地方还请指正,更多精彩内容可以关注我的微信公众号:Java团长ThreadLocal(线程变量副本)Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。友情链接:深入研究java.lang.ThreadLocal类Java内存模型:Java虚拟机规范中将Java运行时数据分为六种。1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。4.Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。5.方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。6.运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。友情链接: Java中JVM虚拟机详解“你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?”在什么时候:1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,如果空间不足就向其中的一个survivor区上放,如果仍然放不下就会引发一次发生在新生代的minor GC,将存活的对象放入另一个survivor区中,然后清空Eden和之前的那个survivor区的内存。在某次GC过程中,如果发现仍然又放不下的对象,就将这些对象放入老年代内存里去。2.大对象以及长期存活的对象直接进入老年区。3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,如果这些马上要到老年区的老年对象的大小超过了老年区的剩余大小,那么执行一次Full GC以尽可能地获得老年区的空间。对什么东西:从GC Roots搜索不到,而且经过一次标记清理之后仍没有复活的对象。做什么: 新生代:复制清理; 老年代:标记-清除和标记-压缩算法; 永久代:存放Java中的类和加载类的类加载器本身。GC Roots都有哪些: 1. 虚拟机栈中的引用的对象 2. 方法区中静态属性引用的对象,常量引用的对象 3. 本地方法栈中JNI(即一般说的Native方法)引用的对象。友情链接:Java GC的那些事(上)友情链接:Java GC的那些事(下)友情链接:CMS垃圾收集器介绍Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。 ReentrantLock适用场景某个线程在等待一个锁的控制权的这段时间需要中断需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。具有公平锁功能,每个到来的线程都将排队等候。友情链接: Synchronized关键字、Lock,并解释它们之间的区别StringBuffer是线程安全的,每次操作字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的友情链接:String、StringBuffer与StringBuilder之间区别fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件happens-before:如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。1.程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。2.监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。3.volatile变量规则:对一个volatile域的写,happens- before于任意后续对这个volatile域的读。4.传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。5.线程启动规则:Thread对象的start()方法happens- before于此线程的每一个动作。Volatile和Synchronized四个不同点:1 粒度不同,前者针对变量 ,后者锁对象和类2 syn阻塞,volatile线程不阻塞3 syn保证三大特性,volatile不保证原子性4 syn编译器优化,volatile不优化 volatile具备两种特性:1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。2.禁止指令重排序优化。Volatile如何保证内存可见性:1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。友情链接:Java并发编程之volatile关键字解析CAS(Compare And Swap) 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。友情链接:非阻塞同步算法与CAS(Compare and Swap)无锁算法线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。常用线程池:ExecutorService 是主要的实现类,其中常用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。友情链接:线程池原理友情链接:线程池原理解析类加载器工作机制:1.装载:将Java二进制代码导入jvm中,生成Class文件。2.连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。友情链接:深入理解Java虚拟机笔记—双亲委派模型 友情链接:JVM类加载的那些事友情链接:JVM(1):Java 类的加载机制一致性哈希:Memcahed缓存:数据结构:key,value对使用方法:get,put等方法友情链接:hashcode(),equal()方法深入解析Redis数据结构: String—字符串(key-value 类型)Hash—字典(hashmap) Redis的哈希结构可以使你像在数据库中更新一个属性一样只修改某一项属性值List—列表 实现消息队列Set—集合 利用唯一性Sorted Set—有序集合 可以进行排序 可以实现数据持久化友情链接: Spring + Redis 实现数据的缓存java自动装箱拆箱深入剖析谈谈Java反射机制如何写一个不可变类?索引:B+,B-,全文索引Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。常用的数据结构是B+Tree,每个叶子节点不但存放了索引键的相关信息还增加了指向相邻叶子节点的指针,这样就形成了带有顺序访问指针的B+Tree,做这个优化的目的是提高不同区间访问的性能。什么时候使用索引:经常出现在group by,order by和distinc关键字后面的字段经常与其他表进行连接的表,在连接字段上应该建立索引经常出现在Where子句中的字段经常出现用作查询选择的字段友情链接:MySQL:InnoDB存储引擎的B+树索引算法友情链接:MySQL索引背后的数据结构及算法原理Spring IOC (控制反转,依赖注入)Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean。Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象。获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,然后通过getBean方法获取bean对象,就可以调用他的方法。Spring Bean的作用域:Singleton:Spring IOC容器中只有一个共享的Bean实例,一般都是Singleton作用域。Prototype:每一个请求,会产生一个新的Bean实例。Request:每一次http请求会产生一个新的Bean实例。友情链接: Spring框架IOC容器和AOP解析友情链接:浅谈Spring框架注解的用法分析友情链接:关于Spring的69个面试问答——终极列表代理的共有优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。Java静态代理:代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,代理对象可以在调用目标对象相应方法前后加上其他业务处理逻辑。缺点:一个代理类只能代理一个业务类。如果业务类增加方法时,相应的代理类也要增加方法。Java动态代理:Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法可以进行增强处
一.基础知识:1)集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet);2)HashMap的底层实现,之后会问ConcurrentHashMap的底层实现;3)如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现;4)HashTable和ConcurrentHashMap的区别;5)String,StringBuffer和StringBuilder的区别;6)Object的方法有哪些:比如有wait方法,为什么会有;7)wait和sleep的区别,必须理解;8)JVM的内存结构,JVM的算法;9)强引用,软引用和弱引用的区别;10)数组在内存中如何分配;11)用过哪些设计模式,手写一个(除单例);12)springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的;13)spring里面的aop的原理是什么;14)mybatis如何处理结果集:反射,建议看看源码;15)java的多态表现在哪里;16)接口有什么用;17)说说http,https协议;18)tcp/ip协议簇;19)osi五层网络协议;20)tcp,udp区别;21)用过哪些加密算法:对称加密,非对称加密算法;22)说说tcp三次握手,四次挥手;23)cookie和session的区别,分布式环境怎么保存用户状态;24)git,svn区别;25)请写一段栈溢出、堆溢出的代码;26)ThreadLocal可以用来共享数据吗;二.IO:1)bio,nio,aio的区别;2)nio框架:dubbo的实现原理;3)京东内部的jsf是使用的什么协议通讯:可参见dubbo的协议;三.算法:1)java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据。2)TreeMap如何插入数据:二叉树的左旋,右旋,双旋;3)一个排序之后的数组,插入数据,可以使用什么方法?答:二分法;问:时间复杂度是多少?4)平衡二叉树的时间复杂度;5)Hash算法和二叉树算法分别什么时候用;6)图的广度优先算法和深度优先算法:详见jvm中垃圾回收实现;四.多线程相关:1)说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行);2)进程通讯的方式:消息队列,共享内存,信号量,socket通讯等;3)用过并发包的哪些类;4)什么地方用了多线程;5)Excutors可以产生哪些线程池;6)为什么要用线程池;7)volatile关键字的用法:使多线程中的变量可见;五.数据库相关(mysql):1)msyql优化经验:2)mysql的语句优化,使用什么工具;3)mysql的索引分类:B+,hash;什么情况用什么索引;4)mysql的存储引擎有哪些,区别是什么;5)说说事务的特性和隔离级别;6)悲观锁和乐观锁的区别,怎么实现;六.mq:1)mq的原理是什么:有点大。。都可以说;2)mq如何保证实时性;3)mq的持久化是怎么做的;七.nosql相关(主要是redis):1)redis和memcache的区别;2)用redis做过什么;3)redis是如何持久化的:rdb和aof;4)redis集群如何同步;5)redis的数据添加过程是怎样的:哈希槽;6)redis的淘汰策略有哪些;7)redis有哪些数据结构;八.zookeeper:1)zookeeper是什么;2)zookeeper哪里用到;3)zookeeper的选主过程;4)zookeeper集群之间如何通讯;5)你们的zookeeper的节点加密是用的什么方式;6)分布式锁的实现过程;九.linux相关:1)linux常用的命令有哪些;2)如何获取java进程的pid;3)如何获取某个进程的网络端口号;4)如何实时打印日志;5)如何统计某个字符串行数;十.设计与思想:1)重构过代码没有?说说经验;2)一千万的用户实时排名如何实现;3)五万人并发抢票怎么实现; 我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽。切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视。准备不充分的面试,完全是浪费时间,更是对自己的不负责(如果title很高,当我没说)。今天给大家分享下chenssy在这次跳槽中整理的Java面试大纲,其中大部分都是面试过程中的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式。项目介绍大部分情况,这是一场面试的开门题,面试官问这个问题,主要是考察你的概述能力和全局视野。有的人经常抱怨自己每天在堆业务,但没有成长。事实上,很多情况下确实在堆业务,但并不是没有成长的。并非做中间件或者技术架构才是成长,例如我们的需求分析能力,沟通协作能力,产品思维能力,抽象建模能力等都是一个非常重要的硬实力。好的,现在进入正文。1、明确项目是做什么的2、明确项目的价值。(为什么做这个项目,它解决了用户什么痛点,它带来什么价值?)3、明确项目的功能。(这个项目涉及哪些功能?)4、明确项目的技术。(这个项目用到哪些技术?)5、明确个人在项目中的位置和作用。(你在这个项目的承担角色?)6、明确项目的整体架构。7、明确项目的优缺点,如果重新设计你会如何设计。8、明确项目的亮点。(这个项目有什么亮点?)9、明确技术成长。(你通过这个项目有哪些技术成长?)Java基础1、List 和 Set 的区别2、HashSet 是如何保证不重复的3、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?4、HashMap 的扩容过程5、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?6、final finally finalize7、强引用 、软引用、 弱引用、虚引用8、Java反射9、Arrays.sort 实现原理和 Collection 实现原理10、LinkedHashMap的应用11、cloneable接口实现原理12、异常分类以及处理机制13、wait和sleep的区别14、数组在内存中如何分配Java 并发1、synchronized 的实现原理以及锁优化?2、volatile 的实现原理?3、Java 的信号灯?4、synchronized 在静态方法和普通方法的区别?5、怎么实现所有线程在等待某个事件的发生才会去执行?6、CAS?CAS 有什么缺陷,如何解决?7、synchronized 和 lock 有什么区别?8、Hashtable 是怎么加锁的 ?9、HashMap 的并发问题?10、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?11、AQS12、如何检测死锁?怎么预防死锁?13、Java 内存模型?14、如何保证多线程下 i++ 结果正确?15、线程池的种类,区别和使用场景?16、分析线程池的实现原理和线程的调度过程?17、线程池如何调优,最大数目如何确认?18、ThreadLocal原理,用的时候需要注意什么?19、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?20、LockSupport工具21、Condition接口及其实现原理22、Fork/Join框架的理解23、分段锁的原理,锁力度减小的思考24、八种阻塞队列以及各个阻塞队列的特性Spring1、BeanFactory 和 FactoryBean?2、Spring IOC 的理解,其初始化过程?3、BeanFactory 和 ApplicationContext?4、Spring Bean 的生命周期,如何被管理的?5、Spring Bean 的加载过程是怎样的?6、如果要你实现Spring AOP,请问怎么实现?7、如果要你实现Spring IOC,你会注意哪些问题?8、Spring 是如何管理事务的,事务管理机制?9、Spring 的不同事务传播行为有哪些,干什么用的?10、Spring 中用到了那些设计模式?11、Spring MVC 的工作原理?12、Spring 循环注入的原理?13、Spring AOP的理解,各个术语,他们是怎么相互工作的?14、Spring 如何保证 Controller 并发的安全?Netty1、BIO、NIO和AIO2、Netty 的各大组件3、Netty的线程模型4、TCP 粘包/拆包的原因及解决方法5、了解哪几种序列化协议?包括使用场景和如何去选择6、Netty的零拷贝实现7、Netty的高性能表现在哪些方面分布式相关1、Dubbo的底层实现原理和机制2、描述一个服务从发布到被消费的详细过程3、分布式系统怎么做服务治理4、接口的幂等性的概念5、消息中间件如何解决消息丢失问题6、Dubbo的服务请求失败怎么处理7、重连机制会不会造成错误8、对分布式事务的理解9、如何实现负载均衡,有哪些算法可以实现?10、Zookeeper的用途,选举的原理是什么?11、数据的垂直拆分水平拆分。12、zookeeper原理和适用场景13、zookeeper watch机制14、redis/zk节点宕机如何处理15、分布式集群下如何做到唯一序列号16、如何做一个分布式锁17、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗18、MQ系统的数据如何保证不丢失19、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题20、zookeeper的选举策略21、全局ID数据库1、mysql分页有什么优化2、悲观锁、乐观锁3、组合索引,最左原则4、mysql 的表锁、行锁5、mysql 性能优化6、mysql的索引分类:B+,hash;什么情况用什么索引7、事务的特性和隔离级别缓存1、Redis用过哪些数据数据,以及Redis底层怎么实现2、Redis缓存穿透,缓存雪崩3、如何使用Redis来实现分布式锁4、Redis的并发竞争问题如何解决5、Redis持久化的几种方式,优缺点是什么,怎么实现的6、Redis的缓存失效策略7、Redis集群,高可用,原理8、Redis缓存分片9、Redis的数据淘汰策略JVM1、详细jvm内存模型2、讲讲什么情况下回出现内存溢出,内存泄漏?3、说说Java线程栈4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?7、类的实例化顺序8、JVM垃圾回收机制,何时触发MinorGC等操作9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的10、各种回收器,各自优缺点,重点CMS、G111、各种回收算法12、OOM错误,stackoverflow错误,permgen space错误我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
不积跬步无以至千里,这里会不断收集和更新Java基础相关的面试题,目前已收集100题。1.什么是B/S架构?什么是C/S架构B/S(Browser/Server),浏览器/服务器程序C/S(Client/Server),客户端/服务端,桌面应用程序2.你所知道网络协议有那些?HTTP:超文本传输协议FTP:文件传输协议SMPT:简单邮件协议TELNET:远程终端协议POP3:邮件读取协议3.Java都有那些开发平台?JAVA SE:主要用在客户端开发JAVA EE:主要用在web应用程序开发JAVA ME:主要用在嵌入式应用程序开发4.什么是JVM?java虚拟机包括什么?JVM:java虚拟机,运用硬件或软件手段实现的虚拟的计算机,Java虚拟机包括:寄存器,堆栈,处理器5.Java是否需要开发人员回收内存垃圾吗?大多情况下是不需要的。Java提供了一个系统级的线程来跟踪内存分配,不再使用的内存区将会自动回收6.什么是JDK?什么是JRE?JDK:java development kit:java开发工具包,是开发人员所需要安装的环境JRE:java runtime environment:java运行环境,java程序运行所需要安装的环境7.什么是数据结构?计算机保存,组织数据的方式8.Java的数据结构有那些?线性表(ArrayList)链表(LinkedList)栈(Stack)队列(Queue)图(Map)树(Tree)9.什么是OOP?面向对象编程10.什么是面向对象?世间万物都可以看成一个对象。每个物体包括动态的行为和静态的属性,这些就构成了一个对象。11.类与对象的关系?类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例12.Java中有几种数据类型整形:byte,short,int,long浮点型:float,double字符型:char布尔型:boolean13.什么是隐式转换,什么是显式转换显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型转换。14.Char类型能不能转成int类型?能不能转化成string类型,能不能转成double类型Char在java中也是比较特殊的类型,它的int值从1开始,一共有2的16次方个数据;Char<int<long<float<double;Char类型可以隐式转成int,double类型,但是不能隐式转换成string;如果char类型转成byte,short类型的时候,需要强转。15.什么是拆装箱?拆箱:把包装类型转成基本数据类型装箱:把基本数据类型转成包装类型16.Java中的包装类都是那些?byte:Byte short:Short int:Integer long:Long float:Float double:Double char:Character boolean:Boolean17.一个java类中包含那些内容?属性、方法、内部类、构造方法、代码块。18.例如: if(a+1.0=4.0),这样做好吗?不好,因为计算机在浮点型数据运算的时候,会有误差,尽量在布尔表达式中不使用浮点型数据(if,while,switch中判断条件不使用浮点型)19.那针对浮点型数据运算出现的误差的问题,你怎么解决?使用Bigdecimal类进行浮点型数据的运算20.++i与i++的区别++i:先赋值,后计算i++:先计算,后赋值21.程序的结构有那些?顺序结构选择结构循环结构22.数组实例化有几种方式?静态实例化:创建数组的时候已经指定数组中的元素,int[] a=new int[]{1,3,3}动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值23.Java中各种数据默认值Byte,short,int,long默认是都是0Boolean默认值是falseChar类型的默认值是’’Float与double类型的默认是0.0对象类型的默认值是null24.Java常用包有那些?Java.langJava.ioJava.sqlJava.utilJava.awtJava.netJava.math25.Java最顶级的父类是哪个?Object26.Object类常用方法有那些?EqualsHashcodetoStringwaitnotifyclonegetClass27.java中有没有指针?有指针,但是隐藏了,开发人员无法直接操作指针,由jvm来操作指针28.java中是值传递引用传递?理论上说,java都是引用传递,对于基本数据类型,传递是值的副本,而不是值本身。对于对象类型,传递是对象的引用,当在一个方法操作操作参数的时候,其实操作的是引用所指向的对象。29.假设把实例化的数组的变量当成方法参数,当方法执行的时候改变了数组内的元素,那么在方法外,数组元素有发生改变吗?改变了,因为传递是对象的引用,操作的是引用所指向的对象30.实例化数组后,能不能改变数组长度呢?不能,数组一旦实例化,它的长度就是固定的31.假设数组内有5个元素,如果对数组进行反序,该如何做?创建一个新数组,从后到前循环遍历每个元素,将取出的元素依次顺序放入新数组中32.形参与实参形参:全称为“形式参数”,是在定义方法名和方法体的时候使用的参数,用于接收调用该方法时传入的实际值;实参:全称为“实际参数”,是在调用方法时传递给该方法的实际值。33.构造方法能不能显式调用?不能构造方法当成普通方法调用,只有在创建对象的时候它才会被系统调用34.构造方法能不能重写?能不能重载?可以重写,也可以重载35.什么是方法重载?方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或者类型不同即可。在这种情况下,该方法就叫被重载了,这个过程称为方法的重载(override)36.内部类与静态内部类的区别?静态内部类相对与外部类是独立存在的,在静态内部类中无法直接访问外部类中变量、方法。如果要访问的话,必须要new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法;普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性如果其他的类要访问静态内部类的属性或者调用静态内部类的方法,直接创建一个静态内部类对象即可。37.Static关键字有什么作用?Static可以修饰内部类、方法、变量、代码块Static修饰的类是静态内部类Static修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。在static方法中不能使用this或者super关键字。Static修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在JVM加载类的时候,只为静态分配一次内存。Static修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。38.Final在java中的作用Final可以修饰类,修饰方法,修饰变量。修饰的类叫最终类。该类不能被继承。修饰的方法不能被重写。修饰的变量叫常量,常量必须初始化,一旦初始化后,常量的值不能发生改变。39.Java中操作字符串使用哪个类?String,StringBuffer,StringBuilder40.StringBuffer,Stringbuilder有什么区别?StringBuffer与StringBuilder都继承了AbstractStringBulder类,而AbtractStringBuilder又实现了CharSequence接口,两个类都是用来进行字符串操作的。在做字符串拼接修改删除替换时,效率比string更高。StringBuffer是线程安全的,Stringbuilder是非线程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了synchronized关键字41.String str=”aaa”,与String str=new String(“aaa”)一样吗?不一样的。因为内存分配的方式不一样。第一种,创建的”aaa”是常量,jvm都将其分配在常量池中。第二种创建的是一个对象,jvm将其值分配在堆内存中。42.String str=”aa”,String s=”bb”,String aa=aa+s;一种创建了几个对象?一共有两个引用,三个对象。因为”aa”与”bb”都是常量,常量的值不能改变,当执行字符串拼接时候,会创建一个新的常量是” aabbb”,有将其存到常量池中。43.将下java中的math类有那些常用方法?Pow():幂运算Sqrt():平方根Round():四舍五入Abs():求绝对值Random():生成一个0-1的随机数,包括0不包括144.String类的常用方法有那些?charAt:返回指定索引处的字符indexOf():返回指定字符的索引replace():字符串替换trim():去除字符串两端空白split():分割字符串,返回一个分割后的字符串数组getBytes():返回字符串的byte类型数组length():返回字符串长度toLowerCase():将字符串转成小写字母toUpperCase():将字符串转成大写字符substring():截取字符串format():格式化字符串equals():字符串比较45.判断两个对象是否相同,能使用equlas比较吗?不能。Equlas大多用来做字符串比较,要判断基本数据类型或者对象类型,需要使用==46.==与equlas有什么区别?==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同,也就是说判断两个对象是否是同一个对象,Equlas通常用来做字符串比较。47.如何将字符串反转?Stringbuilder或者stringbuffer的reverse方法48.面向对象的语言有那些特征?封装、继承、多态49.Java中的继承是单继承还是多继承Java中既有单继承,又有多继承。对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口50.什么是重写?什么是重载?重载和重写都是java多态的表现。重载叫override,在同一个类中多态的表现。当一个类中出现了多个相同名称的方法,但参数个数和参数类型不同,方法重载与返回值无关重写叫overwrite,是字符类中多态的表现。当子类出现与父类相同的方法,那么这就是方法重写。方法重写时,子类的返回值必须与父类的一致。如果父类方法抛出一个异常,子类重写的方法抛出的异常类型不能小于父类抛出的异常类型。51.构造方法能不能重载?能不能重写?可以重载,必须重写52.如果父类只有有参构造方法,那么子类必须要重写父类的构造方法吗?必须重写53.创建一个子类对象的时候,那么父类的构造方法会执行吗?会执行。当创建一个子类对象,调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法。54.什么是父类引用指向子类对象?是java多态一种特殊的表现形式。创建父类引用,让该引用指向一个子类的对象55.当父类引用指向子类对象的时候,子类重写了父类方法和属性,那么当访问属性的时候,访问是谁的属性?调用方法时,调用的是谁的方法?子类重写了父类方法和属性,访问的是父类的属性,调用的是子类的方法56.Super与this表示什么?Super表示当前类的父类对象This表示当前类的对象57.抽象的关键字是什么?Abstract58.抽象类必须要有抽象方法吗不是必须。抽象类可以没有抽象方法。59.如果一个类中有抽象方法,那么这个一定是抽象类?包含抽象方法的类一定是抽象
这里,笔者结合自己过往的面试经验,整理了一些核心的知识清单,帮助读者更好地回顾与复习 Java 服务端核心技术。本文会以引出问题为主,后面有时间的话,笔者陆续会抽些重要的知识点进行详细的剖析与解答。敬请关注微信公众号「Java团长」,获取最新文章。基础篇基本功面向对象的特征final, finally, finalize 的区别int 和 Integer 有什么区别重载和重写的区别抽象类和接口有什么区别说说反射的用途及实现说说自定义注解的场景及实现HTTP 请求的 GET 与 POST 方式的区别session 与 cookie 区别session 分布式处理JDBC 流程MVC 设计思想equals 与 == 的区别集合List 和 Set 区别List 和 Map 区别Arraylist 与 LinkedList 区别ArrayList 与 Vector 区别HashMap 和 Hashtable 的区别HashSet 和 HashMap 区别HashMap 和 ConcurrentHashMap 的区别HashMap 的工作原理及代码实现ConcurrentHashMap 的工作原理及代码实现线程创建线程的方式及实现sleep() 、join()、yield()有什么区别说说 CountDownLatch 原理说说 CyclicBarrier 原理说说 Semaphore 原理说说 Exchanger 原理说说 CountDownLatch 与 CyclicBarrier 区别ThreadLocal 原理分析讲讲线程池的实现原理线程池的几种方式线程的生命周期锁机制说说线程安全问题volatile 实现原理synchronize 实现原理synchronized 与 lock 的区别CAS 乐观锁ABA 问题乐观锁的业务场景及实现方式核心篇数据存储MySQL 索引使用的注意事项说说反模式设计说说分库与分表设计分库与分表带来的分布式困境与应对之策说说 SQL 优化之道MySQL 遇到的死锁问题存储引擎的 InnoDB 与 MyISAM数据库索引的原理为什么要用 B-tree聚集索引与非聚集索引的区别limit 20000 加载很慢怎么解决选择合适的分布式主键方案选择合适的数据存储方案ObjectId 规则聊聊 MongoDB 使用场景倒排索引聊聊 ElasticSearch 使用场景缓存使用Redis 有哪些类型Redis 内部结构聊聊 Redis 使用场景Redis 持久化机制Redis 如何实现持久化Redis 集群方案与实现Redis 为什么是单线程的缓存奔溃缓存降级使用缓存的合理性问题消息队列消息队列的使用场景消息的重发补偿解决思路消息的幂等性解决思路消息的堆积解决思路自己如何实现消息队列如何保证消息的有序性框架篇SpringBeanFactory 和 ApplicationContext 有什么区别Spring Bean 的生命周期Spring IOC 如何实现说说 Spring AOPSpring AOP 实现原理动态代理(cglib 与 JDK)Spring 事务实现方式Spring 事务底层原理如何自定义注解实现功能Spring MVC 运行流程Spring MVC 启动流程Spring 的单例实现原理Spring 框架中用到了哪些设计模式Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)Netty为什么选择 Netty说说业务中,Netty 的使用场景原生的 NIO 在 JDK 1.7 版本存在 epoll bug什么是TCP 粘包/拆包TCP粘包/拆包的解决办法Netty 线程模型说说 Netty 的零拷贝Netty 内部执行流程Netty 重连实现微服务篇微服务前后端分离是如何做的微服务哪些框架你怎么理解 RPC 框架说说 RPC 的实现原理说说 Dubbo 的实现原理你怎么理解 RESTful说说如何设计一个良好的 API如何理解 RESTful API 的幂等性如何保证接口的幂等性说说 CAP 定理、 BASE 理论怎么考虑数据一致性问题说说最终一致性的实现方案你怎么看待微服务微服务与 SOA 的区别如何拆分服务微服务如何进行数据库管理如何应对微服务的链式调用异常对于快速追踪与定位问题微服务的安全分布式谈谈业务中使用分布式的场景Session 分布式方案分布式锁的场景分布是锁的实现方案分布式事务集群与负载均衡的算法与实现说说分库与分表设计分库与分表带来的分布式困境与应对之策安全问题安全要素与 STRIDE 威胁防范常见的 Web 攻击服务端通信安全攻防HTTPS 原理剖析HTTPS 降级攻击授权与认证基于角色的访问控制基于数据的访问控制性能优化性能指标有哪些如何发现性能瓶颈性能调优的常见手段说说你在项目中如何进行性能调优工程篇需求分析你如何对需求原型进行理解和拆分说说你对功能性需求的理解说说你对非功能性需求的理解你针对产品提出哪些交互和改进意见你如何理解用户痛点设计能力说说你在项目中使用过的 UML 图你如何考虑组件化你如何考虑服务化你如何进行领域建模你如何划分领域边界说说你项目中的领域建模说说概要设计设计模式你项目中有使用哪些设计模式说说常用开源框架中设计模式使用分析说说你对设计原则的理解23种设计模式的设计理念设计模式之间的异同,例如策略模式与状态模式的区别设计模式之间的结合,例如策略模式+简单工厂模式的实践设计模式的性能,例如单例模式哪种性能更好。业务工程你系统中的前后端分离是如何做的说说你的开发流程你和团队是如何沟通的你如何进行代码评审说说你对技术与业务的理解说说你在项目中经常遇到的 Exception说说你在项目中遇到感觉最难Bug,怎么解决的说说你在项目中遇到印象最深困难,怎么解决的你觉得你们项目还有哪些不足的地方你是否遇到过 CPU 100% ,如何排查与解决你是否遇到过 内存 OOM ,如何排查与解决说说你对敏捷开发的实践说说你对开发运维的实践介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色软实力说说你的亮点说说你最近在看什么书说说你觉得最有意义的技术书籍工作之余做什么事情说说个人发展方向方面的思考说说你认为的服务端开发工程师应该具备哪些能力说说你认为的架构师是什么样的,架构师主要做什么说说你所理解的技术专家我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
首先,声明下,以下知识点并非全部来自BAT的面试题。如果觉得在本文中笔者总结的内容能对你有所帮助,可以点赞关注一下。本文会以引出问题为主,后面有时间的话,笔者陆续会抽些重要的知识点进行详细的剖析与解答。基础篇基本功1、面向对象的特征2、final, finally, finalize 的区别3、int 和 Integer 有什么区别4、重载和重写的区别5、抽象类和接口有什么区别6、说说反射的用途及实现7、说说自定义注解的场景及实现8、HTTP 请求的 GET 与 POST 方式的区别9、session 与 cookie 区别10、session 分布式处理11、JDBC 流程12、MVC 设计思想13、equals 与 == 的区别集合1、List 和 Set 区别2、List 和 Map 区别3、Arraylist 与 LinkedList 区别4、ArrayList 与 Vector 区别5、HashMap 和 Hashtable 的区别6、HashSet 和 HashMap 区别7、HashMap 和 ConcurrentHashMap 的区别8、HashMap 的工作原理及代码实现9、ConcurrentHashMap 的工作原理及代码实现线程1、创建线程的方式及实现2、sleep() 、join()、yield()有什么区别3、说说 CountDownLatch 原理4、说说 CyclicBarrier 原理5、说说 Semaphore 原理6、说说 Exchanger 原理7、说说 CountDownLatch 与 CyclicBarrier 区别8、ThreadLocal 原理分析9、讲讲线程池的实现原理10、线程池的几种方式11、线程的生命周期锁机制1、说说线程安全问题2、volatile 实现原理3、synchronize 实现原理4、synchronized 与 lock 的区别5、CAS 乐观锁6、ABA 问题7、乐观锁的业务场景及实现方式核心篇数据存储1、MySQL 索引使用的注意事项2、说说反模式设计3、说说分库与分表设计4、分库与分表带来的分布式困境与应对之策5、说说 SQL 优化之道6、MySQL 遇到的死锁问题7、存储引擎的 InnoDB 与 MyISAM8、数据库索引的原理9、为什么要用 B-tree10、聚集索引与非聚集索引的区别11、limit 20000 加载很慢怎么解决12、选择合适的分布式主键方案13、选择合适的数据存储方案14、ObjectId 规则15、聊聊 MongoDB 使用场景16、倒排索引17、聊聊 ElasticSearch 使用场景缓存使用1、Redis 有哪些类型2、Redis 内部结构3、聊聊 Redis 使用场景4、Redis 持久化机制5、Redis 如何实现持久化6、Redis 集群方案与实现7、Redis 为什么是单线程的8、缓存奔溃9、缓存降级10、使用缓存的合理性问题消息队列1、消息队列的使用场景2、消息的重发补偿解决思路3、消息的幂等性解决思路4、消息的堆积解决思路5、自己如何实现消息队列6、如何保证消息的有序性框架篇Spring1、BeanFactory 和 ApplicationContext 有什么区别2、Spring Bean 的生命周期3、Spring IOC 如何实现4、说说 Spring AOP5、Spring AOP 实现原理6、动态代理(cglib 与 JDK)7、Spring 事务实现方式8、Spring 事务底层原理9、如何自定义注解实现功能10、Spring MVC 运行流程11、Spring MVC 启动流程12、Spring 的单例实现原理13、Spring 框架中用到了哪些设计模式14、Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)Netty1、为什么选择 Netty2、说说业务中,Netty 的使用场景3、原生的 NIO 在 JDK 1.7 版本存在 epoll bug4、什么是TCP 粘包/拆包5、TCP粘包/拆包的解决办法6、Netty 线程模型7、说说 Netty 的零拷贝8、Netty 内部执行流程9、Netty 重连实现微服务篇微服务1、前后端分离是如何做的2、微服务哪些框架3、你怎么理解 RPC 框架4、说说 RPC 的实现原理5、说说 Dubbo 的实现原理6、你怎么理解 RESTful7、说说如何设计一个良好的 API8、如何理解 RESTful API 的幂等性9、如何保证接口的幂等性10、说说 CAP 定理、 BASE 理论11、怎么考虑数据一致性问题12、说说最终一致性的实现方案13、你怎么看待微服务14、微服务与 SOA 的区别15、如何拆分服务16、微服务如何进行数据库管理17、如何应对微服务的链式调用异常18、对于快速追踪与定位问题19、微服务的安全  分布式1、谈谈业务中使用分布式的场景2、Session 分布式方案3、分布式锁的场景4、分布是锁的实现方案5、分布式事务6、集群与负载均衡的算法与实现7、说说分库与分表设计8、分库与分表带来的分布式困境与应对之策  安全&性能安全问题1、安全要素与 STRIDE 威胁2、防范常见的 Web 攻击3、服务端通信安全攻防4、HTTPS 原理剖析5、HTTPS 降级攻击6、授权与认证7、基于角色的访问控制8、基于数据的访问控制性能优化1、性能指标有哪些2、如何发现性能瓶颈3、性能调优的常见手段4、说说你在项目中如何进行性能调优  工程篇需求分析1、你如何对需求原型进行理解和拆分2、说说你对功能性需求的理解3、说说你对非功能性需求的理解4、你针对产品提出哪些交互和改进意见5、你如何理解用户痛点设计能力1、说说你在项目中使用过的 UML 图2、你如何考虑组件化3、你如何考虑服务化4、你如何进行领域建模5、你如何划分领域边界6、说说你项目中的领域建模7、说说概要设计设计模式1、你项目中有使用哪些设计模式2、说说常用开源框架中设计模式使用分析3、说说你对设计原则的理解4、23种设计模式的设计理念5、设计模式之间的异同,例如策略模式与状态模式的区别6、设计模式之间的结合,例如策略模式+简单工厂模式的实践7、设计模式的性能,例如单例模式哪种性能更好。业务工程1、你系统中的前后端分离是如何做的2、说说你的开发流程3、你和团队是如何沟通的4、你如何进行代码评审5、说说你对技术与业务的理解6、说说你在项目中经常遇到的 Exception7、说说你在项目中遇到感觉最难Bug,怎么解决的8、说说你在项目中遇到印象最深困难,怎么解决的9、你觉得你们项目还有哪些不足的地方10、你是否遇到过 CPU 100% ,如何排查与解决11、你是否遇到过 内存 OOM ,如何排查与解决12、说说你对敏捷开发的实践13、说说你对开发运维的实践14、介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色  软实力1、说说你的亮点2、说说你最近在看什么书3、说说你觉得最有意义的技术书籍4、工作之余做什么事情5、说说个人发展方向方面的思考6、说说你认为的服务端开发工程师应该具备哪些能力7、说说你认为的架构师是什么样的,架构师主要做什么8、说说你所理解的技术专家我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
面试问题:一、Java基础方面: 1、Java面相对象的思想的理解(主要是多态): http://blog.csdn.net/zhaojw_420/article/details/704776362、集合:ArrayList,LinkedList,HashMap,LinkedHashMap,ConcurrentHashMap,HashTable,HashSet的底层源码实现原理3、Java虚拟机 (1)组成以及各部分作用: http://blog.csdn.net/zhaojw_420/article/details/70477953 (2)类加载器——ClassLoader: http://blog.csdn.net/zhaojw_420/article/details/53373898 (3)类加载器的父亲委托机制深度详解: http://blog.csdn.net/zhaojw_420/article/details/53284225 (4)JVM调优: http://blog.csdn.net/zhaojw_420/article/details/70527138 (5)垃圾回收: http://blog.csdn.net/zhaojw_420/article/details/705272324、异常 http://blog.csdn.net/zhaojw_420/article/details/704777515、String,StringBuffer,StringBuilder区别 http://blog.csdn.net/zhaojw_420/article/details/704777186、值传递与引用传递: http://blog.csdn.net/zhaojw_420/article/details/704776807、Java中的equals和hashCode方法详解 http://blog.csdn.net/zhaojw_420/article/details/704777058、TCP的三次握手和四次挥手9、多线程 (1)实现线程同步: http://blog.csdn.net/zhaojw_420/article/details/67823750 (2)生产者消费者问题: http://blog.csdn.net/zhaojw_420/article/details/67826902 (3)线程安全 (4)线程死锁 (5)Synchronize实现原理 (7)happen-before规则: http://blog.csdn.net/zhaojw_420/article/details/70477874 (8)线程池 (9)DCL失效原因以及解决办法: http://blog.csdn.net/zhaojw_420/article/details/70477921 (10)线程实现方式:Thread,Runable,Callable的区别10、IO http://blog.csdn.net/zhaojw_420/article/details/7052435311、NIO http://blog.csdn.net/zhaojw_420/article/details/7052669512、网络编程13、Java内存模型 http://blog.csdn.net/zhaojw_420/article/details/70477903二、数据库(MySql) 1、面试题: http://blog.csdn.net/zhaojw_420/article/details/70530664 2、sql优化: http://blog.csdn.net/zhaojw_420/article/details/70532017 3、搜索引擎三、设计模式 单例模式,工厂模式,建造者模式,观察者模式,适配器模式,代理模式等等四、数据结构与算法: 1、链表,栈,队列,二叉树: http://blog.csdn.net/zhaojw_420/article/details/68485474 2、八大排序算法: 3、查找算法五、高并发与海量数据 1、大型网站应用之海量数据解决方案 http://blog.csdn.net/zhaojw_420/article/details/708812302、大型网站应用之高并发情况下的解决方案 http://blog.csdn.net/zhaojw_420/article/details/708812663、在一个千万级的数据库查寻中,如何提高查询效率? http://blog.csdn.net/zhaojw_420/article/details/69367682六,Struts,Spring,Hibernate,Mybatis,Springmvc七、前端:javascript,Jquery http://blog.csdn.net/zhaojw_420/article/details/70880977八、Jsp+Servlet http://blog.csdn.net/zhaojw_420/article/details/70880968九、linux操作命令(重点服务器方面操作)十、tomcat调优十一、Redis/MongoDB等NoSql http://blog.csdn.net/zhaojw_420/article/details/68066305十二、Nginx的配置与使用
跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽。切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视。准备不充分的面试,完全是浪费时间,更是对自己的不负责(如果title很高,当我没说)。今天给大家分享下我在这次跳槽中整理的Java面试大纲,其中大部分都是面试过程中的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式。项目介绍大部分情况,这是一场面试的开门题,面试官问这个问题,主要是考察你的概述能力和全局视野。有的人经常抱怨自己每天在堆业务,但没有成长。事实上,很多情况下确实在堆业务,但并不是没有成长的。并非做中间件或者技术架构才是成长,例如我们的需求分析能力,沟通协作能力,产品思维能力,抽象建模能力等都是一个非常重要的硬实力。好的,现在进入正文。1、明确项目是做什么的2、明确项目的价值。(为什么做这个项目,它解决了用户什么痛点,它带来什么价值?)3、明确项目的功能。(这个项目涉及哪些功能?)4、明确项目的技术。(这个项目用到哪些技术?)5、明确个人在项目中的位置和作用。(你在这个项目的承担角色?)6、明确项目的整体架构。7、明确项目的优缺点,如果重新设计你会如何设计。8、明确项目的亮点。(这个项目有什么亮点?)9、明确技术成长。(你通过这个项目有哪些技术成长?)Java基础1、List 和 Set 的区别2、HashSet 是如何保证不重复的3、HashMap 是线程安全的吗,为什么不是线程安全的(最好画图说明多线程环境下不安全)?4、HashMap 的扩容过程5、HashMap 1.7 与 1.8 的 区别,说明 1.8 做了哪些优化,如何优化的?6、final finally finalize7、强引用 、软引用、 弱引用、虚引用8、Java反射9、Arrays.sort 实现原理和 Collection 实现原理10、LinkedHashMap的应用11、cloneable接口实现原理12、异常分类以及处理机制13、wait和sleep的区别14、数组在内存中如何分配Java 并发1、synchronized 的实现原理以及锁优化?2、volatile 的实现原理?3、Java 的信号灯?4、synchronized 在静态方法和普通方法的区别?5、怎么实现所有线程在等待某个事件的发生才会去执行?6、CAS?CAS 有什么缺陷,如何解决?7、synchronized 和 lock 有什么区别?8、Hashtable 是怎么加锁的 ?9、HashMap 的并发问题?10、ConcurrenHashMap 介绍?1.8 中为什么要用红黑树?11、AQS12、如何检测死锁?怎么预防死锁?13、Java 内存模型?14、如何保证多线程下 i++ 结果正确?15、线程池的种类,区别和使用场景?16、分析线程池的实现原理和线程的调度过程?17、线程池如何调优,最大数目如何确认?18、ThreadLocal原理,用的时候需要注意什么?19、CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别?20、LockSupport工具21、Condition接口及其实现原理22、Fork/Join框架的理解23、分段锁的原理,锁力度减小的思考24、八种阻塞队列以及各个阻塞队列的特性Spring1、BeanFactory 和 FactoryBean?2、Spring IOC 的理解,其初始化过程?3、BeanFactory 和 ApplicationContext?4、Spring Bean 的生命周期,如何被管理的?5、Spring Bean 的加载过程是怎样的?6、如果要你实现Spring AOP,请问怎么实现?7、如果要你实现Spring IOC,你会注意哪些问题?8、Spring 是如何管理事务的,事务管理机制?9、Spring 的不同事务传播行为有哪些,干什么用的?10、Spring 中用到了那些设计模式?11、Spring MVC 的工作原理?12、Spring 循环注入的原理?13、Spring AOP的理解,各个术语,他们是怎么相互工作的?14、Spring 如何保证 Controller 并发的安全?Netty1、BIO、NIO和AIO2、Netty 的各大组件3、Netty的线程模型4、TCP 粘包/拆包的原因及解决方法5、了解哪几种序列化协议?包括使用场景和如何去选择6、Netty的零拷贝实现7、Netty的高性能表现在哪些方面分布式相关1、Dubbo的底层实现原理和机制2、描述一个服务从发布到被消费的详细过程3、分布式系统怎么做服务治理4、接口的幂等性的概念5、消息中间件如何解决消息丢失问题6、Dubbo的服务请求失败怎么处理7、重连机制会不会造成错误8、对分布式事务的理解9、如何实现负载均衡,有哪些算法可以实现?10、Zookeeper的用途,选举的原理是什么?11、数据的垂直拆分水平拆分。12、zookeeper原理和适用场景13、zookeeper watch机制14、redis/zk节点宕机如何处理15、分布式集群下如何做到唯一序列号16、如何做一个分布式锁17、用过哪些MQ,怎么用的,和其他mq比较有什么优缺点,MQ的连接是线程安全的吗18、MQ系统的数据如何保证不丢失19、列举出你能想到的数据库分库分表策略;分库分表后,如何解决全表查询的问题20、zookeeper的选举策略21、全局ID数据库1、mysql分页有什么优化2、悲观锁、乐观锁3、组合索引,最左原则4、mysql 的表锁、行锁5、mysql 性能优化6、mysql的索引分类:B+,hash;什么情况用什么索引7、事务的特性和隔离级别缓存1、Redis用过哪些数据数据,以及Redis底层怎么实现2、Redis缓存穿透,缓存雪崩3、如何使用Redis来实现分布式锁4、Redis的并发竞争问题如何解决5、Redis持久化的几种方式,优缺点是什么,怎么实现的6、Redis的缓存失效策略7、Redis集群,高可用,原理8、Redis缓存分片9、Redis的数据淘汰策略JVM1、详细jvm内存模型2、讲讲什么情况下回出现内存溢出,内存泄漏?3、说说Java线程栈4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?7、类的实例化顺序8、JVM垃圾回收机制,何时触发MinorGC等操作9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的10、各种回收器,各自优缺点,重点CMS、G111、各种回收算法12、OOM错误,stackoverflow错误,permgen space错误我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
不积跬步无以至千里,这里会不断收集和更新Java基础相关的面试题,目前已收集100题。1.什么是B/S架构?什么是C/S架构B/S(Browser/Server),浏览器/服务器程序C/S(Client/Server),客户端/服务端,桌面应用程序2.你所知道网络协议有那些?HTTP:超文本传输协议FTP:文件传输协议SMPT:简单邮件协议TELNET:远程终端协议POP3:邮件读取协议3.Java都有那些开发平台?JAVA SE:主要用在客户端开发JAVA EE:主要用在web应用程序开发JAVA ME:主要用在嵌入式应用程序开发4.什么是JVM?java虚拟机包括什么?JVM:java虚拟机,运用硬件或软件手段实现的虚拟的计算机,Java虚拟机包括:寄存器,堆栈,处理器5.Java是否需要开发人员回收内存垃圾吗?大多情况下是不需要的。Java提供了一个系统级的线程来跟踪内存分配,不再使用的内存区将会自动回收6.什么是JDK?什么是JRE?JDK:java development kit:java开发工具包,是开发人员所需要安装的环境JRE:java runtime environment:java运行环境,java程序运行所需要安装的环境7.什么是数据结构?计算机保存,组织数据的方式8.Java的数据结构有那些?线性表(ArrayList)链表(LinkedList)栈(Stack)队列(Queue)图(Map)树(Tree)9.什么是OOP?面向对象编程10.什么是面向对象?世间万物都可以看成一个对象。每个物体包括动态的行为和静态的属性,这些就构成了一个对象。11.类与对象的关系?类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例12.Java中有几种数据类型整形:byte,short,int,long浮点型:float,double字符型:char布尔型:boolean13.什么是隐式转换,什么是显式转换显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型转换。14.Char类型能不能转成int类型?能不能转化成string类型,能不能转成double类型Char在java中也是比较特殊的类型,它的int值从1开始,一共有2的16次方个数据;Char<int<long<float<double;Char类型可以隐式转成int,double类型,但是不能隐式转换成string;如果char类型转成byte,short类型的时候,需要强转。15.什么是拆装箱?拆箱:把包装类型转成基本数据类型装箱:把基本数据类型转成包装类型16.Java中的包装类都是那些?byte:Byteshort:Shortint:Integerlong:Longfloat:Floatdouble:Doublechar:Characterboolean:Boolean17.一个java类中包含那些内容?属性、方法、内部类、构造方法、代码块。18.例如: if(a+1.0=4.0),这样做好吗?不好,因为计算机在浮点型数据运算的时候,会有误差,尽量在布尔表达式中不使用浮点型数据(if,while,switch中判断条件不使用浮点型)19.那针对浮点型数据运算出现的误差的问题,你怎么解决?使用Bigdecimal类进行浮点型数据的运算20.++i与i++的区别++i:先赋值,后计算i++:先计算,后赋值21.程序的结构有那些?顺序结构选择结构循环结构22.数组实例化有几种方式?静态实例化:创建数组的时候已经指定数组中的元素,int[] a=new int[]{1,3,3}动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值23.Java中各种数据默认值Byte,short,int,long默认是都是0Boolean默认值是falseChar类型的默认值是’’Float与double类型的默认是0.0对象类型的默认值是null24.Java常用包有那些?Java.langJava.ioJava.sqlJava.utilJava.awtJava.netJava.math25.Java最顶级的父类是哪个?Object26.Object类常用方法有那些?EqualsHashcodetoStringwaitnotifyclonegetClass27.java中有没有指针?有指针,但是隐藏了,开发人员无法直接操作指针,由jvm来操作指针28.java中是值传递引用传递?理论上说,java都是引用传递,对于基本数据类型,传递是值的副本,而不是值本身。对于对象类型,传递是对象的引用,当在一个方法操作操作参数的时候,其实操作的是引用所指向的对象。29.假设把实例化的数组的变量当成方法参数,当方法执行的时候改变了数组内的元素,那么在方法外,数组元素有发生改变吗?改变了,因为传递是对象的引用,操作的是引用所指向的对象30.实例化数组后,能不能改变数组长度呢?不能,数组一旦实例化,它的长度就是固定的31.假设数组内有5个元素,如果对数组进行反序,该如何做?创建一个新数组,从后到前循环遍历每个元素,将取出的元素依次顺序放入新数组中32.形参与实参形参:全称为“形式参数”,是在定义方法名和方法体的时候使用的参数,用于接收调用该方法时传入的实际值;实参:全称为“实际参数”,是在调用方法时传递给该方法的实际值。33.构造方法能不能显式调用?不能构造方法当成普通方法调用,只有在创建对象的时候它才会被系统调用34.构造方法能不能重写?能不能重载?可以重写,也可以重载35.什么是方法重载?方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要它们的参数个数或者类型不同即可。在这种情况下,该方法就叫被重载了,这个过程称为方法的重载(override)36.内部类与静态内部类的区别?静态内部类相对与外部类是独立存在的,在静态内部类中无法直接访问外部类中变量、方法。如果要访问的话,必须要new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法;普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法。如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性如果其他的类要访问静态内部类的属性或者调用静态内部类的方法,直接创建一个静态内部类对象即可。37.Static关键字有什么作用?Static可以修饰内部类、方法、变量、代码块Static修饰的类是静态内部类Static修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。在static方法中不能使用this或者super关键字。Static修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在JVM加载类的时候,只为静态分配一次内存。Static修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。38.Final在java中的作用Final可以修饰类,修饰方法,修饰变量。修饰的类叫最终类。该类不能被继承。修饰的方法不能被重写。修饰的变量叫常量,常量必须初始化,一旦初始化后,常量的值不能发生改变。39.Java中操作字符串使用哪个类?String,StringBuffer,StringBuilder40.StringBuffer,Stringbuilder有什么区别?StringBuffer与StringBuilder都继承了AbstractStringBulder类,而AbtractStringBuilder又实现了CharSequence接口,两个类都是用来进行字符串操作的。在做字符串拼接修改删除替换时,效率比string更高。StringBuffer是线程安全的,Stringbuilder是非线程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了synchronized关键字41.String str=”aaa”,与String str=new String(“aaa”)一样吗?不一样的。因为内存分配的方式不一样。第一种,创建的”aaa”是常量,jvm都将其分配在常量池中。第二种创建的是一个对象,jvm将其值分配在堆内存中。42.String str=”aa”,String s=”bb”,String aa=aa+s;一种创建了几个对象?一共有两个引用,三个对象。因为”aa”与”bb”都是常量,常量的值不能改变,当执行字符串拼接时候,会创建一个新的常量是” aabbb”,有将其存到常量池中。43.将下java中的math类有那些常用方法?Pow():幂运算Sqrt():平方根Round():四舍五入Abs():求绝对值Random():生成一个0-1的随机数,包括0不包括144.String类的常用方法有那些?charAt:返回指定索引处的字符indexOf():返回指定字符的索引replace():字符串替换trim():去除字符串两端空白split():分割字符串,返回一个分割后的字符串数组getBytes():返回字符串的byte类型数组length():返回字符串长度toLowerCase():将字符串转成小写字母toUpperCase():将字符串转成大写字符substring():截取字符串format():格式化字符串equals():字符串比较45.判断两个对象是否相同,能使用equlas比较吗?不能。Equlas大多用来做字符串比较,要判断基本数据类型或者对象类型,需要使用==46.==与equlas有什么区别?==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同,也就是说判断两个对象是否是同一个对象,Equlas通常用来做字符串比较。47.如何将字符串反转?Stringbuilder或者stringbuffer的reverse方法48.面向对象的语言有那些特征?封装、继承、多态49.Java中的继承是单继承还是多继承Java中既有单继承,又有多继承。对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口50.什么是重写?什么是重载?重载和重写都是java多态的表现。重载叫override,在同一个类中多态的表现。当一个类中出现了多个相同名称的方法,但参数个数和参数类型不同,方法重载与返回值无关重写叫overwrite,是字符类中多态的表现。当子类出现与父类相同的方法,那么这就是方法重写。方法重写时,子类的返回值必须与父类的一致。如果父类方法抛出一个异常,子类重写的方法抛出的异常类型不能小于父类抛出的异常类型。51.构造方法能不能重载?能不能重写?可以重载,必须重写52.如果父类只有有参构造方法,那么子类必须要重写父类的构造方法吗?必须重写53.创建一个子类对象的时候,那么父类的构造方法会执行吗?会执行。当创建一个子类对象,调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法。54.什么是父类引用指向子类对象?是java多态一种特殊的表现形式。创建父类引用,让该引用指向一个子类的对象55.当父类引用指向子类对象的时候,子类重写了父类方法和属性,那么当访问属性的时候,访问是谁的属性?调用方法时,调用的是谁的方法?子类重写了父类方法和属性,访问的是父类的属性,调用的是子类的方法56.Super与this表示什么?Super表示当前类的父类对象This表示当前类的对象57.抽象的关键字是什么?Abstract58.抽象类必须要有抽象方法吗不是必须。抽象类可以没有抽象方法。59.如果一个类中有抽象方法,那么这个一定是抽象类?包含抽象方法的类一定是抽象类60.抽象类
有次一个同事让我一同去面试一个候选人,没仔细看简历,所以在问了设计模式之后就让他谈一谈对内存泄漏和垃圾回收的理解,当时候选人一下子就懵了。后来才知道,他面的是初、中级开发职位,想来估计候选人心里也在骂我吧。我自己用过各式各样的方法面试候选人,也被各式各样的方式面试过。有让拿电脑直接写代码的,有让在白板上写思路、画结构的,或者挨个知识点问问题的。面试,应该是要测试候选人「是否有做好某些事情的能力」,而不应该是「知道某些事情的能力」。虽然这两者往往是相关的,但有很大一部分问题却是对「把事情做好」没有任何帮助的。其中的一类是那些「你不用的时候只是大概知道,需要使用的时候花一分钟就可以搞清楚」的问题,就算你是一个比较好学的开发者,平时会看一些跟工作关系不是那么大的东西,并且可以搞得很清楚,但时间一长,再去问你细节,我想同样会模糊不清,甚至会出错。本文并不是面试刷题的题库。而是希望可以通过对面试的问题进行分类,帮助Java工程师在准备面试时,可以高屋建瓴,快速找到所需的知识点。同时会给出一些好的、坏的示例,希望可以帮助到一些人。面试问题的分类关于会被问到的Java方面的问题,大致可以分为以下几类:1. Hotspot VM(Runtime、GC、JIT)相关问题这些问题其实属于要了解的东西,对指导编码、问题排查、运行时逻辑的理解都有好处。但如果非要问你G1、CMS、Serial垃圾回收器各自的实现方法及其不同,除非你面的就是做JVM调优的职位,那你也是倒了霉了,解决方案只能是面试前突击巩固这方面的知识。2. JDK中特定类的使用问题如果你的工作会用到一些类,可能你会很熟悉,但老实说,还是会有很多类用了很多次,每次都要去源码里看注释的情况……有注释为毛要浪费珍贵的脑容量。有病3. JDK中特定类(或操作符、关键字)的实现问题相信很大一部分(有工作经验的)工程师的工作内容是不需要考虑这些问题的,但很多有追求的工程师都很乐意去探索这些问题,比如HashMap的实现原理,TransferQueue的算法逻辑。但是,那么多类,谁能保证全部记得很清楚,如果有,一定是来面试前背过了。4. 其他一些变态的陷阱问题各种乱花渐欲迷人眼的问题,如「重载和重写的区别」「final、finally、finalize的区别」之流,实在无力吐槽。出这些题的人估计是想要考察你的基本功,但又怀着不耐烦的心情,所以挖个坑看你怎么跳。有种你编程不用搜索引擎啊。这里换个姿势问,面试官的逼格立马就显现了。比如「JDK如何保证在try-catch-finally中的finally块一定会被执行的?」,但这就属于第3类问题了,如果回答不出来,应该引导他通过已有的知识和自己的想法去实现。5. 解决实际问题这是真正有价值的问题,可以考察人的思维及解决问题能力的问题。而且不论是业务相关,亦或是技术理论相关的,都可以问出有价值的问题。如「自己设计一个ArrayList/LinkedBlockingQueue」,「设计一个秒杀系统」,「如果碰到XXX问题,你估计是哪里出的问题」等等。6. 与Java无关的问题这种问题通常是为了考察应聘者的性格、人品、知识面、学习能力等,比如「简单描述一下HTTPS的工作流程」、「最近是否有在看书或者哪方面的知识」等。有些有套路,可以抱抱佛脚,通过刷题刷出来。其他的只能自求多福了。相关问题示例下面是一些从网上看到或者自己被问到过的一些问题,仅供参考。第一类问题1. 简单描述一下JVM的GCA:随意发挥……可以参考Java 9中的GC调优基础这是一个典型的比较有开放性的问题,面试者可以从自己了解的方面入手,如分代、运行时内存结构。如果对垃圾回收器比较了解,那更可以侃侃而谈。如果被问到了比较有针对性的问题,那就看你面试前的课补的好不好了。2. Java中有哪些多线程同步的手段这个问题也可以延伸出很多知识,synchronized的实现原理、synchronized中的锁膨胀、为什么有时候使用volatile可以带来更好的性能、悲观锁&乐观锁的概念、新一代的基于Lock的锁机制,更甚者可能会问到Java的内存模型(JMM)。第二类问题1. StringBuilder vs StringBufferA:前者是后者不加锁的版本,使用场景BlaBla……现在还有人问这个问题,只有两种可能:1. 面试官或者候选人的水平比较初级;2. 面试官一下子想不到别的好问的。2. Java8比Java7添加了什么新的特性A:Lambda、streams、接口默认方法……我要是背书背的好早学文科了。3. Java自带线程池判断线程池是否已经结束运行的方法叫什么A:isShutdown和isTerminated。4. BlockingQueue,CountDownLatch及Semeaphore的使用场景5. java.util.Date与java.sql.Date有什么区别A:继承关系不知道这个问题的意义在哪里。6. 如果要从LinkedBlockingQueue中取出头部对象,分别哪个方法会返回null、抛错、阻塞A:take - 阻塞,poll - 返回null,remove - 抛错第三类问题1. ThreadLocal的实现原理A:就是一个只有当前线程可访问的以ThreadLocal实例为Key的HashMap,其内部的Map实现和HashMap的实现差不多,这个Map的实例存储在Thread对象上,所以通过封装,能保证线程只访问自己的ThreadLocal变量。好吧,很可能面试官想听到的就是这样一句话。但ThreadLocal之所以重要其实是其背后的设计思想,它将变量从共享的和需要多线程同步的环境转移到了线程私有和不需要同步的环境内,这种思想可以用来解决很多不同的场景下的问题。但是,谁关心这些呢?2. LinkedList的实现原理A:它是一个双向列表,实现了List、Deque、Cloneable等接口老实说,Deque(双向队列)这个东西见过几次,但没用过,所以现在也说不太清楚它的特征和实际使用场景,所以也不想胡侃。3. ConcurrentHashMap的实现原理A:它是一个对写操作加了锁的HashMap,不同的是它做了二次分割,元素被存储在不同的桶里,以见效锁的数据范围,提升性能。在JDK8中对这种实现又进行了修改,JDK8中的ConcurrentHashmap基于CAS和TreeBin实现的,不需要对segment或者全局加锁,只需要对单行枷锁(hashCode相同),后边的链表是链表加红黑树。对于单个值的修改使用CAS。面试官很可能想听到的是这样,但这里重要的是分治的概念。其实完全可以让候选人尝试自己去设计一个ConcurrentHashMap,然后引导他去拆分HashMap,这样才是正道啊。4. hashcode()和equals()的关系A:根据JVM标准,equals()相等的对象,hashcode()应该永远相对,反之则不一定,详见HashMap的实现。这个问题其实挺好的,但如果只是简单的问一下,没有任何意义,仍然考的是记忆力。5. TransferQueue的算法是什么样的,它和BlockingQueue有哪些不同A:源代码里有。这么回答肯定是不好的,还是去补补课吧。如果你觉得面试官问这个太无聊,可以拿到offer后丑拒。第五类问题1. 用 wait-notify 写一段代码来解决生产者-消费者问题,更进一步,在分布式的环境下怎么解决A:哈哈哈,我们来写段代码吧……wait()和notify()都是线程间通信的方法,可以直接对线程的行为进行操作。他们的本质其实是传递生产者-消费者各自的消息,理解了这一点,那么在分布式环境下就很简单了,只要找到一个第三方的可以用来传递消息的媒介(Zookeeper、Redis、Kafka等)就可以了。2. 设计一个线程池A:可以参考Java线程池的理论与实践如果对JDK的线程池java.util.concurrent.ThreadPoolExecutor比较了解,可以把一些简单的特性放上去。如果不了解,可以直接设计一个线程数组,然后加一些业务逻辑。所谓线程池,基本也就如此。3. 设计一个IOC容器A:用反射,注解,还有IOC的理论第六类问题1. 谈谈你对C10K问题的理解A:NIO对BIO在吞吐量上的优势,可以参考从I/O模型到Netty(一)我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
上周陪同之前一起工作的同事去面试(乔治,小袁,鹏飞(面试人)),第一站是去深圳,第二站上海,第三站杭州。面试什么公司我在这里就不多说了,你们知道是一线公司就行。其实本来真的没打算写这篇文章,主要是自己的记忆力不是很好,再者是最近好多人询问2018年最新的面试题有点多,我实在回答不过来,而且怕为了避免重复回答,给自己省点力气,干脆就在这里统一回复了。说实话,虽作为陪同人,面试的时候我是不可以一同进去面试的,鹏飞在面试完后出来也是凭借他模糊的记忆,来慢慢回忆当时HR问的几个问题,以下是我整理的一些面试题,虽然不是很完整,但差不多也是必问的几个题目了(前言告诉大家,面试的答案我就不一个一个的写出来了,毕竟等级的不同,回答时的答案也不同,这全靠大家自己慢慢领悟了)我能帮的也只有这么多了。以下便是面试题。第一站:(深圳)1. 多个线程同时读写,读线程的数量远远⼤于写线程,你认为应该如何解决 并发的问题?你会选择加什么样的锁?2. JAVA的AQS是否了解,它是⼲嘛的?3. 除了synchronized关键字之外,你是怎么来保障线程安全的?4. 什么时候需要加volatile关键字?它能保证线程安全吗?5. 线程池内的线程如果全部忙,提交⼀个新的任务,会发⽣什么?队列全部 塞满了之后,还是忙,再提交会发⽣什么?6. Tomcat本身的参数你⼀般会怎么调整?7. synchronized关键字锁住的是什么东⻄?在字节码中是怎么表示的?在内 存中的对象上表现为什么?8. wait/notify/notifyAll⽅法需不需要被包含在synchronized块中?这是为什 么?9. ExecutorService你⼀般是怎么⽤的?是每个service放⼀个还是⼀个项⽬ ⾥⾯放⼀个?有什么好处?第二,第三站Spring1. 你有没有⽤过Spring的AOP? 是⽤来⼲嘛的? ⼤概会怎么使⽤?2. 如果⼀个接⼝有2个不同的实现, 那么怎么来Autowire⼀个指定的实现?3. Spring的声明式事务 @Transaction注解⼀般写在什么位置? 抛出了异常 会⾃动回滚吗?有没有办法控制不触发回滚?4. 如果想在某个Bean⽣成并装配完毕后执⾏⾃⼰的逻辑,可以什么⽅式实 现?5. SpringBoot没有放到web容器⾥为什么能跑HTTP服务?6. SpringBoot中如果你想使⽤⾃定义的配置⽂件⽽不仅仅是 application.properties,应该怎么弄?7. SpringMVC中RequestMapping可以指定GET, POST⽅法么?怎么指定?8. SpringMVC如果希望把输出的Object(例如XXResult或者XXResponse)这 种包装为JSON输出, 应该怎么处理?9. 怎样拦截SpringMVC的异常,然后做⾃定义的处理,⽐如打⽇志或者包装 成JSON10. 1.struts1和struts2的区别11. .struts2和springMVC的区别12. spring框架中需要引用哪些jar包,以及这些jar包的用途13. springMVC的原理14. springMVC注解的意思15. spring中beanFactory和ApplicationContext的联系和区别16. spring注入的几种方式17. spring如何实现事物管理的18. springIOC和AOP的原理19. hibernate中的1级和2级缓存的使用方式以及区别原理20. spring中循环注入的方式MySQL1. 如果有很多数据插⼊MYSQL 你会选择什么⽅式?2. 如果查询很慢,你会想到的第⼀个⽅式是什么?索引是⼲嘛的?3. 如果建了⼀个单列索引,查询的时候查出2列,会⽤到这个单列索引吗?4. 如果建了⼀个包含多个列的索引,查询的时候只⽤了第⼀列,能不能⽤上 这个索引?查三列呢?5. 接上题,如果where条件后⾯带有⼀个 i + 5 < 100 会使⽤到这个索引吗?6. 怎么看是否⽤到了某个索引?7. like %aaa%会使⽤索引吗? like aaa%呢?8. drop、truncate、delete的区别?9. 平时你们是怎么监控数据库的? 慢SQL是怎么排查的?10. 你们数据库是否⽀持emoji表情,如果不⽀持,如何操作?11. 你们的数据库单表数据量是多少?⼀般多⼤的时候开始出现查询性能急 剧下降?12. 查询死掉了,想要找出执⾏的查询进程⽤什么命令?找出来之后⼀般你 会⼲嘛?13. 读写分离是怎么做的?你认为中间件会怎么来操作?这样操作跟事务有 什么关系? 14. 分库分表有没有做过?线上的迁移过程是怎么样的?如何确定数据是正 确的?15. MySQL常用命令16. 数据库中事物的特征?17. JDBC的使用?18. InnodB与MyISAM的区别19. MySQL为什么使用B+树作为索引?JVM1. 你知道哪些或者你们线上使⽤什么GC策略? 它有什么优势,适⽤于什么 场景?2. JAVA类加载器包括⼏种?它们之间的⽗⼦关系是怎么样的?双亲委派机 制是什么意思?有什么好处?3. 如何⾃定义⼀个类加载器?你使⽤过哪些或者你在什么场景下需要⼀个⾃ 定义的类加载器吗?4. 堆内存设置的参数是什么? 5. Perm Space中保存什么数据? 会引起OutOfMemory吗? 6. 做gc时,⼀个对象在内存各个Space中被移动的顺序是什么?7. 你有没有遇到过OutOfMemory问题?你是怎么来处理这个问题的?处理 过程中有哪些收获?8. 1.8之后Perm Space有哪些变动? MetaSpace⼤⼩默认是⽆限的么? 还是 你们会通过什么⽅式来指定⼤⼩?9. Jstack是⼲什么的? Jstat呢? 如果线上程序周期性地出现卡顿,你怀疑可 能是gc导致的,你会怎么来排查这个问题?线程⽇志⼀般你会看其中的什么 部分?10. StackOverFlow异常有没有遇到过?⼀般你猜测会在什么情况下被触 发?如何指定⼀个线程的堆栈⼤⼩?⼀般你们写多少?多线程1) 什么是线程?2) 线程和进程有什么区别?3) 如何在Java中实现线程?4) 用Runnable还是Thread?6) Thread 类中的start() 和 run() 方法有什么区别?7) Java中CyclicBarrier 和 CountDownLatch有什么不同?8) Java中的volatile 变量是什么?9) Java中的同步集合与并发集合有什么区别?10) 如何避免死锁?11) Java中活锁和死锁有什么区别?12) Java中synchronized 和 ReentrantLock 有什么不同?13) Java中ConcurrentHashMap的并发度是什么?14) 如何在Java中创建Immutable对象?15) 单例模式的双检锁是什么?16) 写出3条你遵循的多线程最佳实践17) 如何避免死锁?18. 常用的线程池模式以及不同线程池的使用场景Netty1.BIO、NIO和AIO的区别?2.NIO的组成?3.Netty的特点?4.Netty的线程模型?5.TCP 粘包/拆包的原因及解决方法?6.了解哪几种序列化协议?7.如何选择序列化协议?8.Netty的零拷贝实现?9.Netty的高性能表现在哪些方面?10.NIOEventLoopGroup源码?Redis1.Redis与Memorycache的区别?2.Redis的五种数据结构?3.渐进式rehash过程?4.rehash源码?5.持久化机制6.reaof源码?7.事务与事件8.主从复制9.启动过程10.集群11.Redis的6种数据淘汰策略12.redis的并发竞争问题?Hadoop1.HDFS的特点?2.客户端从HDFS中读写数据过程?3.HDFS的文件目录结构?4.NameNode的内存结构?5.NameNode的重启优化?6.Git的使用?7.Maven的使用好了,到这里面试题差不多已经写完了,如果以上的面试题题目你已经全部理解,全部能回答出来了,那么我可以在这里告诉你,你牛批,我服。如果以上题目还不会的,还回答不上来的,那么你可以跟着我的脚步,我来介绍一下我总结出来的几大体系。以下就是我总结出来的几大体系图:一、源码分析二、分布式架构三、微服务四、性能优化五、Java工程化总结:以上就是我要说的写的内容,希望以上的内容可以帮助到正在默默艰辛,遇到瓶疾且不知道怎么办的Java程序员们,我能帮你的只有这么多了,面试题已经总结完了,我能帮的,也只有这么多了,希望大家在往后的工作与面试中,一切顺利。我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。