史上最全Java面试题整理(附参考答案)工程师搁浅

2、访问修饰符public,private,protected,以及不写(默认)时的区别?

protected当前类,同包,异包子类。

3、String是最基本的数据类型吗?

答:不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitivetype),剩下的都是引用类型(referencetype),Java5以后引入的枚举类型也算是一种比较特殊的引用类型。

4、floatf=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换floatf=(float)3.4;或者写成floatf=3.4F;

5、shorts1=1;s1=s1+1;有错吗shorts1=1;s1+=1;有错吗?

答:对于shorts1=1;s1=s1+1;由于1是int类型,因此s1+1运算结果也是int型,需要强制转换类型才能赋值给short型。而shorts1=1;s1+=1;可以正确编译,因为s1+=1;相当于s1=(short)(s1+1);其中有隐含的强制类型转换。

6、Java有没有goto?

答:goto是Java中的保留字,在目前版本的Java中没有使用。(根据JamesGosling(Java之父)编写的《TheJavaProgrammingLanguage》一书的附录中给出了一个Java关键字列表,其中有goto和const,但是这两个是目前无法使用的关键字,因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义,因为熟悉C语言的程序员都知道,在系统类库中使用过的有特殊意义的单词或单词的组合都被视为保留字)

7、int和Integer有什么区别?

答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapperclass),int的包装类就是Integer,从Java5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。Java为每个原始类型提供了包装类型:

classAutoUnboxingTest{publicstaticvoidmain(String[]args){Integera=newInteger(3);Integerb=3;//将3自动装箱成Integer类型intc=3;System.out.println(a==b);//false两个引用没有引用同一对象System.out.println(a==c);//truea自动拆箱成int类型再和c比较}}最近还遇到一个面试题,也是和自动装箱和拆箱有点关系的,代码如下所示:

publicclassTest03{publicstaticvoidmain(String[]args){Integerf1=100,f2=100,f3=150,f4=150;System.out.println(f1==f2);System.out.println(f3==f4);}}如果不明就里很容易认为两个输出要么都是true要么都是false。首先需要注意的是f1、f2、f3、f4四个变量都是Integer对象引用,所以下面的==运算比较的不是值而是引用。装箱的本质是什么呢?当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,如果看看valueOf的源代码就知道发生了什么。

publicstaticIntegervalueOf(inti){if(i>=IntegerCache.low&&i<=IntegerCache.high)returnIntegerCache.cache[i+(-IntegerCache.low)];returnnewInteger(i);}IntegerCache是Integer的内部类,其代码如下所示:

提醒:越是貌似简单的面试题其中的玄机就越多,需要面试者有相当深厚的功力。

8、&和&&的区别?

补充:如果你熟悉JavaScript,那你可能更能感受到短路运算的强大,想成为JavaScript的高手就先从玩转短路运算开始吧。

9、解释内存中的栈(stack)、堆(heap)和方法区(methodarea)的用法。

答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为FromSurvivor和ToSurvivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在常量池中,常量池是方法区的一部分,。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足则会引发OutOfMemoryError。

Stringstr=newString("hello");上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而"hello"这个字面量是放在方法区的。

补充1:较新版本的Java(从Java6的某个更新开始)中,由于JIT编译器的发展和"逃逸分析"技术的逐渐成熟,栈上分配、标量替换等优化技术使得对象一定分配在堆上这件事情已经变得不那么绝对了。

补充2:运行时常量池相当于Class文件常量池具有动态性,Java语言并不要求常量一定只有编译期间才能产生,运行期间也可以将新的常量放入池中,String类的intern()方法就是这样的。

看看下面代码的执行结果是什么并且比较一下Java7以前和以后的运行结果是否一致。

Strings1=newStringBuilder("go").append("od").toString();System.out.println(s1.intern()==s1);Strings2=newStringBuilder("ja").append("va").toString();System.out.println(s2.intern()==s2);10、Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。

11、switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?

答:在Java5以前,switch(expr)中,expr只能是byte、short、char、int。从Java5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

12、用最有效率的方法计算2乘以8?

答:2<<3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。

补充:我们为编写的类重写hashCode方法时,可能会看到如下所示的代码,其实我们不太理解为什么要使用这样的乘法运算来产生哈希码(散列码),而且为什么这个数是个素数,为什么通常选择31这个数?前两个问题的答案你可以自己百度一下,选择31是因为可以用移位和减法运算来代替乘法,从而得到更好的性能。说到这里你可能已经想到了:31*num等价于(num<<5)-num,左移5位相当于乘以2的5次方再减去自身就相当于乘以31,现在的VM都能自动完成这个优化。

publicclassPhoneNumber{privateintareaCode;privateStringprefix;privateStringlineNumber;@OverridepublicinthashCode(){finalintprime=31;intresult=1;result=prime*result+areaCode;result=prime*result+((lineNumber==null)0:lineNumber.hashCode());result=prime*result+((prefix==null)0:prefix.hashCode());returnresult;}@Overridepublicbooleanequals(Objectobj){if(this==obj)returntrue;if(obj==null)returnfalse;if(getClass()!=obj.getClass())returnfalse;PhoneNumberother=(PhoneNumber)obj;if(areaCode!=other.areaCode)returnfalse;if(lineNumber==null){if(other.lineNumber!=null)returnfalse;}elseif(!lineNumber.equals(other.lineNumber))returnfalse;if(prefix==null){if(other.prefix!=null)returnfalse;}elseif(!prefix.equals(other.prefix))returnfalse;returntrue;}}13、数组有没有length()方法?String有没有length()方法?

答:数组没有length()方法,有length的属性。String有length()方法。JavaScript中,获得字符串的长度是通过length属性得到的,这一点容易和Java混淆。

14、在Java中,如何跳出当前的多重嵌套循环?

答:在最外层循环前加一个标记如A,然后用breakA;可以跳出多重循环。(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)

15、构造器(constructor)是否可被重写(override)?

答:构造器不能被继承,因此不能被重写,但可以被重载。

16、两个对象值相同(x.equals(y)==true),但却可有不同的hashcode,这句话对不对?

答:不对,如果两个对象x和y满足x.equals(y)==true,它们的哈希码(hashcode)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

补充:关于equals和hashCode方法,很多Java程序都知道,但很多人也就是仅仅知道而已,在JoshuaBloch的大作《EffectiveJava》(很多软件公司,《EffectiveJava》、《Java编程思想》以及《重构:改善既有代码质量》是Java程序员必看书籍,如果你还没看过,那就赶紧去亚马逊买一本吧)中是这样介绍equals方法的:首先equals方法必须满足自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(当x和y引用的对象信息没有被修改时,多次调用x.equals(y)应该得到同样的返回值),而且对于任何非null值的引用x,x.equals(null)必须返回false。实现高质量的equals方法的诀窍包括:1.使用==操作符检查"参数是否为这个对象的引用";2.使用instanceof操作符检查"参数是否为正确的类型";3.对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;4.编写完equals方法后,问自己它是否满足对称性、传递性、一致性;5.重写equals时总是要重写hashCode;6.不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@Override注解。

17、是否可以继承String类?

答:String类是final类,不可以被继承。

补充:继承String本身就是一个错误的行为,对String类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)。

18、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是按值传递还是按引用传递?

答:是按值传递。Java语言的方法调用只支持参数的按值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但在方法内部对对象引用的改变是不会影响到被调用者的。C++和C#中可以通过传引用或传输出参数来改变传入的参数的值。在C#中可以编写如下所示的代码,但是在Java中却做不到。

usingSystem;namespaceCS01{classProgram{publicstaticvoidswap(refintx,refinty){inttemp=x;x=y;y=temp;}publicstaticvoidMain(string[]args){inta=5,b=10;swap(refa,refb);//a=10,b=5;Console.WriteLine("a={0},b={1}",a,b);}}}说明:Java中没有传引用实在是非常的不方便,这一点在Java8中仍然没有得到改进,正是如此在Java编写的代码中才会出现大量的Wrapper类(将需要通过方法调用修改的引用置于一个Wrapper类中,再将Wrapper对象传入方法),这样的做法只会让代码变得臃肿,尤其是让从C和C++转型为Java程序员的开发者无法容忍。

19、String和StringBuilder、StringBuffer的区别?

答:Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。

面试题1-什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append方法连接字符串性能更好?

面试题2-请说出下面程序的输出。

classStringEqualTest{publicstaticvoidmain(String[]args){Strings1="Programming";Strings2=newString("Programming");Strings3="Program";Strings4="ming";Strings5="Program"+"ming";Strings6=s3+s4;System.out.println(s1==s2);System.out.println(s1==s5);System.out.println(s1==s6);System.out.println(s1==s6.intern());System.out.println(s2==s2.intern());}}补充:解答上面的面试题需要清除两点:1.String对象的intern方法会得到字符串对象在常量池中对应的版本的引用(如果常量池中有一个字符串与String对象的equals结果是true),如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用;2.字符串的+操作其本质是创建了StringBuilder对象进行append操作,然后将拼接后的StringBuilder对象用toString方法处理成String对象,这一点可以用javap-cStringEqualTest.class命令获得class文件对应的JVM字节码指令就可以看出来。

20、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

面试题:华为的面试题中曾经问过这样一个问题-"为什么不能根据返回类型来区分重载",快说出你的答案吧!

因为调用时不能指定类型信息,编译器不知道你要调用哪个函数。例如:

floatmax(inta,intb);intmax(inta,intb);当调用max(1,2);时无法确定调用的是哪个,单从这一点上来说,仅返回值类型不同的重载是不应该允许的。

21、描述一下JVM加载class文件的原理机制?

22、char型变量中能不能存贮一个中文汉字,为什么?

答:char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char类型占2个字节(16比特),所以放一个中文是没问题的。

补充:使用Unicode意味着字符在JVM内部和外部有不同的表现形式,在JVM内部都是Unicode,当这个字符被从JVM内部转移到外部时(例如存入文件系统中),需要进行编码转换。所以Java中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如InputStreamReader和OutputStreamReader,这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务;对于C程序员来说,要完成这样的编码转换恐怕要依赖于union(联合体/共用体)共享内存的特征来实现了。

23、抽象类(abstractclass)和接口(interface)有什么异同?

24、静态嵌套类(StaticNestedClass)和内部类(InnerClass)的不同?

/***扑克类(一副扑克)**/publicclassPoker{privatestaticString[]suites={"黑桃","红桃","草花","方块"};privatestaticint[]faces={1,2,3,4,5,6,7,8,9,10,11,12,13};privateCard[]cards;/***构造器**/publicPoker(){cards=newCard[52];for(inti=0;i

classPokerTest{publicstaticvoidmain(String[]args){Pokerpoker=newPoker();poker.shuffle();//洗牌Poker.Cardc1=poker.deal(0);//发第一张牌//对于非静态内部类Card//只有通过其外部类Poker对象才能创建Card对象Poker.Cardc2=poker.newCard("红心",1);//自己创建一张牌System.out.println(c1);//洗牌后的第一张System.out.println(c2);//打印:红心A}}面试题-下面的代码哪些地方会产生编译错误?

classOuter{classInner{}publicstaticvoidfoo(){newInner();}publicvoidbar(){newInner();}publicstaticvoidmain(String[]args){newInner();}}注意:Java中非静态内部类对象的创建要依赖其外部类对象,上面的面试题中foo和main方法都是静态方法,静态方法中没有this,也就是说没有所谓的外部类对象,因此无法创建内部类对象,如果要在静态方法中创建内部类对象,可以这样做:

newOuter().newInner();25、Java中会存在内存泄漏吗,请简单描述。

答:理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。下面例子中的代码也会导致内存泄露。

26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?

答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

27、阐述静态变量和实例变量的区别。

答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

补充:在Java开发中,上下文类和工具类中通常会有大量的静态成员。

28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

29、如何实现对象克隆?

答:有两种方式:1).实现Cloneable接口并重写Object类中的clone()方法;2).实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下:

importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;publicclassMyUtil{privateMyUtil(){thrownewAssertionError();}@SuppressWarnings("unchecked")publicstaticTclone(Tobj)throwsException{ByteArrayOutputStreambout=newByteArrayOutputStream();ObjectOutputStreamoos=newObjectOutputStream(bout);oos.writeObject(obj);ByteArrayInputStreambin=newByteArrayInputStream(bout.toByteArray());ObjectInputStreamois=newObjectInputStream(bin);return(T)ois.readObject();//说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义//这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放}}下面是测试代码:

30、GC是什么?为什么要有GC?

补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会根据Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:

31、Strings=newString("xyz");创建了几个字符串对象?

答:两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

32、接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concreteclass)?

答:接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。

举一个多继承的例子,我们定义一个动物(类)既是狗(父类1)也是猫(父类2),两个父类都有“叫”这个方法。那么当我们调用“叫”这个方法时,它就不知道是狗叫还是猫叫了,这就是多重继承的冲突。而接口没有具体的方法实现,所以多继承接口也不会出现这种冲突。

33、一个".java"源文件中是否可以包含多个类(不是内部类)?有什么限制?

答:可以,但一个源文件中最多只能有一个公开类(publicclass)而且文件名必须和公开类的类名完全保持一致。

34、AnonymousInnerClass(匿名内部类)是否可以继承其它类?是否可以实现接口?

答:可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和回调。

35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?

答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

36、Java中的final关键字有哪些用法?

答:(1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

37、指出下面程序的运行结果。

classA{static{System.out.print("1");}publicA(){System.out.print("2");}}classBextendsA{static{System.out.print("a");}publicB(){System.out.print("b");}}publicclassHello{publicstaticvoidmain(String[]args){Aab=newB();ab=newB();}}答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。

提示:如果不能给出此题的正确答案,说明之前第21题Java类加载机制还没有完全理解,赶紧再看看吧。

38、数据类型之间的转换:如何将字符串转换为基本数据类型?如何将基本数据类型转换为字符串?

答:

39、如何实现字符串的反转及替换?

答:方法很多,可以自己写实现也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:

publicstaticStringreverse(StringoriginStr){if(originStr==null||originStr.length()<=1)returnoriginStr;returnreverse(originStr.substring(1))+originStr.charAt(0);}40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?

答:代码如下所示:

答:问题1:创建java.util.Calendar实例,调用其get()方法传入不同的参数即可获得参数所对应的值。Java8中可以使用java.time.LocalDateTimel来获取,代码如下所示。

publicclassDateTimeTest{publicstaticvoidmain(String[]args){Calendarcal=Calendar.getInstance();System.out.println(cal.get(Calendar.YEAR));System.out.println(cal.get(Calendar.MONTH));//0-11System.out.println(cal.get(Calendar.DATE));System.out.println(cal.get(Calendar.HOUR_OF_DAY));System.out.println(cal.get(Calendar.MINUTE));System.out.println(cal.get(Calendar.SECOND));//Java8LocalDateTimedt=LocalDateTime.now();System.out.println(dt.getYear());System.out.println(dt.getMonthValue());//1-12System.out.println(dt.getDayOfMonth());System.out.println(dt.getHour());System.out.println(dt.getMinute());System.out.println(dt.getSecond());}}问题2:以下方法均可获得该毫秒数。

Calendar.getInstance().getTimeInMillis();System.currentTimeMillis();Clock.systemDefaultZone().millis();//Java8问题3:代码如下所示。

42、打印昨天的当前时刻。

importjava.util.Calendar;classYesterdayCurrent{publicstaticvoidmain(String[]args){Calendarcal=Calendar.getInstance();cal.add(Calendar.DATE,-1);System.out.println(cal.getTime());}}在Java8中,可以用下面的代码实现相同的功能。

importjava.time.LocalDateTime;classYesterdayCurrent{publicstaticvoidmain(String[]args){LocalDateTimetoday=LocalDateTime.now();LocalDateTimeyesterday=today.minusDays(1);System.out.println(yesterday);}}43、比较一下Java和JavaSciprt。

答:JavaScript与Java是两个公司开发的不同的两个产品。Java是原SunMicrosystems公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言。JavaScript的前身是LiveScript;而Java的前身是Oak语言。下面对两种语言间的异同作如下比较:

补充:上面列出的四点是网上流传的所谓的标准答案。其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民,因此JavaScript支持函数式编程,可以使用Lambda函数和闭包(closure),当然Java8也开始支持函数式编程,提供了对Lambda表达式以及函数式接口的支持。对于这类问题,在面试的时候最好还是用自己的语言回答会更加靠谱,不要背网上所谓的标准答案。

44、什么时候用断言(assert)?

答:断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,断言用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式的值为false,那么系统会报告一个AssertionError。断言的使用如下面的代码所示:

assert(a>0);//throwsanAssertionErrorifa<=0断言可以有两种形式:assertExpression1;assertExpression1:Expression2;Expression1应该总是产生一个布尔值。Expression2可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。

要在运行时启用断言,可以在启动JVM时使用-enableassertions或者-ea标记。要在运行时选择禁用断言,可以在启动JVM时使用-da或者-disableassertions标记。要在系统类中启用或禁用断言,可使用-esa或-dsa标记。还可以在包的基础上启用或者禁用断言。

注意:断言不应该以任何方式改变程序的状态。简单的说,如果希望在不满足某些条件时阻止代码的执行,就可以考虑用断言来阻止它。

45、Error和Exception有什么区别?

答:Error表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。

面试题:2005年摩托罗拉的面试中曾经问过这么一个问题“Ifaprocessreportsastackoverflowrun-timeerror,what’sthemostpossiblecause”,给了四个选项a.lackofmemory;b.writeonaninvalidmemoryspace;c.recursivefunctioncalling;d.arrayindexoutofboundary.Java程序在运行时也可能会遭遇StackOverflowError,这是一个无法恢复的错误,只能重新修改代码了,这个面试题的答案是c。如果写了不能迅速收敛的递归,则很有可能引发栈溢出的错误,如下所示:

classStackOverflowErrorTest{publicstaticvoidmain(String[]args){main(null);}}提示:用递归编写程序时一定要牢记两点:1.递归公式;2.收敛条件(什么时候就不再继续递归)。

46、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后

答:会执行,在方法返回前执行。

注意:在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。显然,在finally中返回或者修改返回值会对程序造成很大的困扰,C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情,Java中也可以通过提升编译器的语法检查级别来产生警告或错误,Eclipse中可以在如图所示的地方进行设置,强烈建议将此项设置为编译错误。

47、Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

48、运行时异常与受检异常有何异同?

49、列出一些你常见的运行时异常?

50、阐述final、finally、finalize的区别。

51、类ExampleA继承Exception,类ExampleB继承ExampleA。有如下代码片断:

try{thrownewExampleB("b")}catch(ExampleAe){System.out.println("ExampleA");}catch(Exceptione){System.out.println("Exception");}请问执行此段代码的输出是什么?

答:输出:ExampleA。(根据里氏代换原则[能使用父类型的地方一定能使用子类型],抓取ExampleA类型异常的catch块能够抓住try块中抛出的ExampleB类型的异常)

面试题-说出下面代码的运行结果。(此题的出处是《Java编程思想》一书)

classAnnoyanceextendsException{}classSneezeextendsAnnoyance{}classHuman{publicstaticvoidmain(String[]args)throwsException{try{try{thrownewSneeze();}catch(Annoyancea){System.out.println("CaughtAnnoyance");throwa;}}catch(Sneezes){System.out.println("CaughtSneeze");return;}finally{System.out.println("HelloWorld!");}}}52、List、Set、Map是否继承自Collection接口?

答:List、Set是,Map不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。

53、阐述ArrayList、Vector、LinkedList的存储性能和特性。

答:ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector中的方法由于添加了synchronized修饰,因此Vector是线程安全的容器,但性能上较ArrayList差,因此已经是Java中的遗留容器。LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。Vector属于遗留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用,将已有对象传入另一个类的构造器中创建新的对象来增强实现)。

补充:遗留容器中的Properties类和Stack类在设计上有严重的问题,Properties是一个键和值都是字符串的特殊的键值对映射,在设计上应该是关联一个Hashtable并将其两个泛型参数设置为String类型,但是JavaAPI中的Properties直接继承了Hashtable,这很明显是对继承的滥用。这里复用代码的方式应该是Has-A关系而不是Is-A关系,另一方面容器都属于工具类,继承工具类本身就是一个错误的做法,使用工具类最好的方式是Has-A关系(关联)或Use-A关系(依赖)。同理,Stack类继承Vector也是不正确的。Sun公司的工程师们也会犯这种低级错误,让人唏嘘不已。

54、Collection和Collections的区别?

答:Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

55、List、Map、Set三个接口存取元素时,各有什么特点?

56、TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?

答:TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象必须实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。例子1:

publicclassStudentimplementsComparable{privateStringname;//姓名privateintage;//年龄publicStudent(Stringname,intage){this.name=name;this.age=age;}@OverridepublicStringtoString(){return"Student[name="+name+",age="+age+"]";}@OverridepublicintcompareTo(Studento){returnthis.age-o.age;//比较年龄(年龄的升序)}}importjava.util.Set;importjava.util.TreeSet;classTest01{publicstaticvoidmain(String[]args){Setset=newTreeSet<>();//Java7的钻石语法(构造器后面的尖括号中不需要写类型)set.add(newStudent("HaoLUO",33));set.add(newStudent("XJWANG",32));set.add(newStudent("BruceLEE",60));set.add(newStudent("BobYANG",22));for(Studentstu:set){System.out.println(stu);}//输出结果://Student[name=BobYANG,age=22]//Student[name=XJWANG,age=32]//Student[name=HaoLUO,age=33]//Student[name=BruceLEE,age=60]}}例子2:

58、线程的sleep()方法和yield()方法有什么区别?

59、当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

补充:Java5通过Lock接口提供了显式的锁机制(explicitlock),增强了灵活性以及对线程的协调。Lock接口中定义了加锁(lock())和解锁(unlock())的方法,同时还提供了newCondition()方法来产生用于线程之间通信的Condition对象;此外,Java5还提供了信号量机制(semaphore),信号量可以用来限制对某个共享资源进行访问的线程的数量。在对资源进行访问之前,线程必须得到信号量的许可(调用Semaphore对象的acquire()方法);在完成对资源的访问后,线程必须向信号量归还许可(调用Semaphore对象的release()方法)。

下面的例子演示了100个线程同时向一个银行账户中存入1元钱,在没有使用同步机制和使用同步机制情况下的执行情况。

银行账户类:

/***存钱线程*@authornnngu**/publicclassAddMoneyThreadimplementsRunnable{privateAccountaccount;//存入账户privatedoublemoney;//存入金额publicAddMoneyThread(Accountaccount,doublemoney){this.account=account;this.money=money;}@Overridepublicvoidrun(){account.deposit(money);}}测试类:

importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassTest01{publicstaticvoidmain(String[]args){Accountaccount=newAccount();ExecutorServiceservice=Executors.newFixedThreadPool(100);for(inti=1;i<=100;i++){service.execute(newAddMoneyThread(account,1));}service.shutdown();while(!service.isTerminated()){}System.out.println("账户余额:"+account.getBalance());}}在没有同步的情况下,执行结果通常是显示账户余额在10元以下,出现这种状况的原因是,当一个线程A试图存入1元的时候,另外一个线程B也能够进入存款的方法中,线程B读取到的账户余额仍然是线程A存入1元钱之前的账户余额,因此也是在原来的余额0上面做了加1元的操作,同理线程C也会做类似的事情,所以最后100个线程执行结束时,本来期望账户余额为100元,但实际得到的通常在10元以下(很可能是1元哦)。解决这个问题的办法就是同步,当一个线程对银行账户存钱时,需要将此账户锁定,待其操作完成后才允许其他的线程进行操作,代码有如下几种调整方案:

在银行账户的存款(deposit)方法上加同步(synchronized)关键字

/***存钱线程*@author张凯**/publicclassAddMoneyThreadimplementsRunnable{privateAccountaccount;//存入账户privatedoublemoney;//存入金额publicAddMoneyThread(Accountaccount,doublemoney){this.account=account;this.money=money;}@Overridepublicvoidrun(){synchronized(account){account.deposit(money);}}}通过Java5显示的锁机制,为每个银行账户创建一个锁对象,在存款操作进行加锁和解锁的操作

61、编写多线程程序有几种实现方式?

答:Java5以前实现多线程有两种实现方法:一种是继承Thread类;另一种是实现Runnable接口。两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活。

补充:Java5以后创建线程还有第三种方式:实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值,代码如下所示:

importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;classMyTaskimplementsCallable{privateintupperBounds;publicMyTask(intupperBounds){this.upperBounds=upperBounds;}@OverridepublicIntegercall()throwsException{intsum=0;for(inti=1;i<=upperBounds;i++){sum+=i;}returnsum;}}classTest{publicstaticvoidmain(String[]args)throwsException{List>list=newArrayList<>();ExecutorServiceservice=Executors.newFixedThreadPool(10);for(inti=0;i<10;i++){list.add(service.submit(newMyTask((int)(Math.random()*100))));}intsum=0;for(Futurefuture:list){//while(!future.isDone());sum+=future.get();}System.out.println(sum);}}62、synchronized关键字的用法?

63、举例说明同步和异步。

64、启动一个线程是调用run()还是start()方法?

答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。

65、什么是线程池(threadpool)?

第60题的例子中演示了通过Executors工具类创建线程池并使用线程池执行线程的代码。如果希望在服务器上使用线程池,强烈建议使用newFixedThreadPool方法来创建线程池,这样能获得更好的性能。

66、线程的基本状态以及状态之间的关系?

说明:其中Running表示运行状态,Runnable表示就绪状态(万事俱备,只欠CPU),Blocked表示阻塞状态,阻塞状态又有多种情况,可能是因为调用wait()方法进入等待池,也可能是执行同步方法或同步代码块进入等锁池,或者是调用了sleep()方法或join()方法等待休眠或其他线程结束,或是因为发生了I/O中断。

67、简述synchronized和java.util.concurrent.locks.Lock的异同?

答:Lock是Java5以后引入的新的API,和关键字synchronized相比主要相同点:Lock能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally块中释放(这是释放外部资源的最好的地方)。

68、Java中如何实现序列化,有什么意义?

答:序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会存在数据乱序的问题)。要实现序列化,需要让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆(可以参考第29题)。

69、Java中有几种类型的流?

答:字节流和字符流。字节流继承于InputStream、OutputStream,字符流继承于Reader、Writer。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。关于Java的I/O需要注意的有两点:一是两种对称性(输入和输出的对称性,字节和字符的对称性);二是两种设计模式(适配器模式和装潢模式)。另外Java中的流不同于C#的是它只有一个维度一个方向。

面试题-编程实现文件拷贝。(这个题目在笔试的时候经常出现,下面的代码给出了两种实现方案)

70、写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数。

答:代码如下:

importjava.io.BufferedReader;importjava.io.FileReader;publicfinalclassMyUtil{//工具类中的方法都是静态方式访问的因此将构造器私有不允许创建对象(绝对好习惯)privateMyUtil(){thrownewAssertionError();}/***统计给定文件中给定字符串的出现次数**@paramfilename文件名*@paramword字符串*@return字符串在文件中出现的次数*/publicstaticintcountWordInFile(Stringfilename,Stringword){intcounter=0;try(FileReaderfr=newFileReader(filename)){try(BufferedReaderbr=newBufferedReader(fr)){Stringline=null;while((line=br.readLine())!=null){intindex=-1;while(line.length()>=word.length()&&(index=line.indexOf(word))>=0){counter++;line=line.substring(index+word.length());}}}}catch(Exceptionex){ex.printStackTrace();}returncounter;}}71、如何用Java代码列出一个目录下所有的文件?

答:如果只要求列出当前文件夹下的文件,代码如下所示:

importjava.io.File;classTest12{publicstaticvoidmain(String[]args){Filef=newFile("/Users/nnngu/Downloads");for(Filetemp:f.listFiles()){if(temp.isFile()){System.out.println(temp.getName());}}}}如果需要对文件夹继续展开,代码如下所示:

importjava.io.File;classTest12{publicstaticvoidmain(String[]args){showDirectory(newFile("/Users/nnngu/Downloads"));}publicstaticvoidshowDirectory(Filef){_walkDirectory(f,0);}privatestaticvoid_walkDirectory(Filef,intlevel){if(f.isDirectory()){for(Filetemp:f.listFiles()){_walkDirectory(temp,level+1);}}else{for(inti=0;i

classShowFileTest{publicstaticvoidmain(String[]args)throwsIOException{PathinitPath=Paths.get("/Users/nnngu/Downloads");Files.walkFileTree(initPath,newSimpleFileVisitor(){@OverridepublicFileVisitResultvisitFile(Pathfile,BasicFileAttributesattrs)throwsIOException{System.out.println(file.getFileName().toString());returnFileVisitResult.CONTINUE;}});}}72、用Java的套接字编程实现一个多线程的回显(echo)服务器。

下面是一段回显客户端测试代码:

importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.PrintWriter;importjava.net.Socket;importjava.util.Scanner;publicclassEchoClient{publicstaticvoidmain(String[]args)throwsException{Socketclient=newSocket("localhost",6789);Scannersc=newScanner(System.in);System.out.print("请输入内容:");Stringmsg=sc.nextLine();sc.close();PrintWriterpw=newPrintWriter(client.getOutputStream());pw.println(msg);pw.flush();BufferedReaderbr=newBufferedReader(newInputStreamReader(client.getInputStream()));System.out.println(br.readLine());client.close();}}如果希望用NIO的多路复用套接字实现服务器,代码如下所示。NIO的操作虽然带来了更好的性能,但是有些操作是比较底层的,对于初学者来说还是有些难于理解。

74、你在项目中哪些地方用到了XML?

补充:现在有很多时髦的软件(如Sublime)已经开始将配置文件书写成JSON格式,我们已经强烈的感受到XML的另一项功能也将逐渐被业界抛弃。

75、阐述JDBC操作数据库的步骤。

答:下面的代码以连接本机的Oracle数据库为例,演示JDBC操作数据库的步骤。

加载驱动。

Class.forName("oracle.jdbc.driver.OracleDriver");创建连接。

Connectioncon=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger");创建语句。

PreparedStatementps=con.prepareStatement("select*fromempwheresalbetweenand");ps.setInt(1,1000);ps.setInt(2,3000);执行语句。

ResultSetrs=ps.executeQuery();处理结果。

while(rs.next()){System.out.println(rs.getInt("empno")+"-"+rs.getString("ename"));}关闭资源。

finally{if(con!=null){try{con.close();}catch(SQLExceptione){e.printStackTrace();}}}提示:关闭外部资源的顺序应该和打开的顺序相反,也就是说先关闭ResultSet、再关闭Statement、在关闭Connection。上面的代码只关闭了Connection(连接),虽然通常情况下在关闭连接时,连接上创建的语句和打开的游标也会关闭,但不能保证总是如此,因此应该按照刚才说的顺序分别关闭。此外,第一步加载驱动在JDBC4.0中是可以省略的(自动从类路径中加载驱动),但是我们建议保留。

76、Statement和PreparedStatement有什么区别?哪个性能更好?

答:与Statement相比,①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

补充:为了提供对存储过程的调用,JDBCAPI中还提供了CallableStatement接口。存储过程(StoredProcedure)是数据库中一组为了完成特定功能的SQL语句的集合,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。虽然调用存储过程会在网络开销、安全性、性能上获得很多好处,但是存在如果底层数据库发生迁移时就会有很多麻烦,因为每种数据库的存储过程在书写上存在不少的差别。

77、使用JDBC操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?

78、在进行数据库编程时,连接池有什么作用?

79、什么是DAO模式?

答:DAO(DataAccessObject)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是DataAccessor(数据访问器),二是DataObject(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。

80、事务的ACID是指什么?

补充:关于事务,在面试中被问到的概率是很高的,可以问的问题也是很多的。首先需要知道的是,只有存在并发数据访问时才需要事务。当多个事务访问同一数据时,可能会存在5类问题,包括3类数据读取问题(脏读、不可重复读和幻读)和2类数据更新问题(第1类丢失更新和第2类丢失更新)。

脏读(DirtyRead):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。

不可重复读(UnrepeatableRead):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。

幻读(PhantomRead):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。

第1类丢失更新:事务A撤销时,把已经提交的事务B的更新数据覆盖了。

第2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。

数据并发访问所产生的问题,在有些场景下可能是允许的,但是有些场景下可能就是致命的,数据库通常会通过锁机制来解决数据并发访问问题,按锁定对象不同可以分为表级锁和行级锁;按并发事务锁定关系可以分为共享锁和独占锁,具体的内容大家可以自行查阅资料进行了解。直接使用锁是非常麻烦的,为此数据库为用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会通过分析SQL语句然后为事务访问的资源加上合适的锁,此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来说都是透明的(就是说你不用理解,事实上我确实也不知道)。ANSI/ISOSQL92标准定义了4个等级的事务隔离级别,如下表所示:

需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。

81、JDBC中如何进行事务处理?

答:Connection提供了事务处理的方法,通过调用setAutoCommit(false)可以设置手动提交事务;当事务完成后用commit()显式提交事务;如果在事务处理过程中发生异常则通过rollback()进行事务回滚。除此之外,从JDBC3.0中还引入了Savepoint(保存点)的概念,允许通过代码设置保存点并让事务回滚到指定的保存点。

82、JDBC能否处理Blob和Clob?

答:Blob是指二进制大对象(BinaryLargeObject),而Clob是指大字符对象(CharacterLargeObjec),因此其中Blob是为存储大的二进制数据而设计的,而Clob是为存储大的文本数据而设计的。JDBC的PreparedStatement和ResultSet都提供了相应的方法来支持Blob和Clob操作。下面的代码展示了如何使用JDBC操作LOB:下面以MySQL数据库为例,创建一个张有三个字段的用户表,包括编号(id)、姓名(name)和照片(photo),建表语句如下:

createtabletb_user(idintprimarykeyauto_increment,namevarchar(20)uniquenotnull,photolongblob);下面的Java代码向数据库中插入一条记录:

答:在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

说明:计算机诞生初期处理的信息几乎都是数值,但是时过境迁,今天我们使用计算机处理的信息更多的时候不是数值而是字符串,正则表达式就是在进行字符串匹配和处理的时候最为强大的工具,绝大多数语言都提供了对正则表达式的支持。

84、Java中是如何支持正则表达式操作的?

答:Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作,请参考下面面试题的代码。

面试题:-如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写?

85、获得一个类的类对象有哪些方式?

86、如何通过反射创建对象?

87、如何通过反射获取和设置对象私有字段的值?

答:可以通过类对象的getDeclaredField()方法获得字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。下面的代码实现了一个反射的工具类,其中的两个静态方法分别用于获取和设置私有字段的值,字段可以是基本类型也可以是对象类型且支持多级对象操作,例如ReflectionUtil.get(dog,"owner.car.engine.id");可以获得dog对象的主人的汽车的引擎的ID号。

答:请看下面的代码:

importjava.lang.reflect.Method;classMethodInvokeTest{publicstaticvoidmain(String[]args)throwsException{Stringstr="hello";Methodm=str.getClass().getMethod("toUpperCase");System.out.println(m.invoke(str));//HELLO}}89、简述一下面向对象的"六原则一法则"。

90、简述一下你了解的设计模式。

91、用Java写一个单例类。

publicclassSingleton{privateSingleton(){}privatestaticSingletoninstance=newSingleton();publicstaticSingletongetInstance(){returninstance;}}懒汉式单例publicclassSingleton{privatestaticSingletoninstance=null;privateSingleton(){}publicstaticsynchronizedSingletongetInstance(){if(instance==null)instance=newSingleton();returninstance;}}注意:实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例。这里有一个问题可以思考:Spring的IoC容器可以为普通的类创建单例,它是怎么做到的呢?

92、什么是UML?

答:UML是统一建模语言(UnifiedModelingLanguage)的缩写,它发表于1997年,综合了当时已经存在的面向对象的建模语言、方法和过程,是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持。使用UML可以帮助沟通与交流,辅助应用设计和文档的生成,还能够阐释系统的结构和行为。

93、UML中有哪些常用的图?

答:UML定义了多种图形化的符号来描述软件系统部分或全部的静态结构和动态结构,包括:用例图(usecasediagram)、类图(classdiagram)、时序图(sequencediagram)、协作图(collaborationdiagram)、状态图(statechartdiagram)、活动图(activitydiagram)、构件图(componentdiagram)、部署图(deploymentdiagram)等。在这些图形化符号中,有三种图最为重要,分别是:用例图(用来捕获需求,描述系统的功能,通过该图可以迅速的了解系统的功能模块及其关系)、类图(描述类以及类与类之间的关系,通过该图可以快速了解系统)、时序图(描述执行特定任务时对象之间的交互关系以及执行顺序,通过该图可以了解对象能接收的消息也就是说对象能够向外界提供的服务)。用例图:

类图:

时序图:

94、用Java写一个冒泡排序。

答:冒泡排序几乎是个程序员都写得出来,但是面试的时候如何写一个逼格高的冒泡排序却不是每个人都能做到,下面提供一个参考代码:

importjava.util.Comparator;/***排序器接口(策略模式:将算法封装到具有共同接口的独立的类中使得它们可以相互替换)*@authornnngu**/publicinterfaceSorter{/***排序*@paramlist待排序的数组*/public>voidsort(T[]list);/***排序*@paramlist待排序的数组*@paramcomp比较两个对象的比较器*/publicvoidsort(T[]list,Comparatorcomp);}importjava.util.Comparator;/***冒泡排序**@authornnngu**/publicclassBubbleSorterimplementsSorter{@Overridepublic>voidsort(T[]list){booleanswapped=true;for(inti=1,len=list.length;i0){Ttemp=list[j];list[j]=list[j+1];list[j+1]=temp;swapped=true;}}}}@Overridepublicvoidsort(T[]list,Comparatorcomp){booleanswapped=true;for(inti=1,len=list.length;i0){Ttemp=list[j];list[j]=list[j+1];list[j+1]=temp;swapped=true;}}}}}95、用Java写一个折半查找。

importjava.util.Comparator;publicclassMyUtil{publicstatic>intbinarySearch(T[]x,Tkey){returnbinarySearch(x,0,x.length-1,key);}//使用循环实现的二分查找publicstaticintbinarySearch(T[]x,Tkey,Comparatorcomp){intlow=0;inthigh=x.length-1;while(low<=high){intmid=(low+high)>>>1;intcmp=comp.compare(x[mid],key);if(cmp<0){low=mid+1;}elseif(cmp>0){high=mid-1;}else{returnmid;}}return-1;}//使用递归实现的二分查找privatestatic>intbinarySearch(T[]x,intlow,inthigh,Tkey){if(low<=high){intmid=low+((high-low)>>1);if(key.compareTo(x[mid])==0){returnmid;}elseif(key.compareTo(x[mid])<0){returnbinarySearch(x,low,mid-1,key);}else{returnbinarySearch(x,mid+1,high,key);}}return-1;}}说明:上面的代码中给出了折半查找的两个版本,一个用递归实现,一个用循环实现。需要注意的是计算中间位置时不应该使用(high+low)/2的方式,因为加法运算可能导致整数越界,这里应该使用以下三种方式之一:low+(high-low)/2或low+(high–low)>>1或(low+high)>>>1(>>>是逻辑右移,是不带符号位的右移)

THE END
1.包含NFКB抑制剂和佐剂的方法和组合物9.本公开描述了nfкb抑制剂作为免疫增强剂在包含佐剂的疫苗组合物中的用途。因此,本公开的方面涉及为对象接种疫苗的方法,其包括向对象施用nfкb抑制剂和佐剂(或本公开的包含nfкb和佐剂的组合物)。其他方面涉及抑制与佐剂相关的炎症反应并且增强对象中的免疫应答的方法,方法包括向对象联合施用nfкb抑制剂和佐剂(...http://xjishu.com/zhuanli/05/201980091497.html
2.银华中证转债指数增强分级B股吧银华中证转债指数增强分级B股吧,股民朋友可以在这里畅所欲言,分析讨论吧名的最新动态。东方财富股吧,专业的股票论坛社区。https://guba.eastmoney.com/list,of150144,522820434.html
3.BPDM是什么意思BPDM在线翻译英语读音用法例句BPDM 英美 (=butaperazine dimaleate) 马来酸丁酰拉嗪 分享单词到:http://dict.cn/BPDM
4.TG7121B数据手册资料.pdfTG7121B 数据手册资料.pdf,TG7121B_Datasheet TG7121B 数据手册 TG7121B_Datasheet 修订记录 版本 修订日期 修订说明 作者 V1.0 2020-11-22 初始版本 V1.1 2021-02-03 增加TR_SUP 参数和参考设计 V1.2 2021-03-31 更新VIH 和VIL 信息 V1. 1 2/24 TG7121B_Datasheet 目录内https://m.book118.com/html/2023/0324/8133040121005050.shtm
5.通过翻译调控基因表达系统检测和调节细胞死亡的组合物和方法专利...55.权利要求54的哺乳动物细胞,其中胚胎干细胞是鼠胚胎干细胞mES-D3或人胚胎干细胞hES。 56.确定物质毒性的方法,其中所述方法包括: (a)使根据权利要求52-55中任一项的哺乳动物细胞与所述物质接触,其中所述第一ORF序列编码报告多肽;和 (b)检测报告多肽的存在或测量其水平,其中与未接触所述物质或未转染的对照细胞...https://www.patenthub.cn/zhuanli/patent-20407-CN101861391A-11c306e96dd586140aa40cc10c02e3ad.html
6.SUNSolaris问题小结有什么区别呢? A: 第一个是编译好的适合solaris系统的binary格式package文件 安装,可以用pkgadd命令直接添加的 后边的source文件,还没有编译 安装,需要configure,make,make install的过程 5) Q: 求助:vmware下安装solaris10之后不能改分辨率和刷新率 A: 用kdmconfig命令,然后选择Xsun,即可调整分辨率 ...http://www.cnetcom.cn/news/Technology/926.html
1.光环PMP笔记需求跟踪矩阵画图紧前关系绘图法(PDM) 活动的关系 FS(finish-start) SS(start-start) FF(finish-finish) SF(start-finish) 提前量、滞后量 提前量–压缩工期 PDM 前导图 估算资源 学习曲线 成本效益分析 当投入的成本高达一定程度时,还可能存在边际效益递减 资源日历 ...https://blog.csdn.net/snowy_y/article/details/122409936
2.java类似的语言和java类似的几门语言子类拥有父类的非private的属性和方法;子类拥有自己的属性和方法,即子类可以对父类进行扩展;子类可以用自己的方式实现父类的方法(重写);Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,...https://blog.51cto.com/u_16213717/6984252
3.答疑:点检和巡检的区别是什么?好文分享答疑6:【BPDM】李武 点检、巡检 等等相关的概念 如果没有一个行业标准或者是惯例 推荐下个定义,不用争论区别,每个企业自己的理解和做法都不一样,关键是看每个企业 对所说的概念 具体做什么 想到达一个什么样的效果。 提问者:【振动监测 刘铁安】: http://m.hb-qg.com/show-30-362-1.html
4.肇庆用友U8+V15.0的行业插件后续适配发版,以《U8+V15.0行业插件发...因IE6、IE7等低版本的浏览器自身可能存在安全漏洞、样式布局缺陷以及脚本执行效率慢等问题,可能会影响到对U8+B/S产品的功能使用及用户体验,所以建议IE6、IE7用户将浏览器升级到8.0或以上(微软官网提供免费下载),以保证U8+B/S产品的正常使用。 另:推荐在1024*768 的分辨率下使用U8+产品,分辨率太低(如800*600)...https://www.ufida168.com/case_detail/2782.html
5.水鬼的新娘干妞网人人操 105.31MB 804好评 桃红色aj 午夜伦伦色色 午夜伦欧美伦电影理论片 262.37MB 702好评 。。。美女入B动态图 69堂a毛片 精子网最新网址 39.2MB fnex白无垢怎么样 美国黑逼 玖玖玖玖亚洲精品 109.6MB 美女爬下让我c 五月天婷婷乱伦小说网站 老妇...http://www.topvr.cn/aplsamefa63987.htm
6.swPDM创建本地视图注册表失败咋办?附注册表丢失解决方法这种PDM错误的原因是什么? 此消息表明,在创建本地视图过程中,一些信息未能写入Windows的一个称为Windows注册表的区域。如果Windows用户缺乏足够的权限,SOLIDWORKS PDM可能无法写入注册表。需要以本地系统管理员身份登录该计算机,可以允许创建局部视图。 SolidWorks 2024 SP1.0 Full Premium 完美安装版(附教程) 64位 ...https://www.jb51.net/softjc/927771.html
7.闽南师范大学人工智能实验室建设项目附件c.无法按照以上a、b项规定提供财务报告复印件的投标人(包括但不限于:成立年限满1年及以上的投标人、成立年限满半年但不足1年的投标人、成立年限不足半年的投标人),应选择提供资信证明复印件。 (4)依法缴纳税收证明材料 ①投标人提供的税收凭据复印件应符合下列规定: a.投标截止时间前(不含投标截止时间的当月)...http://zfcg.czj.zhangzhou.gov.cn/upload/document/20220428/23b164a933434c7c97ec6d1817a74c80.html
8.rc.huaibin88.cn/apldome/1912219.htm金发少妇干B黑人 极品调教大胸 男人的天堂MA4 87.5MB 97%好评(478人) 爽?好舒服?好紧H男同严选漫画 91蜜柚国偷自产一区二区三区 国产 日韩 无码 澳门葡京 16.5MB 99%好评(799人) 黑丝被插 啊嗯 与马日 月岛雫什么意思 19.6MB 93%好评(660人) 换妻小说激情 91九色原 九九伊人偷拍可播放的...http://rc.huaibin88.cn/apldome/1912219.htm
9.MES管理系统基础知识(完整版)b)立法保证 组织应研究、规划并实施成本和成本管理立法,策划、建立和保持成本管理体系文件,包括:成本管理手册、程序文件、规章制度、各种定额、标准成本、全面预算、成本计划以及作业文件等成本控制文件。这些文件是成本发生过程和成本管理的依据,用来约束、指导和规范成本发生和成本管理的行为、指导成本管理工作和活动。从而...https://m.yx-win.com/h-nd-98.html
10.软件加密论文范文12篇(全文)摘要:采用C#编程语言进行软件设计,读取OSSM2004测报软中的B文件数据,并根据加密气象观测报告电码(《GD-05》)、陆地测站地面天气报告电码《GD-01Ⅲ》进行自动编译天气加密报人工录入字段;同时软件自动登陆省级加密报文保存服务器,在指定路径下查找相应时次报文,读取报文内容进行自动对比,从而检查加密报文是否发送成功和是...https://www.99xueshu.com/w/ikeykkzr5fib.html
11.少女前线:SVD但是在使用B-32穿甲燃烧弹бронебойно-зажигательныйпатронБ-32时,子弹散布扩大了2倍。因此,SVD步枪的膛线缠距在1975年被改为240mm,导致射击时的准确度降低了25%,100m上的散布由8cm扩大到了10cm(即3.44角分)。 值得一提的是,苏联当局所发行的《步枪手册》中,有关SVD...https://zh.moegirl.org/%E5%B0%91%E5%A5%B3%E5%89%8D%E7%BA%BF:SVD
12.副经理述职报告(通用17篇)3)、以人的工作质量确保工序质量,以工序质量确保工程质量;从订货、采购、检查、验收、取样、试验等方面全面控制投入产品的质量;全面控制施工过程,重点控制工序质量;坚持质量标准,严格检查,一切用数据说话,严把分项工程质量检验评定或施工质量验收关;严防系统性因素(如使用不合格材料、违反操作规程、施工机械设备突出性故障...https://www.yjbys.com/shuzhibaogao/fanwen/3659530.html