本博客面试题大多参考骆昊的博客,再加上我进行技术培训的时候整理的面试题
想要查看更多原理性的知识,请到原博查看https://blog.csdn.net/jackfrued/article/details/44931137#comments
1、面向对象的特征有哪些方面?
1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程
2)继承:继承是从已有的类中得到继承信息创建新类的过程
3)封装:封装是把数据和操作数据的方法绑定起来,只能通过已定义的接口去访问
4)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应,多态性分为编译时的多态性(方法重载)和运行时的多态性(方法重写)。要实现多态要做三件事情:a.继承 b.重写 c.父类型引用子类型对象
2、方法重写和方法重载的区别
方法重写(override):子类中出现与父类签名相同的方法,访问修饰符要高于父类,返回值类型,参数列表都相同
方法重载(overlord):一个类内部或子类中出现两个及两个以上方法名相同,参数列表不同的方法(返回值、参数列表无所谓)
3、访问修饰符
public:当前类、同包、子类、其他包
protected:当前类、同包、子类
default:当前类、同包 不写访问修饰符时默认的
friendly:当前类、同包
private:当前类
4、String是最基本的数据类型吗?
不是。Java中最基本的数据类型有8个: short16、long64、int32、double64、float32、byte8、char16、boolean1
除了最基本的数据类型,其他的都是引用类型,String属于引用类型
5、float f=3.4是否正确?
不正确。3.4是双精度数(double),将double型赋值给浮点型属于下转型,会造成精度缺失,因此需要强制转换float f =(float)3.4;或者写成float f=3.4F;
6、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
前者错误,后者正确。对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换
7、Java有没有goto?
goto是java中的保留字,在目前版本的Java中没有使用。
8、基本数据类型各种对应的包装类型(即引用数据类型)是什么?有什么区别?
基本数据类型:short、long、int、double、float、char、byte、boolean
对应包装类型:Short、Long、Integer、Double、Float、Character、Byte、Boolean
Java是面向对象编程语言,为了编程方便引入了基本数据类型,为了能将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型,从Java 5开始引入了自动装箱/拆箱机制,使得两者可以相互转换。
自动装箱拆箱示例:
class AutoUnboxingTest {
public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3; // 将3自动装箱成Integer类型
int c = 3;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
}
}
面试题举例:
public class Test03 {
public static void main(String[] args) {
Integer a = 3;
Integer b = 3;
Integer a1 = 150;
Integer b1 = 150;
Integer a2 = new Integer(3);
Integer b2 = 3;
System.out.println(a==b);//true
System.out.println(a1==b1);//false
System.out.println(a2==b2);//false
}
}
注解:如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,所以上面的面试题中a==b的结果是true,而a1==b1的结果是false
9、&与&&的区别
两者都是要求运算符的两端的布尔值都是true,整个表达式的值才是true,但是&&是短路运算,如果左边表达式的值为false,则右边表达式会被直接短路掉
应用:
在验证用户登录时判定用户名不是null也不是空字符串,应当写成username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常
10、解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法
栈:基本数据类型的变量,对象的引用,函数调用的现场(每个线程包含一个栈区,数据私有,其他栈不能访问);
堆:new关键字和构造器创建的对象,堆是垃圾收集器管理的主要区域(被所有线程共享);
方法区:存储、常量、静态static变量、JIT编译器编译后的代码、已经被JVM加载的类信息等数据;程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在常量池中,常量池是方法区的一部分(方法区被所有线程共享)
栈、堆、方法区不存在包含关系
举例说明:
String str = new String("hello");
其中str放在栈中,用new创建出来的字符串放在堆中,而hello这个字面量放在方法区中
11、switch表达式的作用类型
Java5以前:char、byte、int、short
Java5以后:引入枚举类型enum
Java7以后:在以前的基础上引入了String类型
12、用最有效率的方法计算2乘以8
2<<3
左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方
13、数组有没有length()方法?String有没有length()方法?
数组没有length()方法,有length属性。String有length()方法。在JavaScript中获得字符串长度是通过length属性得到的,不要弄混。
14、在Java中,如何跳出当前的多重嵌套循环?
答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环
15、continue与break的区别
continue:跳出本次循环
break:跳出当前循环
16、构造器是否可以被重写
构造器不能被继承,因此不能被重写,但是可以被重载
17、两个对象值相同,equals方法返回true,但却可有不同的hashcode,这句话对不对?
不对。如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同
18、是否可以继承String类?
String类是final类,不可以被继承
19、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递,Java语言的方法调用只支持参数的值传递,当一个对象实例作为一个参数被传递到方法中时,参数是对该对象的引用,对象的属性可以在被调用过程中被改变。
20、String和StringBuilder、StringBuffer的区别?
String:String一旦赋值或实例化后就不可更改,如果赋予新值将会重新开辟内存地址进行存储
StringBuffer、StringBuilder类改变字符串值时只是在原有对象的存储的内存地址上进行连续操作,减少了资源的开销,两者的区别是:
StringBuffer:线程安全的,同步的,效率比较低,jdk1.0之后出现
StringBuilder:线程不安全的,不同步的,效率比较高,jdk1.5之后出现
面试题举例:
1)什么情况下用+运算符进行字符串连接比调用StringBuffer/StringBuilder对象的append方法连接字符串性能更好?
答:当常量
2)请说出下面程序的输出
public static void main(String[] args) {
String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program";
String s4 = "ming";
String s5 = "Program" + "ming";
String s6 = s3 + s4;
System.out.println(s1 == s2);//false
System.out.println(s1 == s5);//true为什么?内存解释
System.out.println(s1 == s6); //false 为什么?内存解释
System.out.println(s1 == s6.intern());//true 常量池中已有"Programming",指向同一地址
System.out.println(s2 == s2.intern());//false 一个在堆内存中,一个在常量池中
}
注解:String对象的intern方法会得到字符串对象在常量池中的引用,如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用
21、描述一下JVM加载class文件的原理机制
JVM中类的装载是由类加载器和他的子类来实现的,由于Java的跨平台性,经过编译的Java源程序并不是一个可执行的程序,而是一个或多个类文件,类的加载把类的.class文件中的数据读入到内存中,然后产生与所加载类对应的class对象,加载完成后,class对象还不完整,所以此时的类还不可用,最后JVM对类进行初始化,包括:a.如果类存在直接的父类,并且这个类还没有被初始化,那么就先初始化父类;b.如果类中存在初始化语句,就依次执行这些初始化语句
22、char型变量能不能存储一个中文汉字,为什么?
能,因为Java中使用的编码是Unicode,一个char类型占两个字节(16byte),所以没有问题。
23、抽象类和接口有什么异同
相同点:
不同点:
24、静态嵌套类(Static Nested Class)和内部类()的不同
静态嵌套类(Static Nested Class)是被声明为静态的内部类,他可以不依赖外部类实例被实例化。而内部类需要在外部类实例化之后才能实例化
举例:
Person.Student s1 = Person.new Student();
Student是Person的内部类,内部类只能通过外部类Person才能创建Student对象
面试题举例:下面的代码哪些地方会产生编译错误?
class Outer {
class Inner {}
public static void foo() { new Inner(); }
public void bar() { new Inner(); }
public static void main(String[] args) {
new Inner();
}
}
注解:Java中非静态内部类对象的创建要依赖其外部类对象,上面代码中foo和main方法是静态方法,静态方法中没有this,也就是外部类对象,因此无法创建内部类对象,如果要在静态方法中创建内部类对象,可以这样
new Outer().new Inner();
25、 Java 中会存在内存泄漏吗,请简单描述
理论上Java因为有垃圾回收机制(GC),不会存在内存泄漏问题,然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄漏的发生。例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。
26、抽象方法是否可以同时是静态的,是否可以是本地方法(native),是否可同时被synchronized修饰,为什么?
都不能。
27、阐述静态变量和实例变量的区别
静态变量是被static修饰的变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且只有一个拷贝;
实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它
28、是否可以从一个静态方法内部发出对非静态方法的调用
不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象。
29、如何实现对象克隆
1)浅表克隆:复制原对象所有变量的备份,不包括引用类型
该对象所在的类实现Cloneable接口并重写clone()方法
2)深表克隆:复制原对象所有变量的备份,包括引用类型
该对象以及该对象内部的引用类型也要类实现Cloneable接口并重写clone()方法
30、GC是什么,为什么要有GC?
GC是垃圾收集的意思,Java提供的GC功能可以自动检测对象是否超过作用域从而达到自动回收内存的目的
垃圾回收可以有效防止内存泄漏,有效的使用可以使用的内存
31、String s = new String("xyz");创建了几个字符串对象?
两个对象,一个是方法区的“xyz”,一个是用new创建在堆上的对象
32、接口是否可以继承接口?抽象类是否可以实现接口?抽象类是否可以继承具体类
1)接口可以继承接口,并且支持多重继承
2)抽象类可以实现接口,抽象类除了不能实例化对象以外,其他和普通类一样
3)抽象类可以继承具体类,也可以继承抽象类
33、一个“.java”源文件是否可以包含多个类(不是内部类),有什么限制?
可以,但一个源文件最多只能有一个公开类并且文件名必须和公开类的类名完全保持一致
34、Anonymous Inner Class(匿名内部类)是否可以继承其他类?是否可以实现接口?
可以继承其他类,也可以实现接口
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制
一个内部类可以访问创建它的外部类的成员,包括私有成员
36、Java中的final关键字有哪些用法?
1)修饰类:表示该类不能被继承
2)修饰方法:表示方法不能被重写
3)修饰变量:表示变量赋值后不能被修改
37、下列程序的运行结果是:
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
注解:运行结果是1a2b2b,创建对象时,构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再调用子类构造器,并且static快只执行一次
38、数据类型之间的转换
如何将字符串转换为基本数据类型
调用parseXXX(String)或valueOf(String)即可返回相应的基本类型
如何将基本数据类型转换成字符串
一种方法是将基本数据类型与空字符串(“”)连接(+)即可获得对应的字符串;另一种方法是调用String类中的valueOf()方法返回相应的字符串
39、如何实现字符串的反转及替换
用StringBuffer类中的reverse方法实现字符串的反转
用递归实现字符串的反转
public static String reverse(String str) {
if(str == null || str.length() <= 1) {
return str;
}
return reverse(str.substring(1)) + str.charAt(0);
}
40、怎样将GB2312编码的字符串转换为ISO-8859-1的字符串
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
41、日期和时间:
1)如何取得年月日、小时分钟秒?
public class DateTimeTest {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH)); // 0 - 11
System.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));
}
}
2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
Calendar.getInstance().getTimeInMills();
3)如何取得某月的最后一天?
Calender cal = Calendar.getInstance();
cal.getActualMaximum(Calendar.DAY_OF_MONTH);
4)如何格式化日期?
SimpleDateFormat oldDate = new SimpleDateFormat("yyyy/MM/dd");
Date date1 = new Date();
System.out.println(oldDate.format(date1));
42、打印昨天的当前时刻
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE,-1);
System.out.println(cal.getTime());
43、比较一下Java和JavaScript
基于对象和面向对象:Java是一种面向对象的语言,JavaScript是一种脚本语言,是一种基于对象和事件驱动的解释性语言,它本身提供了非常丰富的内部对象供设计人员使用
解释和编译:Java源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其代码不需要经过编译,由浏览器解释执行。
强类型变量和弱类型变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量之前不作声明,JavaScript的解释器在运行时检查推断其数据类型。
代码格式不一样
44、什么时候用断言(assert)
断言在软件开发中是一种常用的调试方式,用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启,在软件发布后关闭。
45、Error和Exception有什么区别?
Error表示系统级的错误和程序不必处理的异常,是很难恢复的严重问题,比如:内存溢出
Exception表示需要程序处理的异常,是一种设计和实现的问题
46、什么情况下调用doGet()和doPost()。
Jsp页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost()。
47、线程的基本概念、线程的基本状态
基本概念:线程,是最小的程序运行体,是进程中的一个实体,是被系统独立调度和分派的基本单位
线程的基本状态:就绪、阻塞、运行
48、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?
会执行,在方法返回调用之前执行
49、Java类可以作为类型定义机制和数据封装机制
50、在调用方法时,若要使方法改变实参的值,可以用对象作为参数
对于基本类型,在方法中修改形参不影响实参
对于对象,在方法中修改形参影响实参
51、以下声明合法的是:B
A)default String s;语法错误,如果什么都不写表示default,但是不能显示的写default
B)public final static native int w()
C)abstract double d;abstract不能修饰成员变量
D)abstract final double hyperbolicCosine()abstract不能喝final同时存在
52、简述下Java中“==”和equals方法有什么区别
“==”用来表示两个变量是否相同,即内存地址是否相同
equals方法用来表示两个对象的内容是否相同(地址可以不同)
53、Java中是如何实现跨平台的?
JVM是运行在平台之上的程序,能够虚拟出一台目标机。所有字节码就在虚拟出的目标机上运行
54、Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用
Java通过面向对象的方法对异常进行处理,每个异常都是一个对象,当一个方法出现异常后便抛出一个异常对象,调用这个对象的方法可以捕捉到这个异常并可以对其进行处理
Java处理异常一般是通过5个关键词来实现的:try、catch、finally、throw、throws
try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获异常的类型;finally为确保一段代码不管发生什么异常都要被执行;throw语句用来明确的抛出一个异常,在方法里面、throws用来声明一个方法可能抛出的各种异常,在方法外面
55、throw与throws的区别
throw:在方法里面抛出异常,只能明确的抛出一个异常对象名,由方法体内的语句处理异常。
throws:在方法外面抛出异常,声明一个方法可能抛出的异常(允许无病呻吟),可以是多个,后面异常范围要比前面大,由该方法的调用者来处理异常
56、运行时异常与受检异常有何异同
运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见错误,只要程序设计的没有问题就不会发生。
受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发
Java编译器要求方法必须声明抛出可能发生的受检异常,但是运行时异常不要求
57、列出一些你常见的运行时异常
ArithmeticException 算术异常
NullPointerException 空指针异常
ClassCastException 类转换异常
IndexOutOFBoundsException 下标越界异常
SecurityException 安全异常
IllegalArgumentException 非法参数异常
58、阐述fianl、finally、finalize的区别
final:如果一个类被声明为final,则这个类不能被继承;将变量声明为final,在声明时必须赋初始值,且在以后的引用中不可修改;将方法声明为final,则不能被重写
finally:通常放在try。。。catch。。的后面,为确保一段代码不管发生什么异常都要被执行,通常放一些释放外部资源的代码
finalize:object类中定义的方法,这个方法是在由垃圾收集器在销毁对象时调用的,通过重写finalize方法可以整理系统资源或者执行其他清理工作
59、类ExampleA继承Exception,类ExampleB继承ExampleA
有如下代码片断:
try {
throw new ExampleB("b")
} catch(ExampleA e){
System.out.println("ExampleA");
} catch(Exception e){
System.out.println("Exception");
}
请问执行此段代码的输出是什么?
答:输出:ExampleA。
60、说出下面代码的运行结果。(此题的出处是《Java编程思想》一书)
class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
class Human {
public static void main(String[] args)
throws Exception {
try {
try {
throw new Sneeze();
}
catch ( Annoyance a ) {
System.out.println("Caught Annoyance");
throw a;
}
}
catch ( Sneeze s ) {
System.out.println("Caught Sneeze");
return ;
}
finally {
System.out.println("Hello World!");
}
}
}
答: Caught Annoyance
Caught Sneeze
Hello World!
61、List、Set、Map是否继承自Collection接口
List、Set是,Map不是。Map是键值对映射容器,Set无序且唯一、List有序不唯一
62、Collection和Collections的区别
Collection是一个接口,他是Set、List等容器的父接口;
Collections是一个工具类,提供一系列的排序、线程安全化等静态方法来辅助容器操作
63、List、Map、Set三个接口存取元素时,各有什么特点?
List:以特定索引来存取元素,可以有重复元素
Set:不能存放重复元素
Map:保存键值对映射,映射关系可以是一对一或多对一。
64、阐述ArrayList、Vector、LinkedList的存储性能和特性
ArrayList:底层物理存储为线性的,线程不安全,查询效率高,删除、添加等操作效率低
Vector:底层物理存储为线性的,线程安全的,数据安全,效率比较低
LinkedList:底层物理存储为链表的,查询效率低,删除、添加等操作效率高
65、TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?
TreeMap:要求存放的键值对映射的键必须实现Comparable接口,从而根据键值对进行排序
TreeSet:要求存放对象所属的类必须实现Comparable接口,当插入元素时会调用CompareTo()方法比较元素的大小
Collections:工具类的sort方法有两种重载形式
第一种:要求容器内存放的元素可比较,实现Compatator接口以实现元素的比较
第二种:不强制要求要求传入的元素可比较,但要传入第二个参数,即Comparator接口的子类型
66、Thread类的sleep()方法和Object类的wait()方法都可以让线程暂停执行,他们有什么区别?
sleep()方法:调用此方法会让当前线程进入阻塞状态,对象的锁依然保持,休眠时间到会自动进入就绪状态
wait()方法:调用此方法会让当前线程进入对象的等待池,放弃对象的锁,只有调用notify()方法才能唤醒等待池中的线程进入等锁池(如果线程重写获得对象的锁就可以进入就绪状态)
67、进程和线程的区别:
进程:是CPU调度和分派一个独立单位,执行时有独立的内存单元
线程:是进程的一个实体,是CPU调度和分派的基本单位,执行时可以共享内存
需要强调的是,不是线程越多,程序的性能越好
68、线程的sleep()方法和yield()方法有什么区别?
1)sleep方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程运行机会;yield方法只会给相同优先级或更高优先级线程运行机会
2)sleep方法执行完后进入阻塞状态;yield方法执行完后进入就绪状态
3)sleep方法声明抛出InterruptedException,yield方法没有声明任何异常
4)sleep方法比yield方法具有更好的可移植性
69、当一个线程进入一个对象的synchronized方法A后,其他线程是否可以进入此对象的synchronized方法B?
不能,其他线程只能访问该对象的非同步方法,因为synchronized修饰符要求执行方法时要获得对象的锁,如果一个线程已经进入A方法,说明对象的锁已经被取走,那么试图进入B方法的其他线程就只能在等锁池中等待对象的锁
70、请说出与线程同步已经线程调度相关的方法
1)wait():使一个线程处于阻塞(等待)状态,并且释放所持有的对象的锁
2)sleep():使当前线程进入阻塞状态,对象的锁依然保持,调用此方法需处理InterruptedException
3)notify():唤醒一个处于等待状态的线程,由JVM确定唤醒哪个线程,与优先级无关
4)notityAll():唤醒所有处于等待状态的线程,唤醒后不是所有线程都会进入就绪状态,只有获得锁的线程才会
71、编写多线程程序有几种实现方式?
Java5以前:继承Thread类、实现Runnable接口
两种方式都要通过重写run()方法,推荐使用后者,因为Java是单继承多实现,一个类如果继承了Thread就无法继承其他类了,所以使用Runnable接口更为灵活
Java5以后:增加实现Callable接口方法
72、synchronized关键字的用法
synchronized关键字可以将对象或者方法标记为同步
对象:synchronized(对象){。。。}:可以对本类对象(this)和其他类对象(new)加锁,无法得知哪些方法是被synchronize保护的
方法:synchronized void 方法名(参数){。。。}:只能对本类对象加锁,整个方法的所有语句加锁,可以显示得知方向是被synchronize保护的
73、同步和异步有什么异同
同步:发送一个请求,需要等待返回,然后才能发送下一个要求。举例:银行的转账系统、数据库的保存操作
异步:发送一个请求,不需要等待返回,就可以发送下一个请求。举例:大多数项目优先使用异步交互
74、启动一个线程是调用run()还是start()方法
调用start()方法,这意味着线程可以由JVM调度并执行,并不意味着线程会立即运行。run()方法是线程启动后要进行回调的方法。
75、什么是线程池
线程池就是事先创建若干个可执行的线程放入一个池中,需要的时候从池中获取线程不用自行创建,使用完毕后放回池中不需要销毁线程,从而减少创建和销毁线程对象的开销
76、线程生命周期
注:阻塞状态有多种情况:a.调用wait()方法进入等待池、b.执行同步synchronize方法进入等锁池、c.调用sleep或者join方法等待休眠或者其他其他线程结束、d.发生了I/O中断
77、简述synchronized和java.util.concurrent.locks.Lock的异同
相同点:Lock的Java5以后引入的新的API,能完成synchronized所实现的所有功能
不同点:Lock比synchronized性能更好,不强制要求一定要获得锁;Lock要求程序员手工释放锁,synchronized会自动释放锁
78、Java中如何实现序列化,有什么意义?
实现序列化需要让一个类实现Serializable接口(该接口可以标注该类对象是可被序列化的),然后用一个输出流建立对象输出流并通过writeObject方法就可以写出对象;反序列化可以用一个输入流建立对象输入流,并通过readObject方法从流中读取对象。
意义:序列化为了解决对象流读写操作时可能引发的数据乱序的问题,能够实现对象的持久化,还能够用于对象的深度克隆
79、Java中有几种类型的流?
字节流和字符流。字节流继承于InputStream、OutputStream,字符流继承于Reader、Writer。
80、写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数
public final class MyUtils{
private MyUtils(){
throw new AssertionError();
}
public static int countWordInFile(String filename,String word){
BufferReader br = new BufferReader(new FileReader(filename));
int count = 0;
String line = null;
while((line = br.readLine()) != null){
int index = -1;
while(line.length() >= word.length() && (index = line.indexOf(word)) >= 0){
count++;
line = line.substring(index + word.length());
}
}
br.close();
return count;
}
}
81、如何用一个Java代码列出当前文件下的文件
public static void main(String[] args){
File f = new File(“/Users/FileDemo”);
for(File temp : f.listFiles()){
if(temp.isFile()){
System.out.println(“文件:”+ temp.getAbsolutePath());
}
}
}
82、如何用一个Java代码列出一个目录下的所有文件(需要对文件夹继续展开)
public void ListFile1(String path){
File f = new File(path);
for(File temp : f.listFiles()){
if(temp.isDirectory){
System.out.println(“文件夹:”+ temp.getAbsolutePath());
ListFile1(temp.getAbsolutePath());//递归调用
}else{
System.out.println(“文件:”+ temp.getAbsolutePath());
}
}
}
83、用Java套接字编程实现一个多线程的回显(echo)服务器(不会)
public class EchoServer{
private static final int ECHO_PORT = 6789;
public static void main(String[] args){
}
}
84、XML文档定义有几种形式?它们之间有什么本质的区别?解析XML文档有哪几种方式?
XML是可扩展的标记语言(Extensible Markup Language)
定义文档:DTD和Scheme两种形式
本质区别:Schema本身也是一个XML文件,可以被XML解析器解析,而且可以为XML承载的数据定义类型,约束能力较之DTD更强大。
XML文档解析方式:
85、你在项目中哪些地方用到了XML?
XML的主要作用有两个方面:数据交换和信息配置。
数据交换:此项功能几乎已经被JSON(JavaScript Object Notation)取代
信息配置:在项目中,将作为配置信息的硬代码写在xml文件中,Java中的很多框架都是这样做的
86、阐述JDBC操作数据库的步骤
1)导入驱动jar包
2)创建驱动类对象
3)连接数据库
4)操作数据库
5)关闭数据库
87、Statement和PreparedStatement有什么区别?哪个性能更好?
1)Statement会引起注入,PreparedStatement防止注入,增强SQL的安全性
2)PreparedStatement中的SQL语句是可以带参数的
3)PreparedStatement是预编译语句,批量处理SQL语句时有明显性能上的优势
88、在进行数据库编程时,连接池有什么用?
为了提升系统访问数据库的性能,可以事先创建若干连接到连接池中,需要时直接从连接池中获取,使用结束时归还连接池而不必关闭连接。避免了频繁创建和是否连接所造成的开销
89、使用JDBC操作数据库,如何提升读取数据的性能?如何提升更新数据库的性能?
1)通过指定结果集(ResultSet)对象的setFetchSize()方法指定每次抓取的记录数
2)可以使用PreparedStatement语句构建批处理,将若干SQL语句置于一个批处理中执行
90、什么是DAO模式
DAO(Data Access Object)是一个为访问数据库提供抽象接口的对象,接口中定义了和数据库交互的所有事务方法。当应用程序需要数据库数据时,则创建一个单独的类实现这个接口,在不暴露实现细节的前提下进行数据访问操作
91、事务的特性(ACID)是指什么?
1)原子性(Atomic):事务中的各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败
2)一致性(Consistent):事务结束后系统状态是一样的
3)隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态
4)持久性(Durable):事务完成后,即使发生灾难性的故障,通过日志和同步备份可以在故障发生后重建数据
92、JDBC中如何进行事务的处理
JDBC中,Connection提供的事务处理的方法:
93、JDBC能否处理Blob和Clob?
能处理。
Blob(Binary Large Object)大二进制对象,是为存储大的二进制数据而设计的、Clob(Character Large Object)大字符对象,是为了存储大的文本数据而设计的。JDBC中的PreparedStatement和ResultSet都提供了方法来支持Blob和Clob操作
94、简述正则表达式及其用途
简述:正则表达式就是记录文本规则的代码。
用途:用来查找某些符合复杂规则的字符串
95、Java中是如何支持正则表达式操作的?
1)Java中可以用Pattern类表示正则表达式对象,一般代码如下
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
2)Java中的String类也提供了支持正则表达式操作的方法,包括matches()、replaceAll()等
96、如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写?
public static void main(String[] args){
String str = "北京市(朝阳区)(西城区)(海淀区)";
Pattern p = Pattern.compile(“.*?(?=\\()”);
Matcher m = p.matcher(str);
if(m.find()){ //查找与该模式匹配的下一个子序列
System.out.println(m.group()); //返回匹配的子序列
}
}
97、获得一个类的类对象有哪些方式
1)类型.class 如:String.class
2)对象.getClass() 如:student.getClass()
3)class.forName() 如:Class.forName(“java.lang.String”)
98、如何通过反射创建对象
1)通过类对象调用newInstance()方法,例如:String.class.newInstance()
2)通过类对象调用getConstructor()方法获得构造器对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);
99、如何通过反射获取和设置对象私有字段的值
可以通过类对象调用getDeclaredField()方法,再通过setAccessible(true)将其设置成可访问的,接下来可以通过get/set方法来获取/设置字段的值了(字段可以是基本类型、对象类型)
Field f = clazz.getDeclaredField(fs[i]);
f.setAccessible(true);
Object target = f.get(target);
100、如何通过反射调用对象方法
public static void main(String[] args) throws Exception{
String str = “hello”;
Method m = str.getClass().getMethod(“toUpperCase”);
System.out.println(m.invoke(str)); //HELLO
}
101、简述一下面向对象的“六原则一法则”
1)单一职责原则:一个类只有单一职责,就是高内聚
2)开闭原则:软件实体应该对扩展开放,对修改关闭
3)依赖倒转原则:面向接口编程,声明方法和变量尽量使用抽象类型,因为抽象类型可以被他的任何一个子类型替代
4)里氏替换原则:任何时候都可以用子类型替换掉父类型
5)接口隔离原则:一个接口只应该描述一种能力,接口也是高度内聚的
6)合成聚合复用原则:优先使用聚合或合成关系复用代码,优先采用Has-A(关联)关系而不是Is-A(继承)关系复用代码
7)迪米特法则:又叫最小知识法则,一个对象应该对其他对象尽可能少的了解,就是低耦合
102、为什么要优先使用组合而不是继承
继承破坏封装性,父类有很多细节都是对子类可见的,如果父类的实现发生改变,那么子类的实现也将发生改变,导致了子类行为的不可预知性,并且从父类继承来的实现是无法在运行期动态改变的,降低了应用的灵活性。组合将已有的对象组合到新对象中,因此新对象可以调用已有对象的功能,组合关系中各个对象的内部实现是隐藏的,我们只能通过接口调用,因此我们完全可以在运行期间实现同样接口的另外一个对象来替代原对象,从而灵活实现运行期间的行为控制
103、简述一下你了解的设计模式
使用设计模式是为了可重用代码、保证代码的可靠性、让代码更容易被他人理解。常用设计模式如下:
104、用Java写一个单例类
两个条件:构造器私有、公开的静态方法向外界返回唯一实例
1)饿汉式模式
public class A{
private A(){} //将构造器自由化,只能被本类实例化
private static A instance = new A();//实例化对象
public static A getInstance(){
return instance; //此类对象只能通过此方法获取返回值
}
}
2)懒汉式模式
public class A{
private A(){}
private static A instance = null;
public static A getInstance(){
if(instance == null){
instance = new A();
return instance;
}
}
}
105、用Java写一个冒泡排序
public static void main(String[] args){
int[] arr = {1,2,3,4,8,5,6,1,2};
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
System.out.print(arr[i]);
}
}
106、用Java写一个折半查找
public static int harfSearch(int[] srcArray,int des){
int low = 0;
int high = srcArray.length-1;
while(low<=high){
int middle = (low+high)/2;
if(des == srcArray[middle]){
return middle;
}else if(des<srcArray[middle]){
high = middle-1;
}else {
low = middle+1;
}
}
return -1;
}
public static void main(String[] args) {
int[] src = new int[] {1, 3, 5, 7, 8, 9};
System.out.println(harfSearch(src, 3));
}
107、Java有几种设计模式
1)单例设计模式:让类的构造方法私有化,同时提供一个静态方法去实例化这个类
2)单工厂设计模式:写一个类,让他制造出我们想要的所有对象
3)适配器设计模式:通过写一个适配器类,里面写了所有的抽象方法,但是这些方法是空的
4)模板设计模式:在类中定义一个抽象方法,由子类去实现