(本系列同步更新于 个人博客小站)
本系列整理Java相关的笔试面试知识点。其它几篇文章例如以下:
Java笔试面试题整理第八波
Java笔试面试题整理第七波
Java笔试面试题整理第六波
Java笔试面试题整理第五波
Java笔试面试题整理第四波
Java笔试面试题整理第三波
Java笔试面试题整理第二波
Java笔试面试题整理第一波
1、Java变量
Java中主要有例如以下几种类型的变量- 局部变量
- 类变量(静态变量)-- 属于类
- 成员变量(非静态变量)-- 属于对象
2、关于枚举
package com.scu.lly;
public class EnumTest {
/**
* 颜色枚举
*/
enum ColorEnum{
RED,
GREEN,
BLUE
}
/**
* 性别枚举
* 可用中文字符。不能单独使用数字
* (枚举值组成:字母、下划线)
*/
enum SexEnum{
男,
女,
MAN,
WOWAM
}
/**
* 1、带有构造方法的枚举。构造方法为仅仅能为private(默认可不写private);
* 2、含带參构造方法的枚举,枚举值必须赋值。
* 3、枚举中有了其它属性或方法之后。枚举值必须定义在最前面。且须要在最后一个枚举值后面加分号";"
*/
enum CarEnum{
BMW("宝马",1000000),
JEEP("吉普",800000),
MINI("mini",200000);
private String name;
/**
* 从这里能够看出尽管枚举值不能直接由数字组成,可是我们能够给该枚举类加入一个int类型的值,通过构造方法给其赋值,相当于间接的能够使用数值
*/
private int price;
private CarEnum(String name,int price){
this.name = name;
this.price = price;
}
//加入setter、getter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
/**
* 由于枚举类都继承了Enum类。故我们定义的enum都不能在继承其它类了,可是能够实现其它接口
*/
enum CarSetEnum implements Car{
BMW("宝马"),
JEEP("吉普"),
MINI("mini");
private String name;
private CarSetEnum(String name){
this.name = name;
}
//加入setter、getter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void setCarName(String name) {
this.name = name;
}
}
public static void main(String[] args){
ColorEnum color = ColorEnum.BLUE;
switch(color){
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
getSelectedColor(color);
//測试含构造方法的枚举
System.out.println("吉普信息:"+CarEnum.JEEP.getName() + ":" +CarEnum.JEEP.price);
for(CarEnum car : CarEnum.values()){
System.out.println(car.name);
System.out.println(car.getPrice());
}
//測试实现接口的枚举
CarSetEnum.BMW.setName("加长宝马");
System.out.println(CarSetEnum.BMW.getName());
}
public static ColorEnum getSelectedColor(ColorEnum color){
ColorEnum result;
switch(color){
case RED:
System.out.println("红色");
break;
case GREEN:
System.out.println("绿色");
break;
case BLUE:
System.out.println("蓝色");
break;
}
result = color;
return result;
}
interface Car{
public void setCarName(String name);
}
}
3、訪问控制修饰符
修饰符 | 说明 |
---|
private
| 私有的,在同一类内可见。
|
默认没写 | 在同一包(包含子类和非子类)内可见。 默认不使用不论什么修饰符。 |
protected | 受保护的。对同一包内的类和全部子类可见。 |
public | 共同拥有的。对全部类可见。 |
主要是默认和protected这两个修饰符,总结起来就是:
默认的:同一包下可訪问;
protected:同一包和全部子类可訪问;
(1)这里的可见、可訪问指的是能不能通过 ”类的对象.变量名“的方式訪问,这是由于除static声明的变量属于类变量外,其它的都属于实例变量,是属于某个对象的。
如。Person p = new Person(); p.age直接訪问age变量,对于那些私有的变量,非常多情况下会对外提供public的setter和getter方法来供外部訪问。
(2)要注意的是,对于有继承关系的子类来说,比方 class A extends B,A直接继承拥有了默认的(在同一包下)、protected、public的这个字段,能够直接使用该字段,而不用通过再次的实例化父类或"父类对象.字段"的形式訪问。由于在实例化A类的时候父类B已经实例化好了。特别的,对于protected来说,例如以下形式是编译不能通过的。
package com.a
public class A extends B{
public void test(){
B b = new B();
String str = b.age;//错误!不同包下的子类不能通过实例出来的父类获取protected的变量
String str2 = age;//正确。A类继承了B。直接拥有了该字段
String str3 = b.birthday;//正确。birthday为public
}
}
package com.b
public class B{
protected String age = "20";
public String birthday = "1995";
}
结论就是:
在上面那个表格修饰符的约束前提下,对于非继承类关系,须要使用 “实例变量.变量名的形式訪问”(static类变量除外);
对于有继承关系的子类来说。 子类直接继承了拥有了默认的(在同一包下)、protected、public的这个字段,能够直接使用该字段。
4、UTF-8和GBK编码转换
以下哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换:byte
[] src,dst;
A、dst=String.fromBytes(src,"GBK").getBytes("UTF-8")
B、dst=new String(src,"GBK").getBytes("UTF-8")
C、dst=new String("GBK",src).getBytes()
D、dst=String.encode(String.decode(src,"GBK")),"UTF-8" )
正确答案:B
操作步骤就是先解码再编码,先通过GBK编码还原字符串。在该字符串正确的基础上得到“UTF-8”所相应的字节串。
5、try、catch、finally运行顺序问题
以下函数将返回?
1 2 3 4 5 6 7 8 9 | public static int func (){
try {
return 1;
} catch (Exception e){
return 2;
}finally{
return 3;
}
}
|
A、1 B、2 C、3 D、编译错误
正确答案:C
(1)try catch中仅仅要有finally语句都要运行(有特例:假设try 或 catch 里面有 exit(0)就不会运行finally了);
(2)finally语句在try或catch中的return语句运行之后返回之前运行。且finally里的改动语句不能影响try或catch中 return已经确定的返回值。
若finally里也有return语句则覆盖try或catch中的return语句直接返回。
(3)在遵守第(2)条return的情况下,运行顺序是:try-->catch(假设有异常的话)-->finally。
6、静态代码块、子类、父类初始化顺序
例如以下代码的输出结果:
package com.scu.lly;
public class HelloB extends HelloA {
public HelloB() {
System.out.println("-----------HelloB 构造方法------------");
}
{
System.out.println("I’m B class");
}
static{
System.out.println("static B");
}
public static void main(String[] args){
new HelloB();
}
}
class HelloA{
public HelloA(){
System.out.println("-----------HelloA 构造方法------------");
}
{
System.out.println("I’m A class");
}
static{
System.out.println("static A");
}
}
输出结果:
static A
static B
I’m A class
-----------HelloA 构造方法------------
I’m B class
-----------HelloB 构造方法------------
运行顺序:1.静态代码块 --> 2.普通代码块 --> 3.构造方法
须要明确的是,1是类级别的,2和3是实例级别的,所以在父子类关系中,上述的运行顺序为:
父类静态代码块-->子类静态代码块-->父类普通代码块-->父类构造方法-->子类代码块-->子类构造方法。
也就是上到下(父类到子类)先走完 类级别的(静态的)--> 再依次走完父类的全部实例级别代码 --> 再走子类全部实例级别代码
7、关于null对象、static变量和方法
有关下述Java代码描写叙述正确的选项是____。
1 2 3 4 5 6 7 8 | public class TestClass {
private static void testMethod(){
System.out.println( "testMethod" );
}
public static void main(String[] args) {
((TestClass) null ).testMethod();
}
}
|
A、编译不通过 B、编译通过,运行异常。报NullPointerException C、编译通过,运行异常,报IllegalArgumentException D、编译通过。运行异常,报NoSuchMethodException E、编译通过,运行异常,报Exception F、运行正常,输出testMethod
正确答案:F
静态方法是属于类的,静态方法在对象实例创建前就已经存在了,它的使用不依赖于对象是否被创建。
当我们通过类的实例来调用时,最后实际上还是将对象实例转换成了类去掉用该静态方法,所以这里的null仅仅是迷惑大家的跟它没有什么关系。
这里
((TestClass)
null
).testMethod();
也能够写成TestClass t = null; t.testMethod();相同能够正确输出。null能够被强制转换成随意类型对象,尽管这个时候t被赋为了空,但这个“空对象”也是属于TestClass的,那么这个“空对象”也就能够去堆上的静态方法区调用testMethod()方法了。
假设这里testMethod把static去掉,该testMethod方法就变成了实例对象的方法了。这时。能够编译通过,可是会报空指针。
同理,对于static变量也是一样的。
比方TestClass 中有例如以下变量:private static String str = "abc"; 我们通过TestClass t = null; System.out.println(t.str);相同能够正确输出。
8、关于线程启动
下列方法中哪个是运行线程的方法? ()
A、run() B、start() C、sleep() D、suspend()
正确答案:A
start()方法启动一个线程。使其处于就绪状态,得到了CPU就会运行,而调用run()方法,就相当于是普通的方法调用,会在主线程中直接运行,此时没有开启一个线程。例如以下:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----------线程中run---------");
}
});
System.out.println("-------主线程11111------");
t.run();
System.out.println("-------主线程222------");
这里调用Thread的run()方法,此时相当于是普通的方法调用,并没有开启线程,直接在主线程中运行Thread中的Runnable方法,睡眠2秒后打印"----------线程中run---------",在运行t.run后面的打印。所以此时的输出为:
-------主线程11111------
----------线程中run---------
-------主线程222------
若将t.run()改为t.start(),此时会开启一个线程,并使该线程处于就绪状态,得到CPU后開始运行,调用t.start()后主线程继续运行以下的打印。所以此时的输出为:
-------主线程11111------
-------主线程222------
----------线程中run---------
9、关于内部类
往OuterClass类的代码段中插入内部类声明, 哪一个是错误的:1 2 3 4 | public class OuterClass{
private float f=1.0f;
//插入代码到这里
}
|
A、class InnerClass{
public static float func(){return f;}
}
B、abstract class InnerClass{
public abstract float func(){}
}
C、static class InnerClass{
protected static float func(){return f;}
}
D、public class InnerClass{
static float func(){return f;}
}
正确答案:ABCD
静态的内部类才干够定义static方法,排除AD;
B抽象方法中不能有方法体;
C,静态方法不能够引用非静态变量。
10、Final修饰符、volatile修饰符
Final修饰符,用来修饰类、方法和变量。final修饰的类不能够被继承,修饰的方法能够被继承,重载,可是不能被子类重写(即又一次定义)
(1)final变量:
被声明为final的对象的引用不能指向不同的对象。可是final对象里的数据能够被改变。也就是说final对象的引用不能改变。可是里面的值能够改变。比方:
final Person p = new Person();
p.name = "aaa";
p.name = "bbb";
可是,假设是final String str = "aaa"; str = "bbb";//错误编译不能通过,由于此时str的引用已经改变了。
(2)final修饰方法
Final修饰的方法能够被子类继承,可是不能被子类改动(重写)。
声明final方法的主要目的是防止该方法的内容被改动。
volatile修饰符,Volatile修饰的成员变量在每次被线程訪问时。都强迫从共享内存中重读该成员变量的值。
而且,当成员变量发生变化时。强迫线程将变化值回写到共享内存。
这样在不论什么时刻。两个不同的线程总是看到某个成员变量的同一个值。
一个volatile对象引用可能是null。
11、StringBuffer 和 StringBuilder
和String类不同。StringBuffer和StringBuilder类的对象能够被多次的改动。而且不产生新的未使用对象。 StringBuilder类和StringBuffer之间的最大不同在于StringBuilder的方法不是线程安全的(不能同步訪问)。
由于StringBuilder相较于StringBuffer有速度优势。所以多数情况下建议使用StringBuilder类。
然而在应用程序要求线程安全的情况下,则必须使用StringBuffer类。
12、可变參数
JDK 1.5 開始,Java支持传递同类型的可变參数给一个方法,一个方法中仅仅能指定一个可变參数,它必须是方法的最后一个參数。不论什么普通的參数必须在它之前声明。
如,public void getStr(String ...str){}//正确
public void getStr2(String ...str,int a){}//错误,一个方法中可变參数仅仅能有一个,它必须是方法的最后一个參数。
13、关于异常分类
全部的异常类是从java.lang.Exception类继承的子类。
Exception类是Throwable类的子类。
除了Exception类外,Throwable另一个子类Error 。
Error用来指示运行时环境发生的错误。层次关系如图:
检查性异常: 不处理编译不能通过
非检查性异常:不处理编译能够通过。假设有抛出直接抛到控制台。
运行时异常(RuntimeException): 继承自
RuntimeException类的就是非检查性异常
非运行时异常: 就是检查性异常
以下的表中列出了Java的非检查性异常(RuntimeException)。
异常 | 描写叙述 |
---|
ArithmeticException | 当出现异常的运算条件时。抛出此异常。 比如,一个整数"除以零"时。抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引訪问数组时抛出的异常。假设索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时。抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不对的參数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其它正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说。即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(比如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 假设应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在须要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
以下的表中列出了Java定义在java.lang包中的检查性异常类。
异常 | 描写叙述 |
---|
ClassNotFoundException | 应用程序试图载入类时。找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象。但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝訪问一个类的时候。抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例。而指定的类对象由于是一个接口或是一个抽象类而无法实例化时。抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
其它
1、以下描写叙述属于java虚拟机功能的是?
A、通过 ClassLoader 寻找和装载 class 文件
B、解释字节码成为指令并运行。提供 class 文件的运行环境
正确答案:ABCD
2、以下有关java threadlocal说法正确的有?
A、ThreadLocal存放的值是线程封闭。线程间相互排斥的。主要用于线程内共享一些数据,避免通过參数来传递
B、线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,仅仅要线程是活动的而且 ThreadLocal 实例是可訪问的;在线程消失之后。其线程局部实例的全部副本都会被垃圾回收
C、在Thread类中有一个Map,用于存储每个线程的变量的副本。
D、对于多线程资源共享的问题,同步机制採用了“以时间换空间”的方式,而ThreadLocal採用了“以空间换时间”的方式
正确答案:ABCD
ThreadLocal类用于创建一个线程本地变量
在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map。它的键是threadLocal。值
就是变量的副本。ThreadLocal为每个使用该变量的线程都提供了一个变量值的副本,每个线程都能够独立地改变自己的副本,是线程隔离的。通过ThreadLocal的get()方法能够获取该线程变量的本地副本。在get方法之前要先set,否则就要重写initialValue()方法。 ThreadLocal不是用来解决对象共享訪问问题的。而主要是提供了保持对象的方法和避免參数传递的方便的对象訪问方式。普通情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其它线程是不须要訪问的。也訪问不到的。各个线程中訪问的是不同的对象。
3、以下集合对象中哪几个是线程安全的?( )
A、ArrayList
B、Vector
C、Hashtable
D、Stack正确答案:BCD
在集合框架中。有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许很多多非线程安全的类。 以下是这些线程安全的同步的类:
vector:比arraylist多了个同步化机制(线程安全)。由于效率较低,如今已经不太建议使用。在web应用中。特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,继承了Vector
hashtable:比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,其它的都是非线程安全的类和接口。比方经常使用的ArrayList、HashMap都是线程不安全的。