Java工程师面试体验

沦落到这样,好吧,Java 工程师面试体验。

最后还是喜欢总结。。

北京科蓝软件系统有限公司(深圳Java工程师),才给6k。。

果断拒了。。




1.作用域


作用域       当前类   同一package   子孙类     其他package 

public        √       √             √           √ 

protected     √       √             √           × 

friendly      √       √             ×           × 

private       √       ×             ×           × 



2.  .java文件和.class的关系


每个java文件能有很多class,但是只能有一个public class,而且这个public 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.谈谈&和&&的区别


这题很阴险,如果你单纯这么说:
1.&是位运算符,表示按位与
2.&&是逻辑运算符,表示逻辑与
你就完蛋了。。
这么简单的题目,就要稍微深入讲讲你是怎么用的?
比如,&,一般用在取一个整数后四位,有个整数a,0xF & a 就是取a的后四位。
比如,&&,有短路功能,如果条件a && 条件b ,条件a不满足,那么该表达式整体为false,不用计算后面的条件b了。

 

5.java有goto吗?


这种问题最脑残了。。
goto 是 Java 中一个没有使用的关键字。如果想叫做保留字也可以。

话说,就算有,你用吗?你问这个问题想表达什么?
严重影响可读性好不好!
有个递归你怎么破?



6.如果跳出多重循环?


方法1是用循环标签:
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语句


switch(case){
case1:
xxx
case2:
xxx
default:
xxx
}
这里的case,只能是整型,也就是int,char,byte,short,后面三个是因为可以隐式转换成int。
什么long啊,string啊,别想了,不和语法。



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必然会面对unicode。

Java的字符类型采用的是UTF-16编码方式对Unicode编码表进行表示。
其中一个char类型固定2Bytes(16bits)。

所以当然可以。


11.请设计一个100亿的计算器


这道题,谁都不可能在短时间内做出来,就看是不是想得比别人多,比别人思路广,比别人更全面。
这个int型,最大是21亿,连加减都不能满足。
long型,最大是42亿,也一定会溢出的。

这必须要自己实现一个class来操作:
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是引用不能变。

final StringBuffer a=new StringBuffer(“immutable”);
执行如下语句将报告编译期错误:
a=new StringBuffer(“”);
但是,执行如下语句则可以通过编译:
a.append(” broken!”);


13."=="和equals方法究竟有什么区别


==操作符:


专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆内存),变量也占用一块内存。
例如Objet obj = new Object();变量obj是一个内存,new Object()是另一个内存,此时,变量obj所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量。
如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。


equals:


equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码:
String a=new String("foo");
String b=new String("foo");
两条new语句创建了两个对象,然后用a,b这两个变量分别指向了其中一个对象。
这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false。
而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。


14.静态变量和实例变量的区别?


在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。

在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

public class VariantTest{
 
           publicstatic int staticVar = 0;
 
           publicint instanceVar = 0;
 
           publicVariantTest(){
 
                    staticVar++;
 
                    instanceVar++;
 
                    System.out.println(“staticVar=”+ staticVar + ”,instanceVar=” + instanceVar);
           }
}


15.是否可以从一个static方法内部发出对非static方法的调用?


基本上不可以,看情况。
本质上,static方法,在对象没有实例化的时候就存在了,而非static方法,必须有实例化的对象。
如果在没有实例化对象的情况下,上面的问题是不成立的。


16.Integer与int的区别


这个其实很无奈,因为面向对象的java,有个基本数据类型int,有点不靠谱,要么就全部面向对象,多好啊。
Interger方法很多。


17.谈谈overload 和 override


overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,JVM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));


2、不能通过访问权限、返回类型、抛出的异常进行重载;


3、方法的异常类型和数目不会对重载造成影响;

override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;

4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,
通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,
这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,
因为子类可以解决父类的一些问题,不能比父类有更多的问题。
子类方法的访问权限只能比父类的更大,不能更小。
如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。


18.构造器Constructor是否可被override?


构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
 
/*新增于2014.3.31
今天被问到了构造器,但是不知道什么是构造器,两道题都没写。。。
后来一查,才发现是构造函数 - -
当然是可以被重载了。。
至于能不能被重写??
这个为什么会有这个问题呢?重写一般都是用在子类继承父类后重写某些函数!或者实现接口的某些函数!
构造器中,又不涉及到上面的两个情况,怎么可以被重写?答案是否定的!
*/


19.接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?


这里还是的谈到抽象类,在C++中,就是有纯虚函数的类。

在java中:抽象类与普通类的唯一区别就是不能创建实例对象和允许有abstract方法。

那么意味着上面的问题都是肯定的!

如果我是java设计师,我为什么不能继承?给出不能继承的理由?如果给不出,那就可以继承了。


20.写clone()方法时,通常都有一行代码,是什么?


晕,一开始看成是close(),原来是克隆。

这里涉及到了深克隆和浅克隆的问题,前者是完全一个新的对象,后者是复制了引用而已。

关于这个问题:super.clone();
因为首先要把父类中的成员复制到位,然后才是复制自己的成员。


21.谈到面向对象,你想到了什么?


封装、继承、抽象、多态。


1.封装


封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“ 高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。 把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同一个类中


例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人以后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。

一个更便于理解的例子就是,司机将火车刹住了,刹车的动作是分配给司机,还是分配给火车,显然,应该分配给火车,因为司机自身是不可能有那么大的力气将一个火车给停下来的,只有火车自己才能完成这一动作,火车需要调用内部的离合器和刹车片等多个器件协作才能完成刹车这个动作,司机刹车的过程只是给火车发了一个消息,通知火车要执行刹车动作而已。


2.继承

在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系, 提高了软件的可重用性和可扩展性


3.抽象


抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够 想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,如下:
class Person{
 
        String name;
 
        int age;
 
}



4.多态


多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在 程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

多态性增强了软件的灵活性和扩展性。

例如,下面代码中的UserDao是一个接口,它定义引用变量userDao指向的实例对象由daofactory.getDao()在执行的时候返回,
有时候指向的是UserJdbcDao这个实现,
有时候指向的是UserHibernateDao这个实现,
这样,不用修改源代码,就可以改变userDao指向的具体类实现,从而导致userDao.insertUser()方法调用的具体代码也随之改变,即有时候调用的是UserJdbcDao的insertUser方法,有时候调用的是UserHibernateDao的insertUser方法:
UserDao userDao = daofactory.getDao(); 
userDao.insertUser(user);


比喻:人吃饭,你看到的是左手,还是右手?
先实现,1.人用手吃饭;2.人用左手 和 人用右手 两种情况。



22.java中实现多态的机制是什么?


1.继承父类
2.实现接口

他们两个定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。


23.abstract class和interface有什么区别?


含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象。
含有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.一个类可以实现多个接口,但只能继承一个抽象类。


接口更多的是在系统架构设计方法发挥作用,主要用于 定义模块之间的通信契约
抽象类在代码实现方面发挥作用,可以实现 代码的重用

面试的时候,比较两个东西:
类中的构造方法
普通成员变量
方法(包括抽象方法)
静态变量
静态方法
继承性
等6个方面!


24.什么是内部类?Static Nested Class 和 Inner Class的不同。


这一题有点和前面的第3问重复了。

内部类就是在类的内部定义的类,在两个地方(包含类中和包含类的方法体中)可以定义,可以访问外部类的成员变量,不能定义静态成员,这是大的特点。

静态嵌套类,因为是静态的,不需要像内部类一样,先有外部类实例化对象a,再有这个a实例化内部类对象b。
而是直接就能实例化如:
OuterClass.StaticNestedClass a = new OuterClass.StaticNestedClass();
它倒是也能直接访问外部类的static对象 + 静态方法中的局部变量,不过该局部变量要加final修饰符。


25.内部类可以引用它的包含类的成员吗?有没有什么限制?


当然可以。
只要不是静态嵌套类,都可以的。即使是静态嵌套类,也是能访问静态变量或静态方法中的加了final修饰符的局部变量。


26.Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?


回到匿名内部类的定义:
1.没有名字,使用一次而已。
2.必须继承父类或实现接口。


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


前者固定长度。。
后者是可变。。
建议用后者。

 
/*以下内容新增于2014.3.31*/

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,多了个固定顺序(有序)。

 

 


 

 

 


 

 


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值