Java综合面试题
1、 面向对象的特征有哪些方面?
多态、继承、封装、抽象
多态:抽象、继承、动态绑定(向上转型)
2、 访问修饰符public,private,protected,以及不写(默认)时的区别?
public:工程下可见
private:本类可见
project:不同包非子类不可见
default:同包可见
3、String 是最基本的数据类型吗?
不是、是引用类型(类类型)
4、float f=3.4;是否正确?
不正确,精度不正确,需强转,默认的是double类型,
5、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
s1 = s1 + 1:有错,右边计算后为int型,需强转
s1 += 1;没错,java自带的运算符,会自动转型
6、Java有没有goto?
没有goto:但是是一个保留字
7、int和Integer有什么区别?
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
延伸:
关于Integer和int的比较
1、由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false
2、Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true
3、非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false
4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false
对于第4条的原因:
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:
public static IntegervalueOf(int i){
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high){
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了
8、&和&&的区别?
电路问题总结:
对于:& -- > 不管怎样,都会执行"&"符号左右两边的程序
对于:&& -- > 只有当符号"&&"左边程序为真(true)后,才会执行符号"&&"右边的程序。
下面来说说运算规则:
对于:& -- > 只要左右两边有一个为false,则为false;只有全部都为true的时候,结果为true
对于:&& -- > 只要符号左边为false,则结果为false;当左边为true,同时右边也为true,则结果为true
9、解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法。
堆区:专门用来保存对象的实例(new 创建的对象和数组),实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中)
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身.
3.一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
栈区:对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
4.由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.
静态区/方法区:
1.方法区又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
3.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
好处:1、栈代表了处理逻辑,而堆代表了数据、得处理逻辑更为清晰
2、堆中的内容可以被多个栈共享。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。
3、使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
4、面向对象就是堆和栈的完美结合,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。
10、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
Math.round(11.5):12
Math.round(-11):-11
11、switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
switch(A),括号中A的取值可以是byte、short、int、char、String,还有枚举类型
long不能
12、用最有效率的方法计算2乘以8?
2<<3
13、数组有没有length()方法?String有没有length()方法?
数组求长度用length属性
字符串求长度用length()方法
集合求长度用size()方法
14、在Java中,如何跳出当前的多重嵌套循环?
标签+break 标签名、renturn、抛异常
15、构造器(constructor)是否可被重写(override)?
不能,不能被继承所以不能被重写
16、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:
(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;
(2)如果两个对象的hashCode相同,它们并不一定相同。
实现高质量的equals方法的诀窍包括:
1. 使用==操作符检查”参数是否为这个对象的引用”;
2. 使用instanceof操作符检查”参数是否为正确的类型”;
3. 对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;
4. 编写完equals方法后,问自己它是否满足对称性、传递性、一致性;
5. 重写equals时总是要重写hashCode;
6. 不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@Override注解。
17、是否可以继承String类?
不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。
18、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。Java编程语言中只有由值传递参数的。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
19、String和StringBuilder、StringBuffer的区别?
1、在执行速度上:Stringbuilder->Stringbuffer->String
2、String是字符串常量
Stringbuffer是字符串变量
Stringbuilder是字符串变量
4、StringBuilder与StringBuffer
StringBuilder:线程非安全的
StringBuffer:线程安全的
5、对于三者的总结:
1)如果操作少量的数据用String
2)单线程下操作大量的数据用StringBuilder
3)多线程下操作大量的数据用StringBuffer
20、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
1、重载和重写都是多态性的体现,区别是重载是编译时的多态性,重写是运行时的多态性;
重载:只发生在一个类中,通过同名方法名不同参数类型或者参数个数来区分
重写:发生在父类和子类之间,重写要求子类的重写方法必须和父类被重写方法有相同的返回类型,比父类的方法更好访问,不能比父类被重写的方法声明更多的异常,而重载没有返回类型的特殊要
2、不能
21、描述一下JVM加载class文件的原理机制?
类成为对象(类加载的步骤):1.加载:类库,以二进制流的形式读入JVM
2、验证:验证字节码文件的正确性,比如魔数
3、 准备
4、 解析:解析字节码文件中包含的文件
1-4、链接:连接本地文件或者包和类
6.初始化:检查类文件,对静态部分进行内存分配
7.实例化:通过new关键字分配内存
22、char 型变量中能不能存贮一个中文汉字,为什么?
在C语言中,char类型占1一个字节,而汉子占2个字节,所以不能存储。
在Java中,char类型占2个字节,而且Java默认采用Unicode编码,以个Unicode码是16位,所以一个Unicode码占两个字节,Java中无论汉子还是英文字母都是用Unicode编码来表示的。所以,在Java中,char类型变量可以存储一个中文汉字。
23、抽象类(abstract class)和接口(interface)有什么异同?
1、抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。
2、一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。
3、接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。
4、抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。
5、抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。
6、有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。
24、静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?
:Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化,
25、Java 中会存在内存泄漏吗,请简单描述。
内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的
java中内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
2.如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
3.当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
1、static与abstract不能同时使用,抽象方法需要重写,静态方法不能被重写,矛盾。
2、抽象方法不能同时是本地方法,本地方法是由其他语言实现的方法。抽象方法没有实现方法。矛盾。
3、不能同时被synchronized修饰,因为synchronized本来就是需要具体实现的,可以调用的。与抽象方法矛盾。
27、阐述静态变量和实例变量的区别。
1、静态变量被static修饰,属于类变量,类加载时便分配内存,可用类名直接调用。
2、实例变量,又称成员变量。属于某个对象的变量,实例化后才分配内存空间。
28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
不可以,因为静态方法被加载,非静态方法的对象可能还没有被实例化。
29、如何实现对象克隆?
1、实现cloned接口,并重写object类中的clone方法。浅克隆:只复制框架
2、实现Serializable接口,通过序列化和反序列化实现克隆。深克隆:类的框架及数据。
30、GC是什么?为什么要有GC?
GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
- 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
- 幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
- 终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
• -Xms / -Xmx — 堆的初始大小 / 堆的最大大小
• -Xmn — 堆中年轻代的大小
• -XX:-DisableExplicitGC — 让System.gc()不产生任何作用
• -XX:+PrintGCDetails — 打印GC的细节
• -XX:+PrintGCDateStamps — 打印GC操作的时间戳
• -XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小
• -XX:NewRatio — 可以设置老生代和新生代的比例
• -XX:PrintTenuringDistribution — 设置每次新生代GC后输出幸存者乐园中对象年龄的分布
• -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值
• -XX:TargetSurvivorRatio:设置幸存区的目标使用率
31、String s = new String(“xyz”);创建了几个字符串对象?
两个,字符串常量池1个,new在堆中分配的内存
32、接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?
1、接口可以继承接口,并且可以多继承。
2、抽象类可以实现接口,也可以继承具体类。
33、一个”.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
可以包含多个类,但是只能存在一个public类并且与源文件名称相同。
34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
匿名内部类在实现时必须借助一个类或一个接口,若从这个层次上讲它是可以继承其他类也可以实现接口的,
但若是通过extends 或implements 关键字那是不可能的.
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。
36、Java 中的final关键字有哪些用法?
修饰类不可被继承,修饰方法不能被重写,修饰变量称为常量。
37、什么是若类型语言,什么强类型语言,java是什么类型语言
弱类型语言允许将一块内存看做多种类型。声明时不指定数据类型。
强语言类型:声明变量时必须确定数据类型,java时强语言类型。
38、数据类型之间的转换:
- 如何将字符串转换为基本数据类型?
基本类型的包装类型的parseXXXX方法或者valueOf方法
- 如何将基本数据类型转换为字符串?
1、基本数据类型与“”空字符串拼接。
2、调用String的valueof()方法
39、如何实现字符串的反转及替换?
1、StringBuffer和StringBuilder的reserve方法。
2、递归反转
1
2
3
4
5
public static String reverse(String originStr) {
if(originStr == null || originStr.length() <= 1)
return originStr;
return reverse(originStr.substring(1)) + originStr.charAt(0);
}
40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
1
2
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
先转为字节数组,然后使用String 的构造方法
41、如何取得年月日、小时分钟秒?
- 如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
- 如何取得某月的最后一天?
- 如何格式化日期?
问题1:创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值。Java 8中可以使用java.time.LocalDateTimel来获取,代码如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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));
// Java 8
LocalDateTime dt = LocalDateTime.now();
System.out.println(dt.getYear());
System.out.println(dt.getMonthValue()); // 1 - 12
System.out.println(dt.getDayOfMonth());
System.out.println(dt.getHour());
System.out.println(dt.getMinute());
System.out.println(dt.getSecond());
}
}
问题2:以下方法均可获得该毫秒数。
1
2
3
Calendar.getInstance().getTimeInMillis();
System.currentTimeMillis();
Clock.systemDefaultZone().millis(); // Java 8
问题3:代码如下所示。
1
2
Calendar time = Calendar.getInstance();
time.getActualMaximum(Calendar.DAY_OF_MONTH);
问题4:利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。Java 8中可以用java.time.format.DateTimeFormatter来格式化时间日期,代码如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
class DateFormatTest {
public static void main(String[] args) {
SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy/MM/dd");
Date date1 = new Date();
System.out.println(oldFormatter.format(date1));
// Java 8
DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date2 = LocalDate.now();
System.out.println(date2.format(newFormatter));
}
}
补充:Java的时间日期API一直以来都是被诟病的东西,为了解决这一问题,Java 8中引入了新的时间日期API,其中包括LocalDate、LocalTime、LocalDateTime、Clock、Instant等类,这些的类的设计都使用了不变模式,因此是线程安全的设计。
42、打印昨天的当前时刻
42、打印昨天的当前时刻。
答:
1
2
3
4
5
6
7
8
9
import java.util.Calendar;
class YesterdayCurrent {
public static void main(String[] args){
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -1);
System.out.println(cal.getTime());
}
}
在Java 8中,可以用下面的代码实现相同的功能。
1
2
3
4
5
6
7
8
9
10
11
import java.time.LocalDateTime;
class YesterdayCurrent {
public static void main(String[] args) {
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.minusDays(1);
System.out.println(yesterday);
}
}
43、比较一下Java和JavaSciprt。
1、java时面向对象编程。javascript时基于对象编程,提供了大量的内部类供开发者调用。
2、是两种不同的产品。
3、- 解释和编译:Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行。
4、强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明,JavaScript的解释器在运行时检查推断其数据类型。
44、Error和Exception有什么区别?
error:错误,不可被捕获,将导致程序中断。
exception:异常,可以进行捕获处理。