沦落到这样,好吧,Java 工程师面试体验。
最后还是喜欢总结。。
北京科蓝软件系统有限公司(深圳Java工程师),才给6k。。
果断拒了。。
1.作用域
作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×
2. .java文件和.class的关系
3.谈谈匿名内部类
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
实现接口:
public class Demo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
Thread t = new Thread(r);
t.start();
}
}
4.谈谈&和&&的区别
5.java有goto吗?
6.如果跳出多重循环?
public static void cycle2(){
lableA://这里就是循环的标签
for (int i = 0; i < 5; i++) {
System.out.println("I 的值是:"+i);
lableB://这里就是循环的标签
for (int j = 0; j < 4; j++) {
System.out.println("J 的值是:"+j);
for (int m = 0; m < 3; m++) {
if(m==1){
System.out.println("M 的值是:"+m+" 跳出第二层循环");
break lableB;
}
else if(m==2){
System.out.println("M 的值是:"+m+" 跳出最外层循环");
break lableA;
}
else{
System.out.println("M 的值是:"+m);
}
}
}
}
}
方法2是根据逻辑设置flag,来跳出(本人一般使用这个方法):
int arr[][] ={{1,2,3},{4,5,6,7},{9}};
boolean found =false;
for(inti=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;
}
}
}
7.谈谈switch语句
8. 谈谈java中的int,long,float,double
int:
1 2-32
符号位 整数位
long:
1 2-64
符号位 整数位
float:
1 2-9 10-32
符号位 整数位 小数位
double:
1 2-12 13-32
符号位 整数位 小数位
谈到这就要谈谈为什么int,16位的那个int,它的范围是-32768到32767?
如果单纯考虑二进制的话,因为是正数部分:+0 ~ +32767 ,然后负数部分:-32767 ~ -0
两个0,正负0,这将导致16位2进制所能表示的数比2^16 少一个。
计算机采用二进制补码来存储,所谓补码就是,正数部分:和原码一样,然后负数部分:符号位不动,其它取反+1。
因为没有任何数的原码转成补码后会变成:1000000000000000 ,所以这个数就被人为的设定为-32768。
说实话,正常二进制最小的数的确是1111111111111111,但是补码的最小数确实1000000000000000,那个本来应该最小的数,反而变成了最大的负数,-1。
所以啊,1111111111111111,不是你出身不好,是体制问题。
9.谈谈强制转换:short s1 = 1; s1 = s1+ 1;有什么错? short s1 = 1; s1 += 1;有什么错?
此题绝对是经典问题之一!
short s1 = 1; s1 = s1+ 1;
因为s1 + 1的结果是int型,赋值给short型,报错。
short s1 = 1; s1 += 1;
因为+=是java自定义的运算符,java经过特殊处理了,正常通过。
10.谈谈unicode:char型变量中能不能存贮一个中文汉字?为什么?
Java的字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。
其中一个char类型固定2Bytes(16bits)。
所以当然可以。
11.请设计一个100亿的计算器
public classBigInteger{
int sign;
byte[] val;
public Biginteger(String val) {
sign = ;
val = ;
}
public BigInteger add(BigIntegerother) {
}
public BigInteger subtract(BigIntegerother) {
}
public BigInteger multiply(BigIntegerother){
}
public BigInteger divide(BigIntegerother){
}
}
12.final关键字修饰一个变量时,是引用不能变,还是引用指向的对象不能变?
final StringBuffer a=new StringBuffer(“immutable”);
执行如下语句将报告编译期错误:
a=new StringBuffer(“”);
但是,执行如下语句则可以通过编译:
a.append(” broken!”);
13."=="和equals方法究竟有什么区别
==操作符:
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存。
例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量。
如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
equals:
String b=new String("foo");
两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象。
这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false。
而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。
14.静态变量和实例变量的区别?
public class VariantTest{
publicstatic int staticVar = 0;
publicint instanceVar = 0;
publicVariantTest(){
staticVar++;
instanceVar++;
System.out.println(“staticVar=”+ staticVar + ”,instanceVar=” + instanceVar);
}
}
15.是否可以从一个static方法内部发出对非static方法的调用?
16.Integer与int的区别
17.谈谈overload 和 override
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,
通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,
这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,
因为子类可以解决父类的一些问题,不能比父类有更多的问题。
子类方法的访问权限只能比父类的更大,不能更小。
如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
18.构造器Constructor是否可被override?
19.接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?
20.写clone()方法时,通常都有一行代码,是什么?
21.谈到面向对象,你想到了什么?
1.封装
例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人以后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。
2.继承
3.抽象
class Person{
String name;
int age;
}
4.多态
UserDao userDao = daofactory.getDao();
userDao.insertUser(user);
比喻:人吃饭,你看到的是左手,还是右手?
22.java中实现多态的机制是什么?
23.abstract class和interface有什么区别?
含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。
abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。
如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。
接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7.一个类可以实现多个接口,但只能继承一个抽象类。
类中的构造方法
普通成员变量
方法(包括抽象方法)
静态变量
静态方法
继承性
24.什么是内部类?Static Nested Class 和 Inner Class的不同。
OuterClass.StaticNestedClass a = new OuterClass.StaticNestedClass();
它倒是也能直接访问外部类的static对象 + 静态方法中的局部变量,不过该局部变量要加final修饰符。
25.内部类可以引用它的包含类的成员吗?有没有什么限制?
26.Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
27. super.getClass() 的结果?
import java.util.Date;
public class Test extends Date{
public static void main(String[] args) {
new Test().test();
}
public void test(){
System.out.println(super.getClass().getName());
}
}
因为getClass()被修饰成final,所以子类不能覆盖,所以test()中调用的getClass()其实就是super.getClass()。
getClass().getSuperClass().getName();
28.String 和 StringBuffer
29. hashmap详解
虽然 HashMap 和 HashSet 实现的接口规范不同,但它们底层的 Hash 存储机制完全一样。
甚至 HashSet 本身就采用 HashMap 来实现的。
存储:
HashMap<String , Double> map = new HashMap<String , Double>();
map.put("语文" , 80.0);
map.put("数学" , 89.0);
map.put("英语" , 78.2);
底层;
系统将调用"语文"的 hashCode() 方法得到其 hashCode 值——每个 Java 对象都有 hashCode() 方法。
都可通过该方法获得它的 hashCode 值。
得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置
public V put(K key, V value)
{
// 如果 key 为 null,调用 putForNullKey 方法进行处理
if (key == null)
return putForNullKey(value);
// 根据 key 的 keyCode 计算 Hash 值
int hash = hash(key.hashCode());
// 搜索指定 hash 值在对应 table 中的索引
int i = indexFor(hash, table.length);
// 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素
for (Entry<K,V> e = table[i]; e != null; e = e.next)
{
Object k;
// 找到指定 key 与需要放入的 key 相等(hash 值相同
// 通过 equals 比较放回 true)
if (e.hash == hash && ((k = e.key) == key
|| key.equals(k)))
{
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry
modCount++;
// 将 key、value 添加到 i 索引处
addEntry(hash, key, value, i);
return null;
}
hashmap就是集合了数组和链表的优点:能索引快速定位和保证插入效率。
遍历1(因效率高被推荐):
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
遍历2(底层遍历了两次):
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
30. java有关时间的类
java.util.Date
java.util.Calendar
31. java的finalize
手工对象销毁!毕竟GC只在三种情况自动调用:内存不足,线程空闲,对象没人引用了。。。
有些时候要自己手工销毁。。就用finalize它了。
对比下finally,是try catch 的最后必须执行的。。
对比下final,是const指针,指针不可变,指针指向内容可以变。
32. java 读写文件
读文件(FileInputStream对象打开文件,然后BufferedReader包装它):
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
String data = null;
while((data = br.readLine())!=null){
System.out.println(data);
}
写文件0(无包装):
FileWriter fw = new FileWriter("hello.txt");
String s = "hello world";
fw.write(s,0,s.length());
fw.flush();
写文件1(FileOutputStream + OutputStreamWriter包装):
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hello2.txt"));
osw.write(s,0,s.length());
osw.flush();
写文件2(FileOutputStream + PrintWriter包装):
PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("hello3.txt")),true);
pw.println(s);
33.java 字符流和字节流
看看Writer的继承:
java.lang.Object
java.io.Writer
java.io.OutputStreamWriter
java.io.FileWriter
字符流 用到了 缓冲区,然后再写入,效率更高(IO操作更少。。)
字节流 直接读写文件,IO操作次数多,效率稍微低。。
带有Reader 和 Writer字样的都是字符流!!!
一般都用字符流,效率更高。比如32的写文件1,2(就是先包装再读写)。
随机读写?
java.lang.Object
java.io.RandomAccessFile
这个用在大文件或者分块文件的定位中。。
看继承就知道他的实现和别的不一样。。。独立出来。。
private void createFile(String filePath)throws IOException
{
File newFile=new File(filePath);
RandomAccessFile raf=new RandomAccessFile(newFile,"rw");
raf.setLength(1024*1024);
raf.close();
}
private void writeIntoFIle(String filePath,byte[] bytes,int realLength,int finishedFileSize) throws IOException
{
File newFile=new File(filePath);
RandomAccessFile raf=new RandomAccessFile(newFIle,"rw");
raf.seek(finishedFileSize);
raf.write(bytes,0,realLength);
raf.close();
}
34. hashmap 、vector、arraylist 哪个是线程不安全的?
hashmap是不安全的!
查看HashMap的源码,内部有一个modCount变量,在put、remove、等等进行结构性修改时改变这个值。
应该是为了效率,加锁影响效率。。
vector:安全!
vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
arraylist:不安全!
因为它就比vector少了个同步化机制。
hashtable:安全!
因为它就比hashmap多了一个同步化机制,效率稍微低下。
它还比hashmap多了个限制:不能加空值。
treemap:不安全!
它相对于hashmap,多了个固定顺序(有序)。