Java基础面试题

1.一个".java" 源文件中是否可以包括多个类(不是内部类)?有什么限制?
  • 可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。
2.Java有没有 goto?
  • java 中的保留字,现在没有在 java 中使用。
3 .说说&和&&的区别。
  • &和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为 true 时,整个运算结果才为 true,否则,只要有一方为 false,则结果为 false。
  • &&还具有短路的功能,即如果第一个表达式为 false,则不再计算第二个表达式,例如,对于 if(str != null&& !str.equals(“”))表达式,当 str 为 null 时,后面的表达式不会执行,所以不会出现NullPointerException,如果将&&改为&,则会抛出 NullPointerException 异常。If(x == 33 & ++y > 0) y 会增长,If(x==33 && ++y > 0),不会增长
  • &还可以用作位运算符,当&操作符两边的表达式不是 boolean 类型时,&表示按位与操作,我们通常使用 0x0f 来与一个整数进行&运算,来获取该整数的最低 4 个 bit 位,例如,0x31 & 0x0f 的结果为 0x01。
  • 备注:这道题先说两者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来表明自己理解透彻深入、实际经验丰富。
4 .在JAVA中如何跳出当前的多重嵌套循环?
  • 在 Java 中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的 break 语句,即可跳出外层循环。例如,
ok:
	for(int i=0;i<10;i++) {
		for(int j=0;j<10;j++) {
			System.out.println(“i=+ i +,j=+ 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++){
		System.out.println(“i=+ i +,j=+ j);
		if(arr[i][j] == 5) {
			found = true;
			break;
		}
	}
}
5 .switch 语句能否作用在 byte上 ,能否作用在long上 ,能否作用在String 上?
  • 在 switch(expr1)中,expr1 只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是 int基本类型或 Integer 包装类型,由于,byte,short,char都可以隐含转换为 int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String 类型都不符合 switch 的语法规定,并且不能被隐式转换成 int类型,所以,它们不能作用于 swtich 语句中。
6 .short s1 = 1; s1 = s1 + 1; 有什么错? short s1 = 1; s1 += 1;有什么错?
  • 对于 short s1 = 1; s1 = s1 + 1; 由于 s1+1 运算时会自动提升表达式的类型,所以结果是 int 型,再赋值给 short 类型 s1 时,编译器将报告需要强制转换类型的错误。
  • 对于 short s1 = 1; s1 += 1;由于 += 是 java 语言规定的运算符,java 编译器会对它进行特殊处理,因此可以正确编译。
7.char 型变量中能不能存贮一个中文汉字?为什么?
  • char 型变量是用来存储 Unicode 编码的字符的,unicode 编码字符集中包含了汉字,所以,char 型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在 unicode 编码字符集中,那么,这个 char型变量中就不能存储这个特殊汉字。补充说明:unicode 编码占用两个字节,所以,char 类型的变量也是占用两个字节。
  • 备注:后面一部分回答虽然不是在正面回答题目,但是,为了展现自己的学识和表现自己对问题理解的透彻深入,可以回答一些相关的知识,做到知无不言,言无不尽。
8.用最有效率的方法算出 2 乘以 8 等於几?
  • 2 << 3,
    因为将一个数左移 n 位,就相当于乘以了 2 的 n 次方,那么,一个数乘以 8 只要将其左移 3 位即可,而位运算 cpu 直接支持的,效率最高,所以,2 乘以 8 等於几的最效率的方法是 2 << 3。
9.请设计一个一百亿的计算器
  • 首先要明白这道题目的考查点是什么,一是大家首先要对计算机原理的底层细节要清楚、要知道加减法的位运算原理和知道计算机中的算术运算会发生越界的情况,二是要具备一定的面向对象的设计思想。
  • 首先,计算机中用固定数量的几个字节来存储的数值,所以计算机中能够表示的数值是有一定的范围的,为了便于讲解和理解,我们先以 byte 类型的整数为例,它用 1 个字节进行存储,表示的最大数值范围为-128 到+127。-1 在内存中对应的二进制数据为 11111111,如果两个-1 相加,不考虑 Java 运算时的类型提升,运算后会产生进位,二进制结果为 1,11111110,由于进位后超过了byte 类型的存储空间,所以进位部分被舍弃,即最终的结果为 11111110,也就是-2,这正好利用溢位的方式实现了负数的运算。-128 在内存中对应的二进制数据为 10000000,如果两个-128 相加,不考虑 Java 运算时的类型提升,运算后会产生进位,二进制结果为 1,00000000,由于进位后超过了 byte 类型的存储空间,所以进位部分被舍弃,即最终的结果为 00000000,也就是 0,这样的结果显然不是我们期望的,这说明 计算机中的算术运算是会发生越界情况的 ,两个数值的运算结果不能超过计算机中的该类型的数值范围 。由于 Java 中涉及表达式运算时的类型自动提升,我们无法用 byte 类型来做演示这种问题和现象的实验,大家可以用下面一个使用整数做实验的例子程序体验一下:
	int a = Integer.MAX_VALUE;
	int b = Integer.MAX_VALUE;
	int sum = a + b;
	System.out.println(“a=+a+,b=+b+,sum=+sum);
  • 先不考虑 long 类型,由于 int 的正数范围为 2 的 31 次方,表示的最大数值约等2x1000x1000x1000,也就是 20 亿的大小,所以,要实现一个一百亿的计算器,我们得自己设计一个类可以用于表示很大的整数,并且提供了与另外一个整数进行加减乘除的功能,大概功能如下:
  • ()这个类内部有两个成员变量,一个表示符号,另一个用字节数组表示数值的二进制数
    ()有一个构造方法,把一个包含有多位数值的字符串转换到内部的符号和字节数组中
    ()提供加减乘除的功能
	public class BigInteger{
		int sign;
		byte[] val;
		public Biginteger(String val){
			sign = ;
			val = ;
		}
		public BigInteger add(BigInteger other) {
		}
		public BigInteger subtract(BigInteger other) {
		}
		public BigInteger multiply(BigInteger other){
		}
		public BigInteger divide(BigInteger other){
		}
	}
  • 备注:要想写出这个类的完整代码,是非常复杂的,如果有兴趣的话,可以参看 jdk 中自带d的java.math.BigInteger 类的源码。面试的人也知道谁都不可能在短时间内写出这个类的完整代码的,他要的是你是否有这方面的概念和意识,他最重要的还是考查你的能力,所以,你不要因为自己无法写出完整的最终结果就放弃答这道题,你要做的就是你比别人写得多,证明你比别人强,你有这方面的思想意识就可以了,毕竟别人可能连题目的意思都看不懂,什么都没写,你要敢于答这道题,即使只答了一部分,那也与那些什么都不懂的人区别出来,拉开了距离,算是矮子中的高个,机会当然就属于你了。另外,答案中的框架代码也很重要,体现了一些面向对象设计的功底,特别是其中的方法命名很专业,用的英文单词很精准,这也是能力、经验、专业性、英语水平等多个方面的体现,会给人留下很好的印象,在编程能力和其他方面条件差不多的情况下,英语好除了可以使你获得更多机会外,薪水可以高出一千元。
10.使用 final 关键字修饰 一个变量时,是引用不能变,还是引用的对象不能变 ?
  • 使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。例如,对于如下语句:
	final StringBuffer a=new StringBuffer("immutable");
  • 执行如下语句将报告编译期错误:
	a=new StringBuffer("");
  • 但是,执行如下语句则可以通过编译:
	a.append(" broken!");
  • 有人在定义方法的参数时,可能想采用如下形式来阻止方法内部修改传进来的参数对象:
	public void method(final StringBuffer param){
	}
  • 实际上,这是办不到的,在该方法内部仍然可以增加如下代码来修改参数对象:
	param.append("a");
11."=="和 和 equals 方法究竟有什么区别?
  • (单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚)
  • == 操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用 == 操作符。
  • 如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存,例如 Objet obj = new Object();变量 obj 是一个内存,new Object()是另一个内存,此时,变量 obj 所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
  • equals 方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码:
	String a=new String("foo");
	String b=new String("foo");
  • 两条 new 语句创建了两个对象,然后用 a,b 这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即 a 和 b 中存储的数值是不相同的,所以,表达式 a==b 将返回 false,而这两个对象中的内容是相同的,所以,表达式 a.equals(b)将返回 true。
  • 在 实 际 开 发 中 , 我 们 经 常 要 比 较 传 递 进 行 来 的 字 符 串 内 容 是 否 等 , 例 如 , String input=…;input.equals(“quit”),许多人稍不注意就使用==进行比较了,这是错误的,随便从网上找几个项目实战的教学视频看看,里面就有大量这样的错误。记住,字符串的比较基本上都是使用 equals 方法。
  • 如果一个类没有自己定义 equals 方法,那么它将继承 Object 类的 equals 方法,Object 类的 equals 方法的实现代码如下:
	boolean equals(Object o){
	return this==o;
	}
  • 这说明,如果一个类没有自己定义 equals 方法,它默认的 equals 方法(从 Object 类继承的)就是使用 == 操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用 equals 和使用 == 会得到同样的结果,如果比较的是两个独立的对象则总返回 false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖 equals 方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。
12.静态变量和实例变量的区别?
  • 在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。
  • 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
  • 例如,对于下面的程序,无论创建多少个实例对象,永远都只分配了一个 staticVar 变量,并且每创建一个实例对象,这个 staticVar 就会加 1;但是,每创建一个实例对象,就会分配一个 instanceVar,即可能分配多个 instanceVar,并且每个 instanceVar 的值都只自加了 1 次。
public class VariantTest{
	public static int staticVar = 0;
	public int instanceVar = 0;
	public VariantTest(){
		staticVar++;
		instanceVar++;
		System.out.println(“staticVar=+ staticVar +,instanceVar=+ instanceVar);
	}
}
13.是否可以从一个 static 方法内部发出对非 static 方法的调用?
  • 不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而 static 方法调用时不需要创建对象,可以直接调用。也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法的调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个 static 方法内部发出对非 static 方法的调用。
14.Integer 与 与 int 的区别
  • int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 java 为 int 提供的封装类。int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为 0 的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。在 JSP 开发中,Integer 的默认为 null,所以用 el 表达式在文本框中显示时,值为空白字符串,而 int 默认的默认值为 0,所以用 el 表达式在文本框中显示时,结果为 0,所以,int 不适合作为 web 层的表单数据的类型。
  • 在 Hibernate 中,如果将 OID 定义为 Integer 类型,那么 Hibernate 就可以根据其值是否为 null 而判断一个对象是否是临时的,如果将 OID 定义为了 int 类型,还需要在 hbm 映射文件中设置其 unsaved-value 属性为 0。
  • 另外,Integer 提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer 中还定义了表示整数的最大值和最小值的常量。
15. Math.round(11.5) 等於多少? Math.round(-11.5) 等於多少?
  • Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil 的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor 的英文意义是地板,该方法就表示向下取整,Math.ceil(11.6)的结果为11,Math.ceil(-11.6)的结果是-12;最难掌握的是 round 方法,它表示“四舍五入”,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以, Math.round(11.5)的结果为 12,Math.round(-11.5)的结果为-11。
16. 下面的代码有什么不妥之处?
1. if(username.equals(“zxx”){} // if("zxx".equals(username){} 反过来写更标准,如果username没赋值的话会报错
2. int x = 1; 
return x==1?true:false; // 程序复杂化,直接x==1,不利于程序阅读
17. 请说出作用域 public ,private ,protected , 以及不写时的区别
  • 这四个作用域的可见范围如下表所示。
    说明:如果在修饰的元素上面没有写任何访问修饰符,则表示 friendly。
    作用域 当前类 同一package内 子孙类 其他package包
    public √ √ √ √
    protected √ √ √ ×
    默认(default) √ √ × ×
    private √ × × ×
    备注:只要记住了有 4 种访问权限,4 个访问范围,然后将全选和范围在水平和垂直方向上分别按排从小到大或从大到小的顺序排列,就很容易画出上面的图了。
18. Overload 和 和 Override 的区别。
  • Overload 是重载的意思,Override 是覆盖的意思,也就是重写。
  • 重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
  • 重写 Override 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
19. 构造器 Constructor 是否可被 override?
  • 构造器 Constructor 不能被继承,因此不能重写 Override,但可以被重载 Overload。
20. 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的 main 方法?
  • 接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类。抽象类中可以有静态的 main 方法。
  • 只要记住抽象类与普通类的唯一区别就是不能创建实例对象和允许有 abstract 方法。
21. 写 clone() 方法时,通常都有一行代码,是什么?
  • clone 有缺省行为,super.clone();因为首先要把父类中的成员复制到位,然后才是复制自己的成员。
22. 面向对象的特征有哪些方面?
  • 封装
  • 继承
  • 多态
23. java 中实现多态的机制是什么?
  • 靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
24. abstract class 和 interface 有什么区别?
  • 抽象类可以有构造方法,接口中不能有构造方法。
  • 抽象类中可以有普通成员变量,接口中没有普通成员变量。
  • 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
  • 抽象类中的抽象方法的访问类型可以是 public,protected 和 默认类型,但接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
  • 抽象类中可以包含静态方法,接口中不能包含静态方法。
  • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是 public static final 类型,并且默认即为 public static final 类型。
  • 一个类可以实现多个接口,但只能继承一个抽象类。
25. abstract 的 的 method 是否可同时是 static, 是否可同时 是native ,是否可同时是 synchronized?
  • abstract 的 method 不可以是 static 的,因为抽象的方法是要被子类实现的,而 static 与子类扯不上关系!
  • native 方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与 abstract 混用。例如,FileOutputSteam 类要硬件打交道,底层的实现用的是操作系统相关的 api 实现。
26. 什么是内部类?
  • 内部类就是在一个类的内部定义的类,内部类中不能定义静态成员
27. 内部类可以引用它的包含类的成员吗?有没有什么限制?
  • 完全可以。如果不是静态内部类,那没有什么限制!
  • 如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员,例如,下面的代码:
class Outer{
	static int x;
	static class Inner{
		void test()
		{
			syso(x);
		}
	}
}
28. Anonymous Inner Class ( 匿名内部类 ) 是否可以extends( 继承 )其它类 ,是否可以implements( 实现 )interface( 接口 )?
  • 可以继承其他类或实现其他接口。不仅是可以,而是必须!
29. super.getClass() 方法调用
  • 下面程序的输出结果是多少?
public class Test extends Date{
	public static void main(String[] args) {
		new Test().test();
	}
	public void test(){
		System.out.println(super.getClass().getName());
	}
}
  • 结果是 Test
  • 在 test 方法中,直接调用 getClass().getName()方法,返回的是 Test 类名由于 getClass()在 Object 类中定义成了 final,子类不能覆盖该方法,所以,在test 方法中调用 getClass().getName()方法,其实就是在调用从父类继承的 getClass()方法 , 等效于调 用 super.getClass().getName() 方 法 ,所 以 ,super.getClass().getName()方法返回的也应该是 Test。如果想得到父类的名称,应该用如下代码:
    getClass().getSuperClass().getName();
30. String是最基本的数据类型吗?
  • 基本数据类型包括 byte、int、char、long、float、double、boolean 和 short。
  • java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用 StringBuffer 类
31. String s = “Hello”;s = s + " world!"; 这两行代码执行后 ,原始的 String 对象中的内容到底变了没有?
  • 没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s 原先指向一个 String 对象,内容是 “Hello”,然后我们对 s 进行了+操作,那么 s 所指向的那个对象是否发生了改变呢?答案是没有。这时,s 不指向原来那个对象了,而指向了另一个 String 对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
32. 是否可以继承 String?
  • String 类是 final 类故不可以继承。
33. String s = new String(“xyz”); 创建了几个 String Object?二者之间有什么区别?
  • 两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String 每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新 String 对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。
34. String 和 和 StringBuffer的区别
  • JAVA 平台提供了两个类:String 和 StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个 String 类提供了数值不可改变的字符串。而这个 StringBuffer 类提供的字符串可以进行修改。当你知道字符数据要改变的时候你就可以使用 StringBuffer。典型地,你可以使用 StringBuffers 来动态构造字符数据。另外,String 实现了 equals 方法,new String(“abc”).equals(new String(“abc”)的结果为 true,而 StringBuffer 没有实现 equals 方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为 false。
35. 如何把一段逗号分割的字符串转换成一个数组?
  • 用正则表达式,代码大概为:String [] result = orgStr.split(“,”);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ww空ww

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值