兰州创新思维吧 关注:151贴子:1,849

【2015届】我在面试中遇到的问题

只看楼主收藏回复

经过20天的奔波,终于在今天签了一家单位,职位是java程序员。
在这20天中也有了差不多10次的面试经历,然而大多都挂在了一面(技术面试),下面把我遇到过的问题给大家说说吧。
一般的公司面试都分为2轮,第一轮技术面,主要是问的java的专业知识,有的公司问的比较基础,有些公司问的问题会比较高大上。第二轮是hr面试,会问到性格方面的吧(么有进几次2面(╯﹏╰),不了解)。
下面是我被经常问到或者印象深刻的问题(答案是百度的,重在理解)


1楼2014-10-30 14:46回复
    1、http和https的区别:
    HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议 它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版。 http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议 http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。 http的连接很简单,是无状态的。HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议 要比http协议安全 。
    2、jstl 和 el
    这个我还是不会,百度出来挺长的,大家自己百度了看吧。


    2楼2014-10-30 14:49
    回复
      3、socket(套接字)
      用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
      Socket连接过程:
      根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。


      3楼2014-10-30 14:52
      回复
        5、java中yield(),sleep()以及wait()的区别
        (原文链接:http://blog.csdn.net/java2000_net/article/details/2551072
        从操作系统的角度讲,os会维护一个ready queue(就绪的线程队列)。并且在某一时刻cpu只为ready queue中位于队列头部的线程服务。 但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield。 或者当前正在被服务的线程需要睡一会,醒来后继续被服务,这就是sleep。
        sleep方法不推荐使用,可用wait。 线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行。
        sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。 sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。
        当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
        waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
        彻底明白多线程通信机制:
        线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
        1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
        2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
        3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。 4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当再次对该线程调用notify或notifyAll后它才能再次回到可执行状态。


        6楼2014-10-30 15:04
        回复
          6、java如何进行异常处理
          Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理。
          用try来指定一块预防所有”异常”的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的”异常”的类型。
          throw语句用来明确地抛出一个”异常”。
          throws用来标明一个成员函数可能抛出的各种”异常”。
          Finally为确保一段代码不管发生什么”异常”都被执行一段代码。
          可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,”异常”的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的try语句。


          7楼2014-10-30 15:06
          回复
            7、java垃圾回收机制 Garbage Collection
            Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。
            需要注意的是:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,很多人来我公司面试时,我都会问这个问题的,70%以上的人回答的含义是回收对象,实际上这是不正确的。
            System.gc()
            Runtime.getRuntime().gc()
            上面的方法调用时用于显式通知JVM可以进行一次垃圾回收,但真正垃圾回收机制具体在什么时间点开始发生动作这同样是不可预料的,这和抢占式的线程在发生作用时的原理一样。


            8楼2014-10-30 15:11
            回复
              8、synchronized的用法
              在java编程思想中对synchronized的一点解释:
              1、synchronized关键字的作用域有二种:
              1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
              2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
              2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象;
              3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。


              9楼2014-10-30 15:17
              回复
                9、回文数字
                在java里怎么弄 输入一个5位正整数,使用数组判断它是不是回文数(例如:12321、1551、5是回文数)。
                要求不能将整数转化为字符串做。
                import java.io.*;
                import java.util.Scanner;
                public class Test
                {
                public static void main(String[] args)
                {
                Scanner scanner = new Scanner (System.in);
                //int x=12321;
                int x=0;
                x=scanner.nextInt();
                int dig[]=new int[16];
                int n=0;
                while(x!=0)
                {
                dig[n++] = x%10;
                x/=10;
                }
                int flag=1;
                for(int i=0;in/2;i++)
                {
                if(dig[i]!=dig[n-1-i])
                { flag=0;break; }
                }
                if(flag==1) System.out.println(Yes\n);
                else System.out.println(No\n);
                }
                }


                10楼2014-10-30 15:22
                回复
                  9、怎么样吧阿拉伯数字转换成大写的(要考虑好零在不同位的情况。比如输入2015007,会得到“贰佰零壹万伍仟零柒”,输入101200,会得到“拾万一千二佰”)。我找个了还包括了小数的程序,大家可以自己改改或者百度其他的。
                  import java.math.BigDecimal;
                  public class NumberFormatChinese {
                  public static void main(String[] args) {
                  System.out.println(toBigMode(1000));
                  System.out.println(toBigMode(1005));
                  System.out.println(toBigMode(1002002));
                  System.out.println(toBigMode(100));;
                  }
                  public static String toBigMode(double value)
                  {
                  final char[] NUMBER_CHAR = "零壹贰叁肆伍陆柒捌玖".toCharArray(); // 大写数字
                  final String[] IN_UNIT_CHAR = { "", "拾", "佰", "仟" }; // 段内字符
                  final String[] UNIT_NAME = { "", "万", "亿", "万亿" }; // 段名
                  long longValue = (long) (value * 100); // 转换成整数
                  // System.out.println(longValue);
                  String valStr = new BigDecimal(Math.ceil(longValue)).toString(); // 转换成字符串
                  StringBuilder prefix = new StringBuilder(); // 整数部分转化的结果
                  StringBuilder suffix = new StringBuilder(); // 小数部分转化的结果
                  if (valStr.length() <= 2) // 只有小数部分
                  {
                  prefix.append("零元");
                  if (valStr.equals("0"))
                  {
                  suffix.append("零角零分");
                  } else if (valStr.length() == 1)
                  {
                  suffix.append(NUMBER_CHAR[valStr.charAt(0) - *0*]).append("分");
                  } else
                  {
                  suffix.append(NUMBER_CHAR[valStr.charAt(0) - *0*]).append("角");
                  suffix.append(NUMBER_CHAR[valStr.charAt(1) - *0*]).append("分");
                  }
                  } else
                  {
                  int flag = valStr.length() - 2;
                  String head = valStr.substring(0, flag); // 取整数部分
                  String rail = valStr.substring(flag); // 取小数部分
                  if (head.length() > 13)
                  {
                  return "数值太大(最大支持13位整数),无法处理。";
                  }
                  // 处理整数位
                  char[] ch = head.toCharArray();
                  int zeroNum = 0; // 连续零的个数
                  for (int i = 0; i < ch.length; i++)
                  {
                  int index = (ch.length - i - 1) % 4; // 取段内位置,介于 3 2 1 0
                  int indexLoc = (ch.length - i - 1) / 4; // 取段位置,介于 3 2 1 0
                  if (ch[i] == *0*)
                  {
                  zeroNum++;
                  } else
                  {
                  if (zeroNum != 0)
                  {
                  if (index != 3)
                  {
                  prefix.append("零");
                  }
                  zeroNum = 0;
                  }
                  prefix.append(NUMBER_CHAR[ch[i] - *0*]); // 转换该位置的数
                  prefix.append(IN_UNIT_CHAR[index]); // 添加段内标识
                  }
                  if (index == 0 && zeroNum < 4) // 添加段名
                  {
                  prefix.append(UNIT_NAME[indexLoc]);
                  }
                  }
                  prefix.append("元");
                  // 处理小数位
                  if (rail.equals("00"))
                  {
                  suffix.append("整");
                  } else if (rail.startsWith("0"))
                  {
                  suffix.append(NUMBER_CHAR[rail.charAt(1) - *0*]).append("分");
                  } else
                  {
                  suffix.append(NUMBER_CHAR[rail.charAt(0) - *0*]).append("角");
                  suffix.append(NUMBER_CHAR[rail.charAt(1) - *0*]).append("分");
                  }
                  }
                  return prefix.append(suffix).toString();
                  }
                  }


                  11楼2014-10-30 15:27
                  回复
                    10、Lock和Synchronized区别
                    Lock的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的。
                    synchronized在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。
                    在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。
                    lock相对于synchronized的优势:
                    synchronized中的notify()方法不能指定唤醒具体哪一个线程,而lock中使用condition可以做到。


                    12楼2014-10-30 15:35
                    回复
                      12、线程池的作用和Executor类:
                      线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率。
                      如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。Executor这个类是一个工厂类,用来生成不同特点的ExecutorService或 ScheduledExecutorService实例。这里主要介绍这些不同特点的实例不同在什么地方。
                      3类不同的ExecutorService实例. static ExecutorService newSingleThreadExecutor() 启动一个线程负责任务顺序执行,顺序意味着先提交的任务先执行。其原理是:任务会被提交到一个队列里,启动的那个线程会从队里里取任务,然后执行, 执行完,再从队列里取下一个任务,再执行。如果该线程执行一个任务失败,并导致线程结束,系统会创建一个新的线程去执行队里里后续的任务,不会因为前面的 任务有异常导致后面无辜的任务无法执行。
                      static ExecutorService newCachedThreadPool() 启动N个线程处理N个任务。既然是多个线程运行,意味着任务不会顺序运行。一个任务完成后,该线程空闲60秒会被结束。新提交的任务会发现空闲线程,并使用它,如果没有空闲线程可用则创建新线程。其实,这就是一个动态线程池。适合于规模比较小、创建较频繁的任务。
                      static ExecutorService newFixedThreadPool(int nThreads) 动态线程池不限制线程的数量,在有些情况下我们不希望线程数量不可控,则可以使用拥有固定线程数目的线程池。运作原理是:任务被提交到一个队列里排 队,线程池里的空闲线程会把队列里的任务提出来执行,每个线程执行完一个任务后,就去队列里抓另一个任务出来执行。如果一个线程由于失败而终止,系统会创 建另一个线程执行后续任务。
                      带ThreadFactory参数生成的ExecutorService实例。以上3种实例创建工作线程时都是用的默认的线程工厂类来创建。也可 以指定自己的线程工厂类来创建,以newSingleThreadExecutor(ThreadFactory threadFactory)为例: //你自己的实现 class YourselfThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { Thread thread = new Thread(r); doXXX; return thread; } } newSingleThreadExecutor 与 newFixedThreadPool(1) 区别. JavaDoc上说:Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.
                      什么意思?不懂。为什么?不具体。具体一下就懂了。
                      ((ThreadPoolExecutor)newFixedThreadPool(1)).setCorePoolSize(3); 即newFixedThreadPool(1)可以后期修改线程数,不能保证线程只有一个。而newSingleThreadExecutor可以保证。
                      static Callablecallable(Runnable task) 把Runnable任务转换成Callable任务.例子如下
                      public static void test() throws Exception { Runnable task = new Runnable() { public void run() { log(*begin task*); try { Thread.sleep(1000); } catch (InterruptedException e) { } log(*end task*); } }; Callable c = Executors.callable(task); ExecutorService service = Executors.newCachedThreadPool(); Future f = service.submit(c); System.out.println(f.get());//返回null log(*end*); } private static void log(String message) { System.out.println(new Date() + *: * + message); } public static void main(String args[]) throws Exception { test(); }
                      JDK1.5引入的concurrent包使多线程编写更加容易、代码更容易理解、可读性更好.
                      http://www.cnblogs.com/taven/archive/2011/12/17/2291469.html


                      15楼2014-10-30 15:54
                      回复
                        13、请和街边扫地的老大爷谈谈面向对象和面向过程(即不能用任何专业术语)。


                        16楼2014-10-30 15:56
                        回复
                          14、一个技术面试官给我的忠告:要有特色,即擅长的部分。要让别人有记住你的点,估计我的点就是长得帅,经常被面试官嫉妒


                          17楼2014-10-30 15:59
                          收起回复
                            已成功收藏


                            IP属地:北京来自Android客户端18楼2014-10-30 16:51
                            回复