目录
一. Java 基础部分
第一天:
1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制
2、Java 有没有 goto?
3、说说&和&&的区别?
4、switch 语句能否作用在 byte 上,能否作用在 long上,能否作用在String上
5、a=a+b 与 a+=b 有什么区别吗
6、char 型变量中能不能存储一个中文汉字?为什么?
7、用最有效率的方法算出 2 乘以 8 等于几?
8、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变
第二天
9、"=="和 equals 方法究竟有什么区别
10、两个对象值相同 (x.equals(y) == true) ,但却可有不同的 hashCode,这句 话对不对
3*0.1 == 0.3 返回值是什么
11、静态变量和实例变量的区别?
12、是否可以从一个 static 方法内部发出对非 static 方法的调用?
Java 自动装箱与拆箱
13、Integer 与 int 的区别
14、Math.round(11.5)等于多少? Math.round(-11.5)等于多少
15、请说出作用域 public,private,protected,以及不写时的区别
16、Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?
第三天
17、构造器 Constructor 是否可被 override?
18、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的 main 方法?
19、写 clone()方法时,通常都有一行代码,是什么?
20、面向对象的特征有哪些方面
21、java 中实现多态的机制是什么?
22、abstract class 和 interface 有什么区别?
23、abstract 的 method 是否可同时是 static,是否可同时是 native,是否可同时是 synchronized?
24、为什么函数不能根据返回类型来区分重载?
每天八道题,想要全部的面试题可以私我
基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的语法,虚拟机方面的语法
可以有多个类,但是只能有一个public类,并且public类的类名必须和文件名一致
goto是Java中的保留字,在目前版本中并没有使用,有些地方称为保留字,但是保留字这个词应该有更广泛的意义,熟悉C语言的程序员应该都知道,在系统类库中使用过有特殊意义的单词或者单词的组合都视为保留字
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算结果两边结果都为true时,整个运算结果才为true,只要有一边结果为false,整个运算结果都为fals
&&还具有短路功能,即如果第一个表达式结果为false时,第二个表达式则不再运算,比如 if(x!=null && y++>0) ,如果x=null时,后面的表达式就不会执行,所以不会出现 NullPointerException 如果将&&改为&,则会抛出 NullPointerException 异常。If(x==33 & ++y>0) y 会增长,If(x==33 && ++y>0)不会增长
&还可以用作位运算,当&操作符两边的表达式不是boolean类型时,&表示按为与操作,我们通常使用 0x0f 来与一个整数进行&运算,来获取该整数的最低 4 个 bit 位,例如,0x31 & 0x0f 的结果为 0x01。
备注:这道题先说两者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来表明自己理解透彻深入、实际经验丰富
在switch(xxx)中, xxx只能是一个整数表达式或者枚举常量,整数表达式可以是int基本类型 或者Integer包装类,由于byte,short,char都可以隐含转换为int,所以这些类型以及这些类型的包装类也是可以的
long和Strig类型都不符合Stitch语法规定,并且不能被隐式转换为int类型,所有不能作用与switch语句中,Java7之后String是支持的,Long不支持
+=操作符会进行隐式自动类型转换,而a=a+b则不会进行自动类型转换,
例如: short a = 1; short b = 1; 如果用 a=a+b 就会报错不兼容类型,因为 short在进行运算的时候会自动转型为int类型,也就是说a+b之后的运算结果为int类型, 而左边的a为short类型,编译会出错
如果用a+=b的话,+=会对右边的表达式结果进行强转匹配为左边的数据类型,所以不会出错
char型变量存储的是Unicode编码的字符,Unicode编码包含汉字,当然可以存储汉字啦,但是如果某些特殊汉字没有包含在Unicode编码的字符集中,那么,这个char类型就不能存储这个特殊汉字
补充:Unicode编码暂用两个字节,所以char类型的变量也是占用了两个字节
2<<3
因为将一个数左移n位,就相当于2的n次方,那么,一个数乘以8,只需要将其左移3位即可,而位运算是cpu直接支持的,效率最高,所以2X8最有效率是2<<3
使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指的对象中的内容还是可以改变的
==操作符是专门用来比较两个变量的值是否相等,,也就是说用于比较两个变量所对应的内存所存储的数值是否相等,要比较两个基本类型数据或者两个引用变量是否相等,只能用==操作符
equals方法用于比较两个独立对象的内容是否相等,就好比去比较两个人的长相是否相同,它所比较的两个对象是独立的,比如两个new语句创建两个对象,然后new出来的这两个变量分别指向其中一个对象,这是两个不同的对象,他们首选的地址是不同的.即两个变量所储存的数值也是不同的,所以两个变量如果用==会返回false,用equals返回true
不对,如果两个对象x和y用equals比较返回true,他们的hashCode应当相同,Java对于equals方法和hashCode方法是这样规定的:
1) 如果两个对象用equals方法返回true,那么他们的hashCode值一定要相同
2) 如果两个对象的hashCode相同,他们并不一定相同
3)对于类中的关键属性,检查参数传入对象的属性是否与之匹配
4) 编写完equals方法后,问自己是否满足对称性,传递性,一致性
5) 重写equals时,总是要重写hashCode
6) 不要将equals方法参数中的Object对象替换成其他数据类型,在重写时不要忘掉@Override注解
false,应为浮点数不能完全精确的表示出来
语法上静态变量前要加 static 关键字,而实例变量前则不加
程序上实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态 变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静 态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而 static 方法调用时不需要创建对象,可以直接调用。也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个 static 方法内部发出对非 static方法内部发出对static 方法的调用。
装箱就是自动将基本数据类型转换为包装器类型(int-->Integer);调用方法:Integer 的 valueOf(int) 方法
拆箱就是自动将包装器类型转换为基本数据类型(Integer-->int)。调用方法:Integer 的 intValue 方
int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 java 为 int 提供的封装类。int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为0的区别,int 则无法表达出未赋值的情况
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
这四个作用域的可见范围如下表所示。 说明:如果在修饰的元素上面没有写任何访问修饰符,则表示 friendly
作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ X
friendly √ √ X X
private √ X X X
备注:只要记住了有 4 种访问权限,4 个访问范围,然后将全选和范围在水平和垂直方向上分别按排从小到大或从大到小的顺序排列,就很容 易画出上面的图了
Overload 是重载的意思,Override 是覆盖的意思,也就是重写。
重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)
构造器 Constructor 不能被继承,因此不能重写 Override,但可以被重载 Overload。
接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承具体类。抽象类中可以有静态的 main 方法。
只有记住抽象类与普通类的唯一区别就是不能创建实例对象和允许有 abstract 方法。
clone 有缺省行为,super.clone();因为首先要把父类中的成员复制到位,然后才是复制自己的成员。
Java 创建对象有几种方式?
java 中提供了以下四种创建对象的方式:
1. new 创建新对象
2.通过反射机制
3.采用 clone 机制
4. 通过序列化机制
面向对象的编程语言有封装、继承 、抽象、多态等 4 个主要的特征。
封装:
封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影 响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一 个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的 属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访 问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则: 把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中。
抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和 目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包 括行为抽象和状态抽象两个方面。
继承:
在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若 干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高 了软件的可重用性和可扩展性。
多态:
多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个 引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运 行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即 不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性增强了软件的灵活性和扩展性。
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具 体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是 public,protected 和(默认类型,虽然 eclipse 下不报错,但应该也不行),但接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是 public static final 类型,并且默认即为 public static final 类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类
说两者在应用上的区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用, 例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有 Servlet 类都要用相同的方式进行权限判断、记录访问日志和处理异常, 那么就可以定义一个抽象的基类,让所有的 Servlet 都继承这个抽象基类,在抽象基类的 service 方法中完成权限判断、记录访问日志和处理异常的 代码,在各个子类中只是完成各自的业务逻辑代码,父类方法中间的某段代码不确定,留给子类干,就用模板方法设计模式。
abstract 的 method 不可以是 static 的,因为抽象的方法是要被子类实现的,而 static 与子类扯不上关系!
native 方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与 abstract 混 用。
该道题来自华为面试题。
因为调用时不能指定类型信息,编译器不知道你要调用哪个函数。
例如:
1.float max(int a, int b);
2.int max(int a, int b);
当调用 max(1, 2);时无法确定调用的是哪个,单从这一点上来说,仅返回值类型不同的重载是不应该允许的。
再比如对下面这两个方法来说,虽然它们有同样的名字和自变量,但其实是很容易区分的: 1.void f() {}
2.int f() {}
若编译器可根据上下文(语境)明确判断出含义,比如在 int x=f()中,那么这样做完全没有问题。然而, 我们也可能调用一个方法,同时忽略返回值;我们通常把这称为“为它的副作用去调用一个方法”,因为我 们关心的不是返回值,而是方法调用的其他效果。所以假如我们像下面这样调用方法: f(); Java 怎样判断 f()的具体调 用方式呢?而且别人如何识别并理解代码呢?由于存在这一类的问题,所以不能。函数的返回值只是作为函数运行之后的一个“状态”,他是 保持方法的调用者与被调用者进行通信的关键。并不能 作为某个方法的“标识”。
基本数据类型包括 byte、int、char、long、float、double、boolean 和 short。 java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用 StringBuffer 类
没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s 最开始指向一个 String 对象,内容是 "Hello",然后我们对 s 进行了+操作,。这时,s 就不指向原来那个对象了,而指向了另一个 String 对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了
通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用 String 来代表字符串的话会引起很大的内存开销。因为 String 对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个 String 对象来表示。这时, 应该考虑使用 StringBuffer 类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。
至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在开发一个系统 的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的, 所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以 Java 标准 类库还提供了一个可变版本,即 StringBuffer。
不可以,因为String是final类,所以不可以被继承
两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String 每写 一遍,就创建一个新的对象,它语句中那个常量”xyz”对象的内容来创建出一个新 String 对象。如果以前就用过’xyz’,这句代表就不会创建”xyz” 自己了,直接从缓冲区拿。
JAVA 平台提供了两个类:String 和 StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个 String 类提供了数值不可改 变的字符串。而这个 StringBuffer 类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用 StringBuffer。典型地,你可以使用StringBuffers 来动态构造字符数据。另外,String 实现了 equals 方法,newString“(abc”).equals(new String“( abc”)的结果为 true,而 StringBuffer 没有实现 equals 方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为 false。
在讲两者区别时,应把循环的次数搞成 10000,然后用 endTime-beginTime 来比较两者执行的时间差异,最后还要讲讲 StringBuilder 与 StringBuffer 的区别。String 覆盖了 equals 方法和 hashCode 方法,而 StringBuffer 没有覆盖 equals 方法和 hashCode 方法,所以,将 StringBuffer 对象存储进 Java 集合类中时会出现问题。
StringBuffer、StringBuilder 和 String 一样,也用来代表字符串。String 类是不可变类,任何对 String 的改变都 会引发新的 String 对象的生成; StringBuffer 则是可变类,任何对它所指代的字符串的改变都不会产生新的对象。既然可变和不可变都有了,为何还有一个 StringBuilder 呢?相信初 期的你,在进行 append 时,一般都会选择 StringBuffer 吧!
先说一下集合的故事,HashTable 是线程安全的,很多方法都是 synchronized 方法,而 HashMap 不是线程安全的,但其在单线程程序中的性 能比 HashTable 要高。StringBuffer 和 StringBuilder 类的区别也是如此,他们的原理和操作基本相同,区别在于 StringBufferd 支持并发操作,线 性安全的,适 合多线程中使用。StringBuilder 不支持并发操作,线性不安全的,不适合多线程中使用。新引入的 StringBuilder 类不是线程安全的, 但其在单线程中的性能比 StringBuffer 高。
ava 编译器将"+"编译成了 StringBuilder,这样 for 语句每循环一次,又创建了一个 StringBuilder 对象。 如果将上面的代码在 JDK1.4 下编译,必须将 StringBuilder 改为 StringBuffer,而 JDK1.4 将"+"转换为 StringBuffer(因为 JDK1.4 并没有 提供 StringBuilder 类)。StringBuffer 和 StringBuilder 的功能基本一样,只是 StringBuffer 是线程安全的,而 StringBuilder 不是线程安全的。 因此,StringBuilder
答:是值传递。Java 语言的参数传递只有值传递。当一个实例对象作为参数被传递到方法中时,参数的值就是该对象的引用的一个副本。指向同 一个对象,对象的内容可以在被调用的方法内改变,但对象的引用(不是引用的副本) 是永远不会改变的。 Java 的参数传递,不管是基本数据类型还是引用类型的参数,都是按值传递,没有按引用传递!