Java工程师笔试面试题集 一

一、笔试题目:

1. 简述类与对象的区别,Java 虚函数的作用。

类是对象的抽象,对象是类的具体实例。
类是抽象的,不占用内存,而对象是具体的,占有内存空间。

java中没有虚函数的概念,普通函数就相当于C++中的虚函数,不过可以在函数前加final使函数不能被重写。虚函数的作用是允许在派生类中重新定义与基类同名的函数,是多态性的一种体现。

2. Database table 写SQL语句去掉重复的记录,保留其中ID最小的一条。

delete from tablename where id not in (select min(id) from tablename group by col1,col2,...)

3. 分析两个for循环的优缺点:

(1)

1 for(i=0; i<N; i++)
2       {
3            if(condition)
4                 DoSomething();
5            else
6                 DoOtherthing();
7       }

(2)

 1 if(condition)
 2       {
 3            for(i=0; i<N; i++)
 4                 DoSomething();
 5       }
 6 else
 7       {
 8            for(i=0; i<N; i++)
 9                 DoOtherthing();
10       }

程序(1)(前者):
优点:程序简洁
条件判断出现在for里面,意味着,即使我在DoSomething()或DoOtherthing()这2个函数中改变了condition的值,for循环也能正确执行我的意图,因为它在每次循环中都会重新检测conditon的值并针对condition的值做不同动作,所谓以不变应万变,这是难能可贵的.
缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。
如果condition一直未曾改变,我们可怜的if必须每次循环都判断一下condition的真假.牺牲了运行时效率.

程序(2)(后者):
优点:循环的效率高。只进行一次判断,运行时效率高.适合那种condition的值不会改变的情况.
缺点:由于只在一开始进行一次判断,所以失去了改变condition的值的机会,也就是说,即使我在DoSomething()中改变了condition的值为false,这个程序也不会改变它的判断,它依然执行着DoSomething()的循环.我们不能随时更换我们需要进行的动作。这是牺牲了弹性。

N较大时,建议采用后面这种写法,由于前者老要进行逻辑判断,打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。

4. 1-100的自然数,放到长度为99的数组a[]中,设计一个好的方法,能够方便地找出未被放入的数。

1 int total = 0;
2 for (int i=0; i<99; i++) {
3     total += a[i];
4 }
5 System.out.println("未被放入的数是:"+(5050-total));

其他方法:
1).先将数组中的99个数字进行排序,然后将1-100个数字依次在数组中折半查找,可以借用java中已有的
Arrays.binarySearch
2).其实如果数组可以换成集合的话,可以直接判断集合中是否contain这1-100个数字就可以了
3).用HashMap实现,把数字1-100都放入HashMap中,key为数字,value随便,比如为1,for循环遍历长度为99的数组,对HashMap移除当前数字的key,最后剩下的1个数即是所求。

5. 用递归实现100!。

 1 import java.math.BigInteger;
 2
 3 public class factorial {
 4
 5     public static BigInteger callFactorial(int n) {
 6         if (n < 1)
 7             throw new IllegalArgumentException();
 8
 9         if (n == 1)
10             return BigInteger.ONE;
11
12         return callFactorial(n - 1).multiply(BigInteger.valueOf(n));
13     }
14
15     public static void main(String[] args) {
16         System.out.println(callFactorial(100));
17     }
18 }

6. 设计模式:Singleton、Factory(代码)

【转】Java:单例模式的七种写法

第一种(懒汉,线程不安全):

 1 public class Singleton {
 2     private static Singleton instance;
 3
 4     public static Singleton getInstance() {
 5     if (instance == null) {
 6         instance = new Singleton();
 7     }
 8     return instance;
 9     }
10 }  

这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。

第二种(懒汉,线程安全):

 1 public class Singleton {
 2     private static Singleton instance;
 3
 4     public static synchronized Singleton getInstance() {
 5     if (instance == null) {
 6         instance = new Singleton();
 7     }
 8     return instance;
 9     }
10 }  

这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

第三种(饿汉):

1 public class Singleton {
2     private static Singleton instance = new Singleton();
3
4     public static Singleton getInstance() {
5     return instance;
6     }
7 }  

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。

第四种(饿汉,变种):

 1 public class Singleton {
 2     private Singleton instance = null;
 3     static {
 4     instance = new Singleton();
 5     }
 6
 7     public static Singleton getInstance() {
 8     return this.instance;
 9     }
10 }  

表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。

第五种(静态内部类):

1 public class Singleton {
2     private static class SingletonHolder {
3     private static final Singleton INSTANCE = new Singleton();
4     }
5
6     public static final Singleton getInstance() {
7     return SingletonHolder.INSTANCE;
8     }
9 }  

这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。

第六种(枚举):

1 public enum Singleton {
2     INSTANCE;
3     public void whateverMethod() {
4     }
5 } 

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

第七种(双重校验锁):

 1 public class Singleton {
 2     private volatile static Singleton singleton;
 3
 4     public static Singleton getSingleton() {
 5     if (singleton == null) {
 6         synchronized (Singleton.class) {
 7         if (singleton == null) {
 8             singleton = new Singleton();
 9         }
10         }
11     }
12     return singleton;
13     }
14 }

这个是第二种方式的升级版,俗称双重检查锁定,详细介绍请查看:http://www.ibm.com/developerworks/cn/java/j-dcl.html
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。

总结
有两个问题需要注意:
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。
2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

对第一个问题修复的办法是:

 1 private static Class getClass(String classname)
 2                                          throws ClassNotFoundException {
 3       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 4
 5       if(classLoader == null)
 6          classLoader = Singleton.class.getClassLoader();
 7
 8       return (classLoader.loadClass(classname));
 9    }
10 }

对第二个问题修复的办法是:

 1 public class Singleton implements java.io.Serializable {
 2    public static Singleton INSTANCE = new Singleton();
 3
 4    protected Singleton() {
 5
 6    }
 7    private Object readResolve() {
 8             return INSTANCE;
 9       }
10 }

对我来说,我比较喜欢第三种和第五种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第三种方式,只有在要明确实现lazy loading效果时才会使用第五种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全的,而且我永远不会使用第一种和第二种方式,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。

Factory模式:待续。

时间: 2024-10-10 12:34:15

Java工程师笔试面试题集 一的相关文章

Java程序员面试题集(1-50)

下面的内容是对网上原有的Java面试题集及答案进行了全面修订之后给出的负责任的题目和答案,原来的题目中有很多重复题目和无价值的题目,还有不少的参考答案也是错误的,修改后的Java面试题集参照了JDK最新版本,去掉了EJB 2.x等无用内容,补充了数据结构和算法相关的题目.经典面试编程题.大型网站技术架构.操作系统.数据库.软件测试.设计模式.UML等内容,同时还对很多知识点进行了深入的剖析,例如hashCode方法的设计.垃圾收集的堆和代.Java新的并发编程.NIO.2等,相信对准备入职的Ja

Java程序员面试题集(71-85)

Java程序员面试题集(71-85) 摘要:这一部分主要包括了UML(统一建模语言).面向对象的设计原则(六原则一法则).GoF设计模式.企业级设计模式.JDBC(Java数据库连接).XML(可扩展标记语言)等知识. 71.UML是什么?UML中有哪些图? 答:UML是统一建模语言(Unified Modeling Language)的缩写,它发表于1997年,综合了当时已经存在的面向对象的建模语言.方法和过程,是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化

java高级工程师开放面试题集&lt;二&gt;

临近年关,不少人蠢蠢欲动,有童鞋问我java后端面试会面试什么? 作为一个java后端老鸟,跌打滚爬多次被面试和面试别人,总结了一些经验,希望对大家有所帮助. 特别说明,仅仅针对工作两年以上的java后端开发.以开放性题目为主,没有标准答案. 上篇<java高级工程师开放面试题集<一>> 本次是第二篇: 6.缓存相关 如何设计实现LRU缓存? Least Recently Used,最近最少使用缓存. 思路: 6.1.每个key 需要有value,最近的使用时间戳 6.2.面向对象

西安尚学堂练习09.11|Java编程笔试面试题

功能描述:删除字符串中字符个数最少的字符,最少字符串有多个,最少的要全部删除,然后返回该子字符串.输入:asdasdas输出:asasas解答:import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry

西安尚学堂练习09.17|Java编程笔试面试题

下列哪些类型能被throw语句抛出? A. Error B. Exception C. Throwable D. Object [解]注意Error也是可以被throw的,只是通常Error出现程序就中断了,我们并不会去捕获. 2.编程:给定两个字符串A,B(只包含26个英文字母),输出所有公共的最长子字符串(如果出现重复子串,则输出多次) 输入包括两行,每行为一个连续字符串(大小写敏感) 输出包括多行,每行为扫描到的最长公共子串,按照该子串在字符串A(即第一行输入字符串)中出现的先后次序输出

Java程序员面试题集(51-70)

摘要:这一部分主要讲解了异常.多线程.容器和I/O的相关面试题.首先,异常机制提供了一种在不打乱原有业务逻辑的前提下,把程序在运行时可能出现的状况处理掉的优雅的解决方案,同时也是面向对象的解决方案.而Java的线程模型是建立在共享的.默认的可见的可变状态以及抢占式线程调度两个概念之上的.Java内置了对多线程编程的支持在20世纪90年代可以说是一个巨大的进步,但是最初的设计在当下看来已经给程序带来很多困扰了.感谢Doug Lea在Java 5中提供了他里程碑式的杰作java.util.concu

Java程序员面试题集(181- 199)

Java面试题集(181-199) 摘要:这部分是包含了Java高级玩法的一些专题,对面试者和新入职的Java程序员相信都会有帮助的. 181.  182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199.

Java程序猿面试题集(181- 199)

Java面试题集(181-199) 摘要:这部分是包括了Java高级玩法的一些专题,对面试者和新入职的Java程序猿相信都会有帮助的. 181.  182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199.

Java程序员面试题集2

51.类ExampleA 继承Exception,类ExampleB 继承ExampleA. 有如下代码片断: [java] view plain copy try{ throw new ExampleB("b") }catch(ExampleA e){ System.out.println("ExampleA"); }catch(Exception e){ System.out.println("Exception"); } 请问执行此段代码的