能够有多个类,但只能有一个public的类,而且public的类名必须与文件名相一致。java
java中的保留字,如今没有在java中使用。web
&和&&均可以用做逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,不然,只要有一方为false,则结果为false。面试
&&还具备短路的功能,即若是第一个表达式为false,则再也不计算第二个表达式,例如,对于if(str!= null&& !str.equals(s))表达式,当str为null时,后面的表达式不会执行,因此不会出现NullPointerException若是将&&改成&,则会抛出NullPointerException异常。If(x==33 &++y>0) y会增加,If(x==33 && ++y>0)不会增加算法
&还能够用做位运算符,当&操做符两边的表达式不是boolean类型时,&表示按位与操做,咱们一般使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。编程
在Java中,要想跳出多重循环,能够在外面的循环语句前定义一个标号,而后在里层循环体的代码中使用带有标号的break语句,便可跳出外层循环。windows
例如:api
for(int i=0;i<10;i++){
for(intj=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(intj=0;j<arr[i].length;j++){System.out.println(“i=” + i + “,j=” + j);if(arr[i][j] ==5) {found =true;break;}}}复制代码
在switch(e)中,e只能是一个整数表达式或者枚举常量(更大字体),整数表达式能够是int基本类型或Integer包装类型,因为byte,short,char均可以隐含转换为int,因此,这些类型以及这些类型的包装类型也是能够的。显然,long和String类型都不符合switch的语法规定,而且不能被隐式转换成int类型,因此,它们不能做用于swtich语句中。安全
对于short s1= 1; s1 = s1 + 1;因为s1+1运算时会自动提高表达式的类型,因此结果是int型,再赋值给short类型s1时,编译器将报告须要强制转换类型的错误。bash
对于short s1= 1; s1 += 1;因为 +=是java语言规定的运算符,java编译器会对它进行特殊处理,所以能够正确编译。
char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,因此,char型变量中固然能够存储汉字啦。不过,若是某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,因此,char类型的变量也是占用两个字节。
2<< 3,(左移三位)由于将一个数左移n位,就至关于乘以了2的n次方,那么,一个数乘以8只要将其左移3位便可,而位运算cpu直接支持的,效率最高,因此,2乘以8等於几的最效率的方法是2<< 3。
使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容仍是能够改变的。例如,对于以下语句:
final StringBuffer a=new StringBuffer("immutable");
复制代码
a=new StringBuffer("");
复制代码
a.append(" broken!");
复制代码
有人在定义方法的参数时,可能想采用以下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){}复制代码
实际上,这是办不到的,在该方法内部仍然能够增长以下代码来修改参数对象:
param.append("a");
复制代码
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须建立了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,因此也称为类变量,只要程序加载了类的字节码,不用建立任何实例对象,静态变量就会被分配空间,静态变量就能够被使用了。总之,实例变量必须建立对象后才能够经过这个对象来使用,静态变量则能够直接使用类名来引用。
例如,对于下面的程序,不管建立多少个实例对象,永远都只分配了一个staticVar变量,而且每建立一个实例对象,这个staticVar就会加1;可是,每建立一个实例对象,就会分配一个instanceVar,便可能分配多个instanceVar,而且每一个instanceVar的值都只自加了1次。
public class VariantTest{publicstatic int staticVar = 0;publicint instanceVar = 0;publicVariantTest(){staticVar++;instanceVar++;System.out.println(staticVar +instanceVar);}}复制代码
不能够。由于非static方法是要与对象关联在一块儿的,必须建立一个对象后,才能够在该对象上进行方法调用,而static方法调用时不须要建立对象,能够直接调用。也就是说,当一个static方法被调用时,可能尚未建立任何实例对象,若是从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪一个对象上的呢?这个逻辑没法成立,因此,一个static方法内部发出对非static方法的调用。
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中还定义了表示整数的最大值和最小值的常量。
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。
这里有一些笔误,floor的英文意义是地板,该方法就表示向下取整,Math.floor(11.6)的结果为11,Math.floor(-11.6)的结果是-12;
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中能够有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不一样)。
重写Override表示子类中的方法能够与父类中的某个方法的名称和参数彻底相同,经过子类建立的实例对象调用这个方法时,将调用子类中的定义方法,这至关于把父类中定义的那个彻底相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,由于子类能够解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。若是父类的方法是private类型,那么,子类则不存在覆盖的限制,至关于子类中增长了一个全新的方法。
至于Overloaded的方法是否能够改变返回值的类型这个问题,要看你倒底想问什么呢?这个题目很模糊。若是几个Overloaded的方法的参数列表不同,它们的返回者类型固然也能够不同。但我估计你想问的问题是:若是两个方法的参数列表彻底同样,是否可让它们的返回值不一样来实现重载Overload。这是不行的,咱们能够用反证法来讲明这个问题,由于咱们有时候调用一个方法时也能够不定义返回结果变量,即不要关心其返回结果,例如,咱们调用map.remove(key)方法时,虽然remove方法有返回值,可是咱们一般都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表彻底相同的方法,仅仅是返回类型不一样,java就没法肯定编程者倒底是想调用哪一个方法了,由于它没法经过返回结果类型来判断。
override能够翻译为覆盖,从字面就能够知道,它是覆盖了一个方法而且对其重写,以求达到不一样的做用。对咱们来讲最熟悉的覆盖就是对接口方法的实现,在接口中通常只是对方法进行了声明,而咱们在实现时,就须要实现接口声明的全部方法。除了这个典型的用法之外,咱们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意如下的几点:
一、覆盖的方法的标志必需要和被覆盖的方法的标志彻底匹配,才能达到覆盖的效果;
二、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
三、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
四、被覆盖的方法不能为private,不然在其子类中只是新定义了一个方法,并无对其进行覆盖。
Overload对咱们来讲可能比较熟悉,能够翻译为重载,它是指咱们能够定义一些名称相同的方法,经过定义不一样的输入参数来区分这些方法,而后再调用时,VM就会根据不一样的参数样式,来选择合适的方法执行。在使用重载要注意如下的几点:
一、在使用重载时只能经过不一样的参数样式。例如,不一样的参数类型,不一样的参数个数,不一样的参数顺序(固然,同一方法内的几个参数类型必须不同,例如能够是fun(int,float),可是不能为fun(int,int));
二、不能经过访问权限、返回类型、抛出的异常进行重载;
三、方法的异常类型和数目不会对重载形成影响;
四、对于继承来讲,若是某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,若是定义的话,也只是定义了一个新方法,而不会达到重载的效果。
接口能够继承接口。抽象类能够实现(implements)接口,抽象类能够继承具体类。抽象类中能够有静态的main方法。
备注:只要明白了接口和抽象类的本质和做用,这些问题都很好回答,你想一想,若是你是java语言的设计者,你是否会提供这样的支持,若是不提供的话,有什么理由吗?若是你没有道理不提供,那答案就是确定的了。
只要记住抽象类与普通类的惟一区别就是不能建立实例对象和容许有abstract方法。
靠的是父类或接口定义的引用变量能够指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
1.抽象类能够有构造方法,接口中不能有构造方法。
2.抽象类中能够有普通成员变量,接口中没有普通成员变量
3.抽象类中能够包含非抽象的普通方法,接口中的全部方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型能够是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,而且默认即为public abstract类型。
5. 抽象类中能够包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中均可以包含静态成员变量,抽象类中的静态成员变量的访问类型能够任意,但接口中定义的变量只能是publicstatic final类型,而且默认即为publicstatic final类型。
7. 一个类能够实现多个接口,但只能继承一个抽象类。
abstract的method不能够是static的,由于抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另一种依赖平台的编程语言实现的,不存在着被子类实现的问题,因此,它也不能是抽象的,不能与abstract混用。例如,FileOutputSteam类要硬件打交道,底层的实现用的是操做系统相关的api实现;例如,在windows用c语言实现的,因此,查看jdk的源代码,能够发现FileOutputStream的open方法的定义以下:
private native void open(Stringname) throwsFileNotFoundException;
复制代码
若是咱们要用java调用别人写的c语言函数,咱们是没法直接调用的,咱们须要按照java的要求写一个c语言的函数,又咱们的这个c语言函数去调用别人的c语言函数。因为咱们的c语言函数是按java的要求来写的,咱们这个c语言函数就能够与java对接上,java那边的对接方式就是定义出与咱们这个c函数相对应的方法,java中对应的方法不须要写具体的代码,但须要在前面声明native。
关于synchronized与abstract合用的问题,我以为也不行,由于在我几年的学习和开发中,历来没见到过这种状况,而且我以为synchronized应该是做用在一个具体的方法上才有意义。并且,方法上的synchronized同步所使用的同步锁对象是this,而抽象方法上没法肯定this是什么。
彻底能够。若是不是静态内部类,那没有什么限制!
若是你把静态嵌套类看成内部类的一种特例,那在这种状况下不能够访问外部类的普通成员变量,而只能访问外部类中的静态成员,例如,下面的代码:
class Outer{static int x;static class Inner{voidtest(){syso(x);}}}复制代码
没有。由于String被设计成不可变(immutable)类,因此它的全部对象都是不可变对象。在这段代码中,s原先指向一个String对象,内容是 "Hello",而后咱们对s进行了+操做,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另外一个 String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量再也不指向它了。
经过上面的说明,咱们很容易导出另外一个结论,若是常常对字符串进行各类各样的修改,或者说,不可预见的修改,那么使用String来表明字符串的话会引发很大的内存开销。由于String对象创建以后不能再改变,因此对于每个不一样的字符串,都须要一个String对象来表示。这时,应该考虑使用StringBuffer类,它容许修改,而不是每一个不一样的字符串都要生成一个新的对象。而且,这两种类的对象转换十分容易。
同时,咱们还能够知道,若是要使用内容相同的字符串,没必要每次都new一个String。例如咱们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样作:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
复制代码
而非
s = new String("Initial Value");
复制代码
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,而且没有意义,由于String对象不可改变,因此对于内容相同的字符串,只要一个String对象来表示就能够了。也就说,屡次调用上面的构造器建立多个对象,他们的 String类型属性s都指向同一个对象。
上面的结论还基于这样一个事实:对于字符串常量,若是内容相同,Java认为它们表明同一个String对象。而用关键字new调用构造器,老是会建立一个新的对象,不管内容是否相同。
至于为何要把String类设计成不可变类,是它的用途决定的。其实不仅String,不少Java标准类库中的类都是不可变的。在开发一个系统的时候,咱们有时候也须要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优势,好比由于它的对象是只读的,因此多线程并发访问也不会有任何问题。固然也有一些缺点,好比每一个不一样的状态都要一个对象来表明,可能会形成性能上的问题。因此Java标准类库还提供了一个可变版本,即StringBuffer。
这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,至关于一种动态的数组,咱们之后能够按位置索引号取出某个元素,而且其中的数据是容许重复的,这是与HashSet之类的集合的最大不一样处,HashSet之类的集合不能够按索引号去检索其中的元素,也不容许有重复的元素。
ArrayList与Vector的区别主要包括两个方面:.
(1)同步性:
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不一样步的。若是只有一个线程会访问到集合,那最好是使用ArrayList,由于它不考虑线程安全,效率会高些;若是有多个线程会访问到集合,那最好是使用Vector,由于不须要咱们本身再去考虑和编写线程安全的代码。
(2)数据增加:
ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就须要增长ArrayList与Vector的存储空间,每次要增长存储空间时,不是只增长一个存储单元,而是增长多个存储单元,每次增长的存储单元的个数在内存空间利用与程序效率之间要取得必定的平衡。Vector默认增加为原来两倍,而ArrayList的增加策略在文档中没有明确规定(从源代码看到的是增加为原来的1.5倍)。ArrayList与Vector均可以设置初始的空间大小,Vector还能够设置增加的空间大小,而ArrayList没有提供设置增加空间的方法。
总结:即Vector增加原来的一倍,ArrayList增长原来的0.5倍。
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap容许空(null)键值(key),因为非线程安全,在只有一个线程访问的状况下,效率要高于Hashtable。
HashMap容许将null做为一个entry的key或者value,而Hashtable不容许。
HashMap把Hashtable的contains方法去掉了,改为containsvalue和containsKey。由于contains方法容易让人引发误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不一样是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不须要本身为它的方法实现同步,而HashMap就必须为之提供同步。
就HashMap与HashTable主要从三方面来讲。
一.历史缘由:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
三.值:只有HashMap可让你将空值做为一个表的条目的key或value
一个是存储单列数据的集合,另外一个是存储键和值这样的双列数据的集合,List中存储的数据是有顺序,而且容许重复;Map中存储的数据是没有顺序的,其键是不能重复的,它的值是能够有重复的。
List,Set是,Map不是
(这样的题比较考水平,两个方面的水平:一是要真正明白这些内容,二是要有较强的总结和表述能力。)
首先,List与Set具备类似性,它们都是单列元素的集合,因此,它们有一个共同的父接口,叫Collection。Set里面不容许有重复的元素,即不能有两个相等(注意,不是仅仅是相同)的对象,即假设Set集合中有了一个A对象,如今我要向Set集合再存入一个B对象,但B对象与A对象equals相等,则B对象存储不进去,因此,Set集合的add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true,当集合含有与某个元素equals相等的元素时,此时add方法没法加入该元素,返回结果为false。Set取元素时,不能细说要取第几个,只能以Iterator接口取得全部的元素,再逐一遍历各个元素。
List表示有前后顺序的集合,注意,不是那种按年龄、按大小、按价格之类的排序。当咱们屡次调用add(Obje)方法时,每次加入的对象就像火车站买票有排队顺序同样,按先来后到的顺序排序。有时候,也能够插队,即调用add(intindex,Obj e)方法,就能够指定当前对象在集合中的存放位置。一个对象能够被反复存储进List中,每调用一次add方法,这个对象就被插入进集合中一次,其实,并非把这个对象自己存储进了集合中,而是在集合中用一个索引变量指向这个对象,当这个对象被add屡次时,即至关于集合中有多个索引指向了这个对象,如图x所示。List除了能够用Iterator接口取得全部的元素,再逐一遍历各个元素以外,还能够调用get(index i)来明确说明取第几个。
Map与List和Set不一样,它是双列的集合,其中有put方法,定义以下:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。取则能够根据key得到相应的value,即get(Object key)返回值为key所对应的value。另外,也能够得到全部的key的结合,还能够得到全部的value的结合,还能够得到key和value组合成的Map.Entry对象的集合。
List以特定次序来持有元素,可有重复元素。Set没法拥有重复元素,内部排序。Map保存key-value值,value可多值。
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增长和插入元素,它们都容许直接按序号索引元素,可是插入元素要涉及数组元素移动等内存操做,因此索引数据快而插入数据慢,Vector因为使用了synchronized方法(线程安全),一般性能上较ArrayList差。而LinkedList使用双向链表实现存储,按序号索引数据须要进行前向或后向遍历,索引就变慢了,可是插入数据时只须要记录本项的先后项便可,因此插入速度较快。
LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList能够被看成堆栈和队列来使用。
Vector newVector = new Vector();For (int i=0;i<vector.size();i++){Object obj = vector.get(i);if(!newVector.contains(obj);newVector.add(obj);}复制代码
还有一种简单的方式,利用了Set不容许重复元素:
Collection是集合类的上级接口,继承他的接口主要有Set和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各类集合的搜索、排序、线程安全化等操做。
Set里的元素是不能重复的,元素重复与否是使用equals()方法进行判断的。
==和equal区别也是考烂了的题,这里说一下:
==操做符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操做符。
equals方法是用于比较两个独立对象的内容是否相同,就比如去比较两我的的长相是否相同,它比较的两个对象是独立的。
好比:两条new语句建立了两个对象,而后用a/b这两个变量分别指向了其中一个对象,这是两个不一样的对象,它们的首地址是不一样的,即a和b中存储的数值是不相同的,因此,表达式a==b将返回false,而这两个对象中的内容是相同的,因此,表达式a.equals(b)将返回true。
最经常使用的集合类是 List 和 Map。 List的具体实现包括 ArrayList和 Vector,它们是可变大小的列表,比较适合构建、存储和操做任何类型对象的元素列表。 List适用于按数值索引访问元素的情形。
Map 提供了一个更通用的元素存储方法。 Map集合类用于存储元素对(称做"键"和"值"),其中每一个键映射到一个值。
它们都有增删改查的方法。
对于set,大概的方法是add,remove, contains等
对于map,大概的方法就是put,remove,contains等
List类会有get(int index)这样的方法,由于它能够按顺序取元素,而set类中没有get(int index)这样的方法。List和set均可以迭代出全部元素,迭代时先要获得一个iterator对象,因此,set和list类都有一个iterator方法,用于返回那个iterator对象。map能够返回三个集合,一个是返回全部的key的集合,另一个返回的是全部value的集合,再一个返回的key和value组合成的EntrySet对象的集合,map也有get方法,参数是key,返回值是key对应的value,这个自由发挥,也不是考记方法的能力,这些编程过程当中会有提示,结合他们三者的不一样说一下用法就行。
Java知音公众号整理一些各大公司经常使用的面试笔试题,供你们在天天闲暇之余学习其中几道题目,日积月累,等到出去面试时,一切都水到渠成,面试时就天然会游刃有余了。