java基础面试题
1. 一个”.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
可以有多个类,但只能有一个public的类,并且public 的类名必须和文件名相一致.
2. Java有没有goto? 它是java中的保留字,现在没有在java中使用.
3. &和&&的区别?
他们2个都可以用作逻辑与的运算符.表示逻辑语and,当运算符两边的表达式结果都为true时,整个运算结果才为true.
不同点:&&具有短路的功能,如果第一个表达式为false,则不再计算第二个表达式,如对于if(str!=null && !str.equals(“”))的表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException.如果将&&改为&,则会抛出NullPointerException异常.
&还可以用作运算符,当&操作符两边的表达式不是boolean类型时,&表示安位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31&0x0f的结果为0x01.
4. 在java中如何跳出当前的多重嵌套循环?
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。
代码如下:
- loop:
- for(int i=0;i<10;i++) {
- System.out.println(i);
- for(int j=0;j<10;j++) {
- System.out.println("i=" + i +",j=" + j);
- if(j == 5) break loop;
- }
- }
loop: for(int i=0;i<10;i++) { System.out.println(i); for(int j=0;j<10;j++) { System.out.println("i=" + i +",j=" + j); if(j == 5) break loop; } }
我个人通常并不使用标号这种方式,而是让外层的循环条件表达式的结果可以受到里层循环体代码的控制,例如,要在二维数组中查找到某个数字。
代码如下:
- int arr[][] ={{1,2,3},{4,5,6,7},{9}};
- // int d=0;
- // byte a=1;
- // char b=1;
- short c=1;
- 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; } }
int arr[][] ={{1,2,3},{4,5,6,7},{9}}; // int d=0; // byte a=1; // char b=1; short c=1; 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(x)中,x只能是一个整数表达式或者枚举常量,整数表达式可以说inte或Interger包装类型.因为byte,short,char都可以隐式转换为int,所以这些类型都可以,但明显long或String不行.
6. 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都是占用两个字节.
8. 最有效率计算2*8等于几?
2<<3
因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8,只要将其左移3位就可以了.而位运算cpu直接支持,效率最高.
1. 使用final关键字修饰一个变量,是引用不能变,还是引用的对象不能变?
使用final修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.
如: final StringBuffer a=new StringBuffer(“zhaoqian”);
执行以下语句会报道编译器错误: a=new StringBuffer(“”);
但执行以下语句可以通过编译: a.append(“let”);
如方法体method
Public void method(final StringBuffer param){}
该方法内部可以增加如下代码修改参数: param.append(“a”);
12.静态变量和实例变量的区别?
在语法定义上的区别:
静态变量前要加static关键字,而实例变量不加.
程序运行的区别:
实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间.
静态变量不属于某个实例对象,而是属于类,所以也可称类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了.
总之,实例变量必须创建对象后才可以通过对象来使用,静态变量这可以直接用类名引用.
Publicclass Test{
public static int staticVar=0;
public int instanceVar=0;
public Test()
{staticVar++;
instanceVar++;
System.out.println(“staticVar=”+staticVar+”,instanceVar=”+instanceVar);}
上面的例子,无论创建多少实例对象,永远只分配一个staticVar变量,并且每创建一个实例对象,这个staticVar就会加一;但是,每创建一个实例对象,就会分配一个instanceVar,即可能分配多个instanceVar,并且每个instanceVar的值都只加了一次.
13.是否可以用一个static方法内部发出对非static方法的调用?
不可以.
因为非static方法是要和对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用.
而static方法调用的时候不需要创建对象,可以直接调用.也就是说一个static方法被调用的时候,可能还没有创建任何实例对象.
如果从一个static方法中发出对非static的调用,那非static方法是关联到哪个对象上呢?逻辑错误,所以,一个static方法无法从内部发出对非static方法的调用.
14.Integer和int的区别
Int是java提供的原始数据类型之一.Java为每个原始类型提供了封装类.
Integer就是java为int提供的封装类.
Int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别.
而int无法表达出没有赋值的情况.比如,要表达出没参加考试和考试为0的区别,用Integer.
在JSP开发中,integet默认为null,所以用el表达式在文本框中显示为空白字符串,而int则显示为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.floor(11.6)的结果为11,Math.floor(-11.6)的结果是-12;
round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
16.下面代码的不妥之处.
a.if(username.equals(‘zxx’)){}
不妥:如果username为空的话,会报空指针错误.java.lang.NullPointerException
实际开发中应这么写: if(“zxx”.equals(username)){};
Bint x=1; return x==1?true:false;
从代码上看,返回的肯定是true,不需要这么复杂,直接指定返回值就可以了.
17.访问修饰符
如果在修饰的元素上没有写任何的访问修饰符,就表示为friendly.
作用域 当前类 同一包 子类 其他包
Public y y y y
Protected y y y X
Friendly y y x x
Private y x x x
18.Overload和Override的区别.Overloaded的方法是否可以改变返回值的类型?
重载Ocerload表示一个类中可以有多个名称相同的方法,但这些方法的参数列表不相同(就是参数个数或类型不同).
重写Override表示子类中的方法可以和父类中某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法的时候,将用子类中的定义的方法.这相当于把父类中定义的那个完全相同的方法给覆盖率.这也是面向对象编程的多态性的一种表现.子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题.子类的访问权限只能比父类的更大,不能跟小.如果父类是private,那么子类则不存在覆盖的限制,相等于子类中增加了一个全新的方法.
至于Overloaded的方法是否可以改变返回值的类型这个问题,
如果几个Overloaded的方法的参数列表不一样,他们的返回者类型也可以不一样.
如果两个方法的参数列表完全一样,是否可以让他们的返回值不同来实现重载overload,这是不行的.
反证法证明:
因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果.例如我们调用map.remove(key)方法时,虽然remove没有返回值,但是我们通常都不会定义接受返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,那么java无法确定编程者到底是想要调用哪个方法,因此它无法通过返回结果类型来判断.
Override可以翻译为覆盖,它覆盖了一个方法并对其重写,以求达到不同的作用.
对我们来说,最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了生命,而我们在实现时,就需要实现接口声明的所有方法,除了这个典型的用法外,我们在继承中,也可能会在子类覆盖父类方法.
在覆盖要注意一下几点:
1. 覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果.
2. 覆盖的方法的返回值必须和被覆盖的方法的返回值一致.
3. 覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致.
4. 被覆盖的方法不能为private,否则其子类中只是定义了一个新方法.并没有对其覆盖.
Overload为重载,它指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后在调用时,VM就会根据不同的参数样式,来选择合适的方法进行执行,注意以下几点:
1. 在使用重载时只能通过不同的参数样式,参数类型或参数个数的不同.
2. 不能通过访问权限,返回类型,抛出异常进行重载.
3. 方法的异常类型和数目不会对重载造成影响.
4. 对于继承来说,如果某一方法在父类中访问的权限是private,那么就不能在子类对其进行重载,如果定义的话,也是定义了一个新方法,不会达到重载的效果.
19.hasa和is a的区别?
Is-a表示的是属于的关系,比如兔子属于一种动物,继承关系.has-a表示祝贺,包含关系.如兔子含有腿.
20.构造器Constructor是否可以被override?
构造器不能被继承,因此不能重写.但是可以被重载Overload.构造器其实可以简单理解为构造方法.
21.super.getClass()方法调用,下面程序的输出结果是多少?
I
- mportjavautil.Date;
- Publicclass Test extends Date{
- Public static void main(String[] args){
- New Test().test();
- }
- Public void test(){
- System.out.println(super.getClass().getName());
- }
- }
mportjavautil.Date; Publicclass Test extends Date{ Public static void main(String[] args){ New Test().test(); } Public void test(){ System.out.println(super.getClass().getName()); } }
在test方法中,直接调用getClass().getName()方法,返回的是Test的类名.
由于getClass()在Object
类中,定义了final,之类不能覆盖这个方法,所以在test方法中调用的getClass().getName()方法,其实就是在调用从父类继承的getClass()方法,等效于调用super.getClass().getName()方法,所以super.getClass().getName()方法返回的也应该是Test.
如果想得到父类的名称,应该用以下的代码:
GetClass().getSuperClass().getName();
22.jdk中哪些类似不能继承的?
不能继承的是那些用final的类.一般比较基本的类型或者防止扩展类无意间破坏原来的方法的实现的类型都应该是final的.在jdk中,System,String,StringBuffer等都是基本数据累累.
1.说出一些常用的类,包,接口,请各举5个
常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer
java.util.Date,System,Class,List,HashMap
常用的包:java.lang java.io java.util java.sql,javax.servlet,org.apache.strtuts.action,org.hibernate
常用的接口:Remote List Map Document NodeList,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)、Session(Hibernate),HttpSession
2. java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
字节流,字符流。字节流继承于InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。
3.字节流与字符流的区别
字节流与字符流主要的区别是他们的的处理方式
(1).字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;
(2).字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
4. 什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。
要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输,但是,jre本身就提供了这种支持,我们可以调用OutputStream的writeObject方法来做,如果要让java 帮我们做,要被传输的对象必须实现serializable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。需要被序列化的类必须实现Serializable接口,该接口是一个mini接口,其中没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。
例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输或通过rmi等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现Serializable接口。
5、描述一下JVM加载class文件的原理机制?
JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
6.GC是什么? 为什么要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
7.垃圾回收的优点和原理。并考虑2种回收机制。
Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
8.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
9.什么时候用assert?
断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true。如果表达式计算为 false,那么系统会报告一个 Assertionerror。它用于调试目的:
assert(a > 0); // throws anAssertionerror if a <= 0
断言可以有两种形式:
assert Expression1 ;
assert Expression1 :Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式。这个值用于生成显示更多调试信息的 String 消息。
断言在默认情况下是禁用的。要在编译时启用断言,需要使用 source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用 -enableassertions 或者 -ea 标记。
要在运行时选择禁用断言,可使用 -da 或者 -disableassertions 标记。
要系统类中启用断言,可使用 -esa 或者 -dsa 标记。还可以在包的基础上启用或者禁用断言。
可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
10. 、java中会存在内存泄漏吗,请简单描述
会的。 return(i-i2); //when i为足够大的正数,i2为足够大的负数,导致错误。
11. 能不能自己写个类,也叫java.lang.String?
可以,但是在应用的时候,要用自己类的加载器去加载.否则,系统的类加载器永远加载jre.jar中的java.lang.String. 由于在tomcat的web应用程序中,都是由webapp自己的类加载器先自己加载WEB-INF/classess目录中的类,然后才委托上级的类加载器加载,如果我们在tomcat的web应用程序中写一个java.lang.String,这时候Servlet程序加载的就是我们自己写的java.lang.String,但是这么干就会出很多潜在的问题,原来所有用了java.lang.String类的都将出现问题。