导语
  Java面试题集2021版


Java基础部分

  • 1、一个.java 源文件中是否可以包括多个类(不是内部类)?有什么限制?
  • 2、Java中有没有goto?
  • 3、说说& 和 && 的区别?
  • 4、Java中的“短路”是指什么?
  • 5、在Java中如何跳出当前的多重循环的嵌套?
  • 6、switch 语句能否作用在byte上,能否作用在long上,能否作用在String上?
  • 7、short s = 1;s=s+1;有什么错?short s = 1;s+=1 有什么错?
  • 8、char型变量中能不能存储一个中文汉字?为什么?
  • 9、用最有效的方法算出2乘以8等于几?
  • 10、冒泡排序实现
  • 11、"=="和equals究竟有什么区别?
  • 12、两个对象值相同(x.equals(y)==true),但却可有不同的hash code,这句话对不对?
  • 13、写出Object类中定义的方法?


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

  可以有多个类,但只能有一个public的类,并且public的类名必须与文件名一致。

2、Java中有没有goto?

  是属于Java中的保留字,现在没有在Java中使用

3、说说& 和 && 的区别?

  & 和&& 都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true的时候,整个运算的结果才为true,否则,只要有一个为false,则结果为false。

  其中&& 有短路的作用,也就是说如果第一个表达式为false,则不需要在进行第二个表达式的计算。例如 if(str!=null && !str.equals("")) 表达式,当str为null的时候,后面的判断就不会再执行了,所以就不会出现NullPointException的异常。如果将&& 改为 &,则会抛出NullPointException异常。if(x==33&++y>0) y 会进行增长,if(x==33&&++y>0),不会增长。
   & 还可以用作位运算符,当& 操作符两边的表达式不是boolean 类型的时候,& 表示按位与操作,通常 使用 0x0f 来与一个整数进行& 运算,来获取该整数的最低4位bit位,例如 0x31&0x0f的结果为0x01。

4、Java中的“短路”是指什么?

  在Java逻辑运算中使用逻辑运算符|| 或者是&& 的时候将会采取短路的措施,例如

if(a>0||a<1){

}

  上面这段代码执行过程中当a 满足大于0的时候将不再执行后面的a<1的操作,这个就是短路操作。

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

  在Java中,如果在某些情况下想要跳出多重循环,可以通过在外部循环语句前定义一个标识,然后在内层循环的代码中,使用带有标号的break语句,这样就可以跳出外层循环。例如

ok: //用来定义一个标识
for(int i = 0;i<10;i++){
	for(int j = 0;j<10;j++){
		System.out.println(i+j)
		if(j==5){
			break ok;
		}
	}
}

  当然如果让外层的循环表达式的结果可以受到内层循环整体代码的控制,那么可以使用如下的方式

int arr[][] = {{1,2,3},{4,5,6,7},{9}}
boolean found = false;
for(int i = 0;i<arr.length&&!found;i++){
	for(int j = 0;j<arr[i].length;j++){
		if(arr[i][j]==5){
			found=true;
			break;
		}
	}
}

6、switch 语句能否作用在byte上,能否作用在long上,能否作用在String上?

  在switch(expression)中,expression 是一个整数表达式或者是枚举常量,其中整数表达式可以是int基本类型或者是Integer 包装类型,在Java中,由于byte,short,char都可以隐含的转换为int类型,所以说这些类型及其包装类都是可以的。
  在Java8之后String类型也可以作为它的语法规则进行操作。对于long类型的来说他不能被隐式的转化为int类型,所以说它不能用于switch语句中。

7、short s = 1;s=s+1;有什么错?short s = 1;s+=1 有什么错?

  对于short s = 1;s=s+1; 由于s+1的时候回自动提升表达式类型,所以结果是int型,在赋值给short的时候,编译器将会报告强制类型转换错误;
  对于short s = 1;s+=1;由于+= 操作是Java语言中规定的操作符,Java编译器会对它进行特殊处理,因此可以正确进行操作。

8、char型变量中能不能存储一个中文汉字?为什么?

  char变量是用来存储Unicode 编码的字符,Unicode 编码字符集中包含了汉字,所以,char 型变量中当然课可以存储汉字,但是,如果某个特殊的汉字没有被包含在Unicode的编码字符集中,那么,这个char 变量中就不能存储这个汉字,补充:Unicode 编码占两个字节,所以char类型变量也占两个字节。

9、用最有效的方法算出2乘以8等于几?

  最有效的计算方式:int result = 2<<3;
  因为将一个数左移n位,就相当于乘以2的n次方,那么一个数乘以8只要将其左移3位即可,而位运算是CPU直接支持的,效率最高,所以2乘以8 等于几最有效的方式就是2<<3

10、冒泡排序实现

口诀:n个数字来比较,外层循环N-1,内层循环N-1-i,两两相比小靠前。

public static void main(String[] args) {
		int[] number=new int[]{22,12,33,45,66};
		int temp;
		//冒泡排序
		for(int i=0;i<number.length-1;i++){
			for(int j=0;j<number.length-1-i;j++){
				if(number[j]>number[j+1]){
					temp=number[j+1];
					number[j+1]=number[j];
					number[j]=temp;
				}
			}
		}
	}

11、"=="和equals究竟有什么区别?

   == 操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本数据类型或者两个索引变量知否相等,只能用 == 操作符
  如果一把变量指向的数据是对象类型的,那么这个时候就涉及到两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如 Object obj = new Object();引用变量obj是一个内存,new Object()是另一块内存,这个时候,变量obj所对应的内存中存储的额数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向的是同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这个时候就需要进行==的比较。
  equals 方法是 用于比较两个独立对象的内容是否相同,就好比比较两个人的长相是否相同,它比较的两个对象是相互独立的,例如

String a = new String("test");
String b = new String("test");

  两条New语句创建了两个对象,然后用 a,b两个变量分别指向了其中一个对象,这两个不同的对象,它们的首地址是不同的,也就是说a和b中所存储的数值是不相同的,所以表达式a = b 将会返回 false,而这两个对象中的内容是相同的,所以表达式a.equal(b) 返回的值是true。
  在实际的开发中,经常要比较传递的字符串内容是否相等。很多情况下,不注意就通过== 进行比较了。

  如果定义一个类没有自己定义equal方法,那么它将继承Object的equals方法。这就说明,一个类,如果没有一个自定义的equals方法,它默认的equals方法就是使用 = 操作符,也是比较两个变量指向的对象是否是同一个对象,这个时候使用equals和使用== 将会得到同样的结果。如果比较的是两个独立的对象则总返回false,如果在定义类的时候希望能够比较该类创建的两个实例对象的内容是否相同,那么就需要重写equals方法,这个就可以由自己来定义如何算相同。

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

  
  如果对象要保存在HashSet 或 HashMap中,它们的equals相等,那么,它们的hashCode值就必须相等。
  如果不是要保存在HashSet 或者 HashMap,则与HashCode就没有关系了,这个时候 hashcode 不等是可以的,例如ArrayList存储的对象就不用实现hashCode,当然,可没有理由不去实现,通常都是Object实现的默认的内容。

13、写出Object类中定义的方法?

  • clone() 创建并返回此对象的副本
  • equals() 某个对象是否与其他对象相等
  • finalize() 当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器调用此方法
  • getClass() 返回一个对象的运行时类
  • hashCode() 返回改对象的哈希值
  • notify() 唤醒在此对象监视器上等待的单个线程
  • **notifyAll()**唤醒在对象监视器上等待的所有线程
  • **toString()**返回该对象的字符串标识
  • wait() 导致当前线程等待,知道其他线程调用了此对象的notify()方法或者是notifyAll()方法
  • 其他两个的wait方法都是wait方法的重载