think in java interview-高级开发人员面试宝典(二)

Java-Interview-超全集合github上评分最高的jiva面试题 立即下载

从现在开始,以样题的方式一一列出各种面试题以及点评,考虑到我在前文中说的,对于一些大型的外资型公司,你将会面临全程英语面试,因此我在文章中也会出现许多全英语样题。

这些题目来自于各个真实的公司,公司名我就不一一例举了,是本人一直以来苦心收藏的。

一个JAVA 的MAIN方法引发的一场血案


Q:    What if the main method is declared as private?

A:     The program compiles properly but at run time it will give "Main method not public." message.


Q: What if the static modifier is removed from the signature of the main method?

A:  Program compiles. But at run time throws an error "NoSuchMethodError".

Q: What if I write static public void instead of public static void?

A:  Program compiles and runs properly.


Q: What if I do not provide the String array as the argument to the method?

A:  Program compiles but throws a run time error "NoSuchMethodError".


Q: What is the first argument of the String array in main method?

A:  The String array is empty. It does not have any element. This is unlike C/C++(读作plus plus) where the first element by default is the program name.


Q: If I do not provide any arguments on the command line, then the String array of Main method will be empty or null?

A:  It is empty. But not null.


Q: How can one prove that the array is notnull but empty using one line of code?

A:  Print args.length. It will print 0. That means it is empty. But if it would have been null then it would have thrown a NullPointerException on attempting to print args.length.


仔细看完后有人直接吐血了,拿个eclipse,这几个问题全部模拟一边就可以了,即无算法也不需要死记硬背


有人会说了,唉,我怎么写了5年的JAVA怎么就没记得多写多看,多想想这个public static void main(String[] args)方法呢?唉。。。


再来!!!


hashcode & equals之5重天

何时需要重写equals()

当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。


如何覆写equals()和hashcode


覆写equals方法

1  使用instanceof操作符检查“实参是否为正确的类型”。

2  对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。

3. 对于非float和double类型的原语类型域,使用==比较;

4  对于对象引用域,递归调用equals方法;

5  对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;

6  对于double域,使用Double.doubleToLongBits(adouble)转换为int,再使用==比较;

7  对于数组域,调用Arrays.equals方法。

覆写hashcode

1. 把某个非零常数值,例如17,保存在int变量result中;

2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域):

3, boolean型,计算(f? 0 : 1);

4. byte,char,short型,计算(int);

5. long型,计算(int)(f ^ (f>>>32));

6. float型,计算Float.floatToIntBits(afloat);

7. double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];

8. 对象引用,递归调用它的hashCode方法;

9. 数组域,对其中每个元素调用它的hashCode方法。

10. 将上面计算得到的散列码保存到int变量c,然后执行result=37*result+c;

11. 返回result。


举个例子:

  1. public class MyUnit{  
  2.     private short ashort;  
  3.     private char achar;  
  4.     private byte abyte;  
  5.     private boolean abool;  
  6.     private long along;  
  7.     private float afloat;  
  8.     private double adouble;  
  9.     private Unit aObject;  
  10.     private int[] ints;  
  11.     private Unit[] units;  
  12.    
  13.     public boolean equals(Object o) {  
  14.        if (!(o instanceof Unit))  
  15.            return false;  
  16.        Unit unit = (Unit) o;  
  17.        return unit.ashort == ashort  
  18.               && unit.achar == achar  
  19.               && unit.abyte == abyte  
  20.               && unit.abool == abool  
  21.               && unit.along == along  
  22.               && Float.floatToIntBits(unit.afloat) == Float  
  23.                      .floatToIntBits(afloat)  
  24.               && Double.doubleToLongBits(unit.adouble) == Double  
  25.                      .doubleToLongBits(adouble)  
  26.               && unit.aObject.equals(aObject)   
  27.               && equalsInts(unit.ints)  
  28.               && equalsUnits(unit.units);  
  29.     }  
  30.    
  31.     private boolean equalsInts(int[] aints) {  
  32.        return Arrays.equals(ints, aints);  
  33.     }  
  34.    
  35.     private boolean equalsUnits(Unit[] aUnits) {  
  36.        return Arrays.equals(units, aUnits);  
  37.     }  
  38.    
  39.     public int hashCode() {  
  40.        int result = 17;  
  41.        result = 31 * result + (int) ashort;  
  42.        result = 31 * result + (int) achar;  
  43.        result = 31 * result + (int) abyte;  
  44.        result = 31 * result + (abool ? 0 : 1);  
  45.        result = 31 * result + (int) (along ^ (along >>> 32));  
  46.        result = 31 * result + Float.floatToIntBits(afloat);  
  47.        long tolong = Double.doubleToLongBits(adouble);  
  48.        result = 31 * result + (int) (tolong ^ (tolong >>> 32));  
  49.        result = 31 * result + aObject.hashCode();  
  50.        result = 31 * result + intsHashCode(ints);  
  51.        result = 31 * result + unitsHashCode(units);  
  52.        return result;  
  53.     }  
  54.    
  55.     private int intsHashCode(int[] aints) {  
  56.        int result = 17;  
  57.        for (int i = 0; i < aints.length; i++)  
  58.            result = 31 * result + aints[i];  
  59.        return result;  
  60.     }  
  61.    
  62.     private int unitsHashCode(Unit[] aUnits) {  
  63.        int result = 17;  
  64.        for (int i = 0; i < aUnits.length; i++)  
  65.            result = 31 * result + aUnits[i].hashCode();  
  66.        return result;  
  67.     }  
  68. }  
public class MyUnit{
    private short ashort;
    private char achar;
    private byte abyte;
    private boolean abool;
    private long along;
    private float afloat;
    private double adouble;
    private Unit aObject;
    private int[] ints;
    private Unit[] units;
 
    public boolean equals(Object o) {
       if (!(o instanceof Unit))
           return false;
       Unit unit = (Unit) o;
       return unit.ashort == ashort
              && unit.achar == achar
              && unit.abyte == abyte
              && unit.abool == abool
              && unit.along == along
              && Float.floatToIntBits(unit.afloat) == Float
                     .floatToIntBits(afloat)
              && Double.doubleToLongBits(unit.adouble) == Double
                     .doubleToLongBits(adouble)
              && unit.aObject.equals(aObject) 
              && equalsInts(unit.ints)
              && equalsUnits(unit.units);
    }
 
    private boolean equalsInts(int[] aints) {
       return Arrays.equals(ints, aints);
    }
 
    private boolean equalsUnits(Unit[] aUnits) {
       return Arrays.equals(units, aUnits);
    }
 
    public int hashCode() {
       int result = 17;
       result = 31 * result + (int) ashort;
       result = 31 * result + (int) achar;
       result = 31 * result + (int) abyte;
       result = 31 * result + (abool ? 0 : 1);
       result = 31 * result + (int) (along ^ (along >>> 32));
       result = 31 * result + Float.floatToIntBits(afloat);
       long tolong = Double.doubleToLongBits(adouble);
       result = 31 * result + (int) (tolong ^ (tolong >>> 32));
       result = 31 * result + aObject.hashCode();
       result = 31 * result + intsHashCode(ints);
       result = 31 * result + unitsHashCode(units);
       return result;
    }
 
    private int intsHashCode(int[] aints) {
       int result = 17;
       for (int i = 0; i < aints.length; i++)
           result = 31 * result + aints[i];
       return result;
    }
 
    private int unitsHashCode(Unit[] aUnits) {
       int result = 17;
       for (int i = 0; i < aUnits.length; i++)
           result = 31 * result + aUnits[i].hashCode();
       return result;
    }
}


当改写equals()的时候,总是要改写hashCode()

根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。


两个对象如果equals那么这两个对象的hashcode一定相等,如果两个对象的hashcode相等那么这两个对象是否一定equals?

回答是不一定,这要看这两个对象有没有重写Object的hashCode方法和equals方法。如果没有重写,是按Object默认的方式去处理。

试想我有一个桶,这个桶就是hashcode,桶里装的是西瓜我们认为西瓜就是object,有的桶是一个桶装一个西瓜,有的桶是一个桶装多个西瓜。

比如String重写了Object的hashcode和equals,但是两个String如果hashcode相等,那么equals比较肯定是相等的,但是“==”比较却不一定相等。如果自定义的对象重写了hashCode方法,有可能hashcode相等,equals却不一定相等,“==”比较也不一定相等。

此处考的是你对object的hashcode的意义的真正的理解!!!如果作为一名高级开发人员或者是架构师,必须是要有这个概念的,否则,直接ban掉了。

为什么我们在定义hashcode时如: h = 31*h + val[off++];  要使用31这个数呢?
public int hashCode() { 
    int h = hash; 
        int len = count; 
    if (h == 0 && len > 0) { 
        int off = offset; 
        char val[] = value; 
        for (int i = 0; i < len; i++) { 
           h = 31*h + val[off++]; 
        } 
        hash = h; 
    } 
    return h; 
} 

来看一段hashcode的覆写案例:

其实上面的实现也可以总结成数数里面下面这样的公式:

s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

我们来看这个要命的31这个系数为什么总是在里面乘啊乘的?为什么不适用32或者其他数字?

大家都知道,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31原因是因为31是一个素数!

所谓素数:

质数又称素数

素数在使用的时候有一个作用就是如果我用一个数字来乘以这个素数,那么最终的出来的结果只能被素数本身和被乘数还有1来整除!如:我们选择素数3来做系数,那么3*n只能被3和n或者1来整除,我们可以很容易的通过3n来计算出这个n来。这应该也是一个原因!

在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”。

31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多,对左移现在很多虚拟机里面都有做相关优化,并且31只占用5bits!

hashcode & equals基本问到第三问,很多人就已经挂了,如果问到了为什么要使用31比较好呢,90%的人无法回答或者只回答出一半。

此处考的是编程者在平时开发时是否经常考虑“性能”这个问题。

 

comparable接口与comparator

两种比较接口分析


前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。


一个类实现了 Camparable 接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用 Sort 方法排序了。


而 Comparator 的作用有两个:
1. 如果类的设计师没有考虑到 Compare 的问题而没有实现 Comparable 接口,可以通过 Comparator 来实现比较算法进行排序;
2. 为了使用不同的排序标准做准备,比如:升序、降序或其他什么序。

在 “集合框架” 中有两种比较接口: Comparable 接口和 Comparator 接口。 

Comparable 是通用的接口,用户可以实现它来完成自己特定的比较,而 Comparator 可以看成一种算法的实现,在需要容器集合实现比较功能的时候,来指定这个比较器,这可以看成一种设计模式,将算法和数据分离。

来看样例:

PersonBean类

  1. <span style="font-size: 12px;">public class PersonBean implements Comparable<PersonBean> {  
  2.     public PersonBean(int age, String name) {  
  3.         this.age = age;  
  4.         this.name = name;  
  5.     }  
  6.   
  7.     int age = 0;  
  8.     String name = "";  
  9.   
  10.     public int getAge() {  
  11.         return age;  
  12.     }  
  13.   
  14.     public void setAge(int age) {  
  15.         this.age = age;  
  16.     }  
  17.   
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.   
  22.     public void setName(String name) {  
  23.         this.name = name;  
  24.     }  
  25.   
  26.     public boolean equals(Object o) {  
  27.         if (!(o instanceof PersonBean)) {  
  28.             return false;  
  29.         }  
  30.         PersonBean p = (PersonBean) o;  
  31.         return (age == p.age) && (name.equals(p.name));  
  32.     }  
  33.   
  34.     public int hashCode() {  
  35.         int result = 17;  
  36.         result = 31 * result + age;  
  37.         result = 31 * result + name.hashCode();  
  38.         return result;  
  39.   
  40.     }  
  41.   
  42.     public String toString() {  
  43.         return (age + "{" + name + "}");  
  44.     }  
  45.   
  46.     public int compareTo(PersonBean person) {  
  47.         int cop = age - person.getAge();  
  48.         if (cop != 0)  
  49.             return cop;  
  50.         else  
  51.             return name.compareTo(person.name);  
  52.     }  
  53. }  
  54. </span>  
public class PersonBean implements Comparable<PersonBean> {
	public PersonBean(int age, String name) {
		this.age = age;
		this.name = name;
	}

	int age = 0;
	String name = "";

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean equals(Object o) {
		if (!(o instanceof PersonBean)) {
			return false;
		}
		PersonBean p = (PersonBean) o;
		return (age == p.age) && (name.equals(p.name));
	}

	public int hashCode() {
		int result = 17;
		result = 31 * result + age;
		result = 31 * result + name.hashCode();
		return result;

	}

	public String toString() {
		return (age + "{" + name + "}");
	}

	public int compareTo(PersonBean person) {
		int cop = age - person.getAge();
		if (cop != 0)
			return cop;
		else
			return name.compareTo(person.name);
	}
}
AlphDesc类

  1. <span style="font-size: 12px;">import java.util.Comparator;  
  2.   
  3. public class AlphDesc implements Comparator<PersonBean> {  
  4.   
  5.     public int compare(PersonBean personA, PersonBean personB) {  
  6.         int cop = personA.age - personB.age;  
  7.         if (cop != 0)  
  8.             return cop;  
  9.         else  
  10.             return personB.getName().compareTo(personA.getName());  
  11.   
  12.     }  
  13.   
  14. }  
  15. </span>  
import java.util.Comparator;

public class AlphDesc implements Comparator<PersonBean> {

	public int compare(PersonBean personA, PersonBean personB) {
		int cop = personA.age - personB.age;
		if (cop != 0)
			return cop;
		else
			return personB.getName().compareTo(personA.getName());

	}

}

TestComparable类

  1. <span style="font-size: 12px;">import java.util.*;  
  2.   
  3. public class TestComparable {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public void compare() {  
  9.         PersonBean[] p = { new PersonBean(20, "Tom"),  
  10.                 new PersonBean(20, "Jeff"),   
  11.                 new PersonBean(30, "Mary"),  
  12.                 new PersonBean(20, "Ada"),   
  13.                 new PersonBean(40, "Walton"),  
  14.                 new PersonBean(61, "Peter"),   
  15.                 new PersonBean(20, "Bush") };  
  16.         System.out.println("before sort:\n" + Arrays.toString(p));  
  17.         AlphDesc desc = new AlphDesc();  
  18.         Arrays.sort(p,desc);  
  19.         System.out.println("after sort:\n" + Arrays.toString(p));  
  20.     }  
  21.   
  22.     public static void main(String[] args) {  
  23.         TestComparable tc = new TestComparable();  
  24.         tc.compare();  
  25.     }  
  26.   
  27. }</span>  
import java.util.*;

public class TestComparable {

	/**
	 * @param args
	 */
	public void compare() {
		PersonBean[] p = { new PersonBean(20, "Tom"),
				new PersonBean(20, "Jeff"), 
				new PersonBean(30, "Mary"),
				new PersonBean(20, "Ada"), 
				new PersonBean(40, "Walton"),
				new PersonBean(61, "Peter"), 
				new PersonBean(20, "Bush") };
		System.out.println("before sort:\n" + Arrays.toString(p));
		AlphDesc desc = new AlphDesc();
		Arrays.sort(p,desc);
		System.out.println("after sort:\n" + Arrays.toString(p));
	}

	public static void main(String[] args) {
		TestComparable tc = new TestComparable();
		tc.compare();
	}

}

 

java实现shallow clone(浅克隆)与深克隆(deep clone)

克隆就是复制一个对象的复本.但一个对象中可能有基本数据类型,如:int,long,float    等,也同时含有非基本数据类型如(数组,集合等)被克隆得到的对象基本类型的值修改了,原对象的值不会改变.这种适合shadow clone(浅克隆).
但如果你要改变一个非基本类型的值时,原对象的值却改变了,.比如一个数组,内存中只copy他的地址,而这个地址指向的值并没有 copy,当clone时,两个地址指向了一个值,这样一旦这个值改变了,原来的值当然也变了,因为他们共用一个值.,这就必须得用深克隆(deep clone)
以下举个例子,说明以上情况.
被克隆类:ShadowClone.java

  1. <span style="font-size: 12px;">public class ShadowClone implements Cloneable  
  2. {  
  3.     // 基本类型  
  4.     private int a;  
  5.     // 非基本类型  
  6.     private String b;  
  7.     // 非基本类型  
  8.     private int[] c;  
  9.     // 重写Object.clone()方法,并把protected改为public  
  10.     @Override  
  11.     public Object clone()  
  12.     {  
  13.         ShadowClone sc = null;  
  14.         try  
  15.         {  
  16.             sc = (ShadowClone) super.clone();  
  17.         } catch (CloneNotSupportedException e)  
  18.         {  
  19.             e.printStackTrace();  
  20.         }  
  21.         return sc;  
  22.     }  
  23.     public int getA()  
  24.     {  
  25.         return a;  
  26.     }  
  27.     public void setA(int a)  
  28.     {  
  29.         this.a = a;  
  30.     }  
  31.     public String getB()  
  32.     {  
  33.         return b;  
  34.     }  
  35.     public void setB(String b)  
  36.     {  
  37.         this.b = b;  
  38.     }  
  39.     public int[] getC()  
  40.     {  
  41.         return c;  
  42.     }  
  43.     public void setC(int[] c)  
  44.     {  
  45.         this.c = c;  
  46.     }  
  47. }</span>  
public class ShadowClone implements Cloneable
{
    // 基本类型
    private int a;
    // 非基本类型
    private String b;
    // 非基本类型
    private int[] c;
    // 重写Object.clone()方法,并把protected改为public
    @Override
    public Object clone()
    {
        ShadowClone sc = null;
        try
        {
            sc = (ShadowClone) super.clone();
        } catch (CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
        return sc;
    }
    public int getA()
    {
        return a;
    }
    public void setA(int a)
    {
        this.a = a;
    }
    public String getB()
    {
        return b;
    }
    public void setB(String b)
    {
        this.b = b;
    }
    public int[] getC()
    {
        return c;
    }
    public void setC(int[] c)
    {
        this.c = c;
    }
}
测试类Test.java
  1. <span style="font-size: 12px;">public class Test  
  2. {  
  3.     public static void main(String[] args) throws CloneNotSupportedException  
  4.     {  
  5.         ShadowClone c1 = new ShadowClone();  
  6.         //对c1赋值  
  7.         c1.setA(100) ;  
  8.         c1.setB("clone1") ;  
  9.         c1.setC(new int[]{1000}) ;  
  10.           
  11.         System.out.println("克隆前: c1.a="+c1.getA() );  
  12.         System.out.println("克隆前: c1.b="+c1.getB() );  
  13.         System.out.println("克隆前: c1.c[0]="+c1.getC()[0]);  
  14.         System.out.println("-----------") ;  
  15.           
  16.         //克隆出对象c2,并对c2的属性A,B,C进行修改  
  17.           
  18.         ShadowClone c2 = (ShadowClone) c1.clone();  
  19.           
  20.         //对c2进行修改  
  21.         c2.setA(50) ;  
  22.         c2.setB("clone2");  
  23.         int []a = c2.getC() ;  
  24.         a[0]=500 ;  
  25.         c2.setC(a);  
  26.           
  27.         System.out.println("克隆后: c1.a="+c1.getA() );  
  28.         System.out.println("克隆后: c1.b="+c1.getB() );  
  29.         System.out.println("克隆后: c1.c[0]="+c1.getC()[0]);  
  30.         System.out.println("---------------") ;  
  31.           
  32.         System.out.println("克隆后: c2.a=" + c2.getA());  
  33.         System.out.println("克隆后: c2.b=" + c2.getB());  
  34.         System.out.println("克隆后: c2.c[0]=" + c2.getC()[0]);  
  35.     }  
  36. }</span>  
public class Test
{
    public static void main(String[] args) throws CloneNotSupportedException
    {
        ShadowClone c1 = new ShadowClone();
        //对c1赋值
        c1.setA(100) ;
        c1.setB("clone1") ;
        c1.setC(new int[]{1000}) ;
        
        System.out.println("克隆前: c1.a="+c1.getA() );
        System.out.println("克隆前: c1.b="+c1.getB() );
        System.out.println("克隆前: c1.c[0]="+c1.getC()[0]);
        System.out.println("-----------") ;
        
        //克隆出对象c2,并对c2的属性A,B,C进行修改
        
        ShadowClone c2 = (ShadowClone) c1.clone();
        
        //对c2进行修改
        c2.setA(50) ;
        c2.setB("clone2");
        int []a = c2.getC() ;
        a[0]=500 ;
        c2.setC(a);
        
        System.out.println("克隆后: c1.a="+c1.getA() );
        System.out.println("克隆后: c1.b="+c1.getB() );
        System.out.println("克隆后: c1.c[0]="+c1.getC()[0]);
        System.out.println("---------------") ;
        
        System.out.println("克隆后: c2.a=" + c2.getA());
        System.out.println("克隆后: c2.b=" + c2.getB());
        System.out.println("克隆后: c2.c[0]=" + c2.getC()[0]);
    }
}

结果:
克隆前: c1.a=100
克隆前: c1.b=clone1
克隆前: c1.c[0]=1000
-----------
克隆后: c1.a=100
克隆后: c1.b=clone1
克隆后: c1.c[0]=500
---------------
克隆后: c2.a=50
克隆后: c2.b=clone2
克隆后: c2.c[0]=500
问题出现了,我指修改了克隆后的对象c2.c的值,但c1.c的值也改变了,与c2的值相等.
以下针对浅克隆得出结论:基本类型是可以被克隆的,但引用类型只是copy地址,并没有copy这个地址指向的对象的值,这使得两个地址指向同一值,修改其中一个,当然另一个也就变了.
由此可见,浅克隆只适合克隆基本类型,对于引用类型就不能实现克隆了.

那如何实现克隆引用对象呢,以下提供一种方法.    用序列化与反序列化实现深克隆(deep copy)

被克隆对象.DeepClone.java

  1. <span style="font-size: 12px;">import java.io.Serializable;  
  2. //要实现深克隆必须实现Serializable接口  
  3. public class DeepClone implements Serializable  
  4. {  
  5.     private int a;  
  6.     private String b;  
  7.     private int[] c;  
  8.     public int getA()  
  9.     {  
  10.         return a;  
  11.     }  
  12.     public void setA(int a)  
  13.     {  
  14.         this.a = a;  
  15.     }  
  16.     public String getB()  
  17.     {  
  18.         return b;  
  19.     }  
  20.     public void setB(String b)  
  21.     {  
  22.         this.b = b;  
  23.     }  
  24.     public int[] getC()  
  25.     {  
  26.         return c;  
  27.     }  
  28.     public void setC(int[] c)  
  29.     {  
  30.         this.c = c;  
  31.     }  
  32. }</span>  
import java.io.Serializable;
//要实现深克隆必须实现Serializable接口
public class DeepClone implements Serializable
{
    private int a;
    private String b;
    private int[] c;
    public int getA()
    {
        return a;
    }
    public void setA(int a)
    {
        this.a = a;
    }
    public String getB()
    {
        return b;
    }
    public void setB(String b)
    {
        this.b = b;
    }
    public int[] getC()
    {
        return c;
    }
    public void setC(int[] c)
    {
        this.c = c;
    }
}

测试类Test.java

  1. <span style="font-size: 12px;">import java.io.ByteArrayInputStream;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.ObjectInputStream;  
  5. import java.io.ObjectOutputStream;  
  6. public class Test  
  7. {  
  8.     public static void main(String[] args) throws CloneNotSupportedException  
  9.     {  
  10.         Test t = new Test();  
  11.         DeepClone dc1 = new DeepClone();  
  12.         // 对dc1赋值  
  13.         dc1.setA(100);  
  14.         dc1.setB("clone1");  
  15.         dc1.setC(new int[] { 1000 });  
  16.         System.out.println("克隆前: dc1.a=" + dc1.getA());  
  17.         System.out.println("克隆前: dc1.b=" + dc1.getB());  
  18.         System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]);  
  19.         System.out.println("-----------");  
  20.         DeepClone dc2 = (DeepClone) t.deepClone(dc1);  
  21.         // 对c2进行修改  
  22.         dc2.setA(50);  
  23.         dc2.setB("clone2");  
  24.         int[] a = dc2.getC();  
  25.         a[0] = 500;  
  26.         dc2.setC(a);  
  27.         System.out.println("克隆前: dc1.a=" + dc1.getA());  
  28.         System.out.println("克隆前: dc1.b=" + dc1.getB());  
  29.         System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]);  
  30.         System.out.println("-----------");  
  31.         System.out.println("克隆后: dc2.a=" + dc2.getA());  
  32.         System.out.println("克隆后: dc2.b=" + dc2.getB());  
  33.         System.out.println("克隆后: dc2.c[0]=" + dc2.getC()[0]);  
  34.     }  
  35.     // 用序列化与反序列化实现深克隆  
  36.     public Object deepClone(Object src)  
  37.     {  
  38.         Object o = null;  
  39.         try  
  40.         {  
  41.             if (src != null)  
  42.             {  
  43.                 ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  44.                 ObjectOutputStream oos = new ObjectOutputStream(baos);  
  45.                 oos.writeObject(src);  
  46.                 oos.close();  
  47.                 ByteArrayInputStream bais = new ByteArrayInputStream(baos  
  48.                         .toByteArray());  
  49.                 ObjectInputStream ois = new ObjectInputStream(bais);  
  50.                 o = ois.readObject();  
  51.                 ois.close();  
  52.             }  
  53.         } catch (IOException e)  
  54.         {  
  55.             e.printStackTrace();  
  56.         } catch (ClassNotFoundException e)  
  57.         {  
  58.             e.printStackTrace();  
  59.         }  
  60.         return o;  
  61.     }  
  62. }</span>  
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Test
{
    public static void main(String[] args) throws CloneNotSupportedException
    {
        Test t = new Test();
        DeepClone dc1 = new DeepClone();
        // 对dc1赋值
        dc1.setA(100);
        dc1.setB("clone1");
        dc1.setC(new int[] { 1000 });
        System.out.println("克隆前: dc1.a=" + dc1.getA());
        System.out.println("克隆前: dc1.b=" + dc1.getB());
        System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]);
        System.out.println("-----------");
        DeepClone dc2 = (DeepClone) t.deepClone(dc1);
        // 对c2进行修改
        dc2.setA(50);
        dc2.setB("clone2");
        int[] a = dc2.getC();
        a[0] = 500;
        dc2.setC(a);
        System.out.println("克隆前: dc1.a=" + dc1.getA());
        System.out.println("克隆前: dc1.b=" + dc1.getB());
        System.out.println("克隆前: dc1.c[0]=" + dc1.getC()[0]);
        System.out.println("-----------");
        System.out.println("克隆后: dc2.a=" + dc2.getA());
        System.out.println("克隆后: dc2.b=" + dc2.getB());
        System.out.println("克隆后: dc2.c[0]=" + dc2.getC()[0]);
    }
    // 用序列化与反序列化实现深克隆
    public Object deepClone(Object src)
    {
        Object o = null;
        try
        {
            if (src != null)
            {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(src);
                oos.close();
                ByteArrayInputStream bais = new ByteArrayInputStream(baos
                        .toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bais);
                o = ois.readObject();
                ois.close();
            }
        } catch (IOException e)
        {
            e.printStackTrace();
        } catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return o;
    }
}
结果:
克隆前: dc1.a=100
克隆前: dc1.b=clone1
克隆前: dc1.c[0]=1000
-----------
克隆前: dc1.a=100
克隆前: dc1.b=clone1
克隆前: dc1.c[0]=1000
-----------
克隆后: dc2.a=50
克隆后: dc2.b=clone2
克隆后: dc2.c[0]=500
深克隆后:修改dc1或者dc2,无论是基本类型还是引用类型,他们的值都不会随着一方改变另一方也改变.

总结:

当克隆的对象只有基本类型,不含引用类型时,可以用浅克隆实现.     

当克隆的对象含有引用类型时,必须使用深克隆实现.

谈谈final, finally, finalize的区别

final修饰符(关键字)

如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载finally?再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。 

finalize方法名

Java 技术允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。


Java对象的强、软、弱和虚引用

 

强引用

  1. <span style="font-size: 12px;">Object o=new Object();     
  2. Object o1=o;  </span>  
Object o=new Object();   
Object o1=o;  

上面代码中第一句是在heap堆中创建新的Object对象通过o引用这个对象,第二句是通过o建立o1到new Object()这个heap堆中的对象的引用,这两个引用都是强引用.只要存在对heap中对象的引用,gc就不会收集该对象.如果通过如下代码:
  1. <span style="font-size: 12px;">o=null;     
  2. o1=null;</span>  
o=null;   
o1=null;

如果显式地设置o和o1为null,或超出范围,则gc认为该对象不存在引用,这时就可以收集它了。可以收集并不等于就一会被收集,什么时候收集这要取 决于gc的算法,这要就带来很多不确定性。例如你就想指定一个对象,希望下次gc运行时把它收集了,那就没办法了,有了其他的三种引用就可以做到了。其他 三种引用在不妨碍gc收集的情况下,可以做简单的交互。

heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定。如下: 
  1. <span style="font-size: 12px;">String abc=new String("abc");  //1     
  2. SoftReference<String> abcSoftRef=new SoftReference<String>(abc);  //2     
  3. WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3     
  4. abc=null; //4     
  5. abcSoftRef.clear();//5</span>  
String abc=new String("abc");  //1   
SoftReference<String> abcSoftRef=new SoftReference<String>(abc);  //2   
WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3   
abc=null; //4   
abcSoftRef.clear();//5

第一行在heap对中创建内容为“abc”的对象,并建立abc到该对象的强引用,该对象是强可及的。

第二行和第三行分别建立对heap中对象的软引用和弱引用,此时heap中的对象仍是强可及的。

第四行之后heap中对象不再是强可及的,变成软可及的。同样第五行执行之后变成弱可及的。

SoftReference(软引用)


软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避 免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用是执行以下过程,以上面的abc SoftRef为例:

1、首先将abcSoftRef的referent设置为null,不再引用heap中的new String("abc")对象。

2、将heap中的new String("abc")对象设置为可结束的(finalizable)。

3、当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, abcSoftRef被添加到它的ReferenceQueue中。

注:对ReferenceQueue软引用和弱引用可以有可无,但是虚引用必须有,参见:

  1. <span style="font-size: 12px;">Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)  </span>  
Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)  

被 Soft Reference 指到的对象,即使没有任何 Direct Reference,也不会被清除。

一直要到 JVM 内存不足且 没有 Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。

如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。我觉得 Soft Reference 也适合拿来实作 pooling 的技巧。

  1. <span style="font-size: 12px;">A obj = new A();  
  2. SoftRefenrence sr = new SoftReference(obj);  
  3.   
  4. //引用时  
  5. if(sr!=null){  
  6.     obj = sr.get();  
  7. }else{  
  8.     obj = new A();  
  9.     sr = new SoftReference(obj);  
  10. }</span>  
A obj = new A();
SoftRefenrence sr = new SoftReference(obj);

//引用时
if(sr!=null){
    obj = sr.get();
}else{
    obj = new A();
    sr = new SoftReference(obj);
}

弱引用


当gc碰到弱可及对象,并释放abcWeakRef的引用,收集该对象。但是gc可能需要对此运用才能找到该弱可及对象。通过如下代码可以了明了的看出它的作用:
  1. <span style="font-size: 12px;">String abc=new String("abc");      
  2. WeakReference<String> abcWeakRef = new WeakReference<String>(abc);      
  3. abc=null;      
  4. System.out.println("before gc: "+abcWeakRef.get());      
  5. System.gc();      
  6. System.out.println("after gc: "+abcWeakRef.get()); </span>  
String abc=new String("abc");    
WeakReference<String> abcWeakRef = new WeakReference<String>(abc);    
abc=null;    
System.out.println("before gc: "+abcWeakRef.get());    
System.gc();    
System.out.println("after gc: "+abcWeakRef.get()); 

运行结果:

  before gc: abc
  after gc: null

gc收集弱可及对象的执行过程和软可及一样,只是gc不会根据内存情况来决定是不是收集该对象。

如果你希望能随时取得某对象的信息,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象,而不是用一般的 reference。
  1. <span style="font-size: 12px;">A obj = new A();  
  2.   
  3. WeakReference wr = new WeakReference(obj);  
  4.   
  5. obj = null;  
  6.   
  7. //等待一段时间,obj对象就会被垃圾回收  
  8. ...  
  9.   
  10. if (wr.get()==null) {   
  11.     System.out.println("obj 已经被清除了 ");   
  12. } else {   
  13.    System.out.println("obj 尚未被清除,其信息是 "+obj.toString());  
  14. }  
  15. ...</span>  
A obj = new A();

WeakReference wr = new WeakReference(obj);

obj = null;

//等待一段时间,obj对象就会被垃圾回收
...

if (wr.get()==null) { 
    System.out.println("obj 已经被清除了 "); 
} else { 
   System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}
...
在此例中,透过 get() 可以取得此 Reference 的所指到的对象,如果返回值为 null 的话,代表此对象已经被清除。

这类的技巧,在设计 Optimizer 或 Debugger 这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以 影响此对象的垃圾收集。

PhantomRefrence(虚引用)

虚顾名思义就是没有的意思,建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null。先看一下和gc交互的过程在说一下他的作用。


1 不把referent设置为null,直接把heap中的new String("abc")对象设置为可结束的(finalizable).

2 与软引用和弱引用不同,先把PhantomRefrence对象添加到它的ReferenceQueue中,然后在释放虚可及的对象。

你会发现在收集heap中的new String("abc")对象之前,你就可以做一些其他的事情。通过以下代码可以了解他的作用。
  1. <span style="font-size: 12px;">import java.lang.ref.PhantomReference;      
  2. import java.lang.ref.Reference;      
  3. import java.lang.ref.ReferenceQueue;      
  4. import java.lang.reflect.Field;      
  5.      
  6. public class Test {      
  7.     public static boolean isRun = true;      
  8.      
  9.     public static void main(String[] args) throws Exception {      
  10.         String abc = new String("abc");      
  11.         System.out.println(abc.getClass() + "@" + abc.hashCode());      
  12.         final ReferenceQueue referenceQueue = new ReferenceQueue<String>();      
  13.         new Thread() {      
  14.             public void run() {      
  15.                 while (isRun) {      
  16.                     Object o = referenceQueue.poll();      
  17.                     if (o != null) {      
  18.                         try {      
  19.                             Field rereferent = Reference.class     
  20.                                     .getDeclaredField("referent");      
  21.                             rereferent.setAccessible(true);      
  22.                             Object result = rereferent.get(o);      
  23.                             System.out.println("gc will collect:"     
  24.                                     + result.getClass() + "@"     
  25.                                     + result.hashCode());      
  26.                         } catch (Exception e) {      
  27.      
  28.                             e.printStackTrace();      
  29.                         }      
  30.                     }      
  31.                 }      
  32.             }      
  33.         }.start();      
  34.         PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,      
  35.                 referenceQueue);      
  36.         abc = null;      
  37.         Thread.currentThread().sleep(3000);      
  38.         System.gc();      
  39.         Thread.currentThread().sleep(3000);      
  40.         isRun = false;      
  41.     }      
  42.      
  43. }</span>  
import java.lang.ref.PhantomReference;    
import java.lang.ref.Reference;    
import java.lang.ref.ReferenceQueue;    
import java.lang.reflect.Field;    
   
public class Test {    
    public static boolean isRun = true;    
   
    public static void main(String[] args) throws Exception {    
        String abc = new String("abc");    
        System.out.println(abc.getClass() + "@" + abc.hashCode());    
        final ReferenceQueue referenceQueue = new ReferenceQueue<String>();    
        new Thread() {    
            public void run() {    
                while (isRun) {    
                    Object o = referenceQueue.poll();    
                    if (o != null) {    
                        try {    
                            Field rereferent = Reference.class   
                                    .getDeclaredField("referent");    
                            rereferent.setAccessible(true);    
                            Object result = rereferent.get(o);    
                            System.out.println("gc will collect:"   
                                    + result.getClass() + "@"   
                                    + result.hashCode());    
                        } catch (Exception e) {    
   
                            e.printStackTrace();    
                        }    
                    }    
                }    
            }    
        }.start();    
        PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,    
                referenceQueue);    
        abc = null;    
        Thread.currentThread().sleep(3000);    
        System.gc();    
        Thread.currentThread().sleep(3000);    
        isRun = false;    
    }    
   
}

结果为:

class java.lang.String@96354
gc will collect:class java.lang.String@96354

为什么需要使用软引用

首先,我们看一个雇员信息查询系统的实例。

我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。

作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。

这时我们通常会有两种程序实现方式:

一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;

另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。

很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。

我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。

   

在J2EE的bean设计时我们对有些bean需要实现Serializable,为什么?

实现了Serializable接口的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。这一过程亦可通过网络进行。这意味着序列化机制能自动补偿操作系统间的差异。换句话说,可以先在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新“装配”。不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。

每一篇不宜写得过长,下篇继续

 

转载地址:http://blog.youkuaiyun.com/lifetragedy/article/details/9751079

Java Interview QA java 面试中一些关键的常常被问到的问题。 面试宝典。 立即下载

相关推荐

图解凸函数与凹函数:别再被数学定义搞晕了!

本文通过图解和生活化类比,深入浅出地解释了凸函数与凹函数的数学定义及其与日常直觉的差异。文章详细介绍了凸函数的图像特征、数学定义(包括二阶导数判断)、在机器学习中的重要性,以及常见误区和实际应用中的判断技巧,帮助读者彻底理解这一关键数学概念。

weixin_29159441的博客 648

面试题总结一

1.transient关键字的作用 transient关键字用来修饰类的属性,被修饰的属性在对象被序列化时不会被序列化,所以transient可以用来修饰没必要序列化的成员属性. 2.子类能否重写父类的静态方法 不能 因为静态方法属于类,在类加载的时候就被加载进来,存储到所在的内存中,而类的非静态方法属于对象,每个对象都有一份非静态方法的引用,方法被重写,调用的仍是子类...

weixin_44307391的博客 194

QtWebApp的使用【在Qt中搭建HTTP服务器】(一)

用Qt和QtWebApp能够实现在C++中开发HTTP Web服务器应用程序。 首先,需要先安装Qt的软件开发工具包。点此下载 其次,下载最新的QtWebApp库。点此下载 下载并解压缩QtWebApp ZIP文件。你将会看到: 如何使用QtWebApp 1)将QtWebApp.zip文件解压到文件夹中,并创建一个名为“ MyFirstWebApp”的新Qt控制台项目。然后,建立如下文件结构: 2)将以下行添加到MyFirstWebApp项目的项目文件中: QT += network include(

饭的笔记本 2万+

探索Java深度:Java-Interview开源项目推荐

探索Java深度:Java-Interview开源项目推荐 在Java开发的世界中,深入理解基础知识、底层原理以及算法是每个开发者成长的必经之路。今天,我们将向您推荐一个极具价值的开源项目——Java-Interview,它不仅涵盖了Java的基础知识,还包括了底层原理、算法详解以及大厂面试真题,是提升技术深度和广度的宝贵资源。 项目介绍 Java-Interview 是一个持续更新中的Java知...

gitblog_00898的博客 827

EMB电子机械制动执行器五大核心部件选型解析

本文介绍了EMB电子机械制动执行器五大核心部件的选型方案:采用无刷直流电机作为驱动源,兼具高扭矩和快速响应特性;选用滚珠丝杠传动机构,实现高效旋转-直线转换;行星齿轮减速器满足紧凑空间内的增扭需求;QT450-QT550材质的钳体确保刚度要求;应变片式压力传感器实现夹紧力精确测量。各部件选型综合考虑了性能、可靠性和空间限制,为EMB系统设计提供了完整解决方案。

m0_59012156的博客 1731

全面指南:PyTorch与ROCm版本兼容性及多版本环境管理

本文详细介绍了在AMD GPU上配置PyTorch开发环境的完整流程,重点解决版本兼容性和多版本ROCm环境管理问题。主要内容包括:1) PyTorch与ROCm版本对应关系查询;2) 四种查看ROCm版本的方法;3) 使用update-alternatives管理多版本ROCm;4) 环境变量配置与冲突解决方案;5) 完整的验证流程和性能测试方法。文章提供了最佳实践建议和故障排除清单,帮助开发者快速搭建稳定高效的深度学习开发环境,充分发挥AMD GPU硬件性能。通过系统化的验证流程确保各组件协同工作,解决

数字人生 606

Java-Interview

https://github.com/crossoverJie/Java-Interview 本项目多数是一些Java基础知识,底层原理,算法详解。  

cap423654的博客 372

手把手入门YOLO到改进优化教程 | 【P5进阶篇】YOLOv8损失函数改进实战-损失函数IoU之KLD Loss

在本节,将从 KLD Loss(Kullback–Leibler Divergence Loss)的理论到实战代码实现,带你把 KLD Loss融合进 YOLOv8 的训练框架中。并通过训练日志与实验结果,验证 KLD Loss 在实际工程中的优势。

嵌入式阿齐Archie 2万+

Aegisub插件开发入门:为你的字幕工作流定制专属工具

Aegisub是一款跨平台的高级字幕编辑器,通过插件开发功能,你可以为自己的字幕工作流定制专属工具,提升字幕制作效率。本文将带你了解Aegisub插件开发的基础知识,从环境搭建到简单插件的编写,让你快速掌握定制字幕工具的技能。 ## 为什么选择Aegisub插件开发? Aegisub作为一款专业的字幕编辑软件,本身已经具备强大的功能。但每个字幕制作者的工作流都有所不同,通过插件开发,你可以:

gitblog_00029的博客 456

LAMMPS后处理—如何构建二维云图-接触角呢?

计算接触角

Rockyoung 6520

UG\NX二次开发 替换部件引用集UF_ASSEM_replace_refset

替换部件引用集UF_ASSEM_replace_refset,需要替换成“完整部件(Entire Part)”需要第三个参数传入空指针或者空字符串。

王牌飞行员_里海的博客 252

[置顶] think in java interview-高级开发人员面试宝典(二)

从现在开始,以样题的方式一一列出各种面试题以及点评,考虑到我在前文中说的,对于一些大型的外资型公司,你将会面临全程英语面试,因此我在文章中也会出现许多全英语样题。 这些题目来自于各个真实的公司,公司名我就不一一例举了,是本人一直以来苦心收藏的。 一个JAVA 的MAIN方法引发的一场血案     Q:    What if the main method is declared as p...

weixin_33857679的博客 121

模型瘦身术:YOLOv5无损剪枝实战教程

本文介绍了一种YOLOv5模型的无损剪枝方法,通过"稀疏训练+结构化剪枝+微调"的流程,在不损失精度的前提下显著减小模型尺寸并提升推理速度。具体步骤包括:1)稀疏训练给参数排优先级;2)裁剪不重要通道;3)微调恢复精度;4)验证效果。实战部分详细展示了从环境搭建到剪枝实现的完整流程,并分析了剪枝后在边缘设备部署、实时检测等场景的优势。该方法可使YOLOv5s模型从14MB缩减至2-3MB,推理速度提升30%-50%,适用于资源受限设备的轻量化部署需求。

LXY_LOVE36的博客 104

think in java interview-高级开发人员面试宝典(一)

无论你是在职,非在职,高级工程师,工程师,架构师,如果你正在面试阶段,请看完此文,相信这篇文章对你的职业生涯和阶值观会发生重大的改变。如果你是一名PM或者是管理者正在物色合适的开发人选,那么我相信这篇文章会在在如何挑选技术型人材上给你带来重大的帮助。作为一名技术型人材由期是程序员,用什么可以恒量自己是否合格或者我们怎么去恒量一个程序员是否质深,比如说:他可以适合一般的软件工程师岗位,还是适合高级工

打造全国最全的AI Agent开发知识领域的博客 2万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

think in java interview-高级开发人员面试宝典(九)

模拟面试今天来谈一下面试时的综合能力。下面先来看一份简历的摘要。熟练掌握SPRING, STRUTS1, 2, HIBERNATE;J2EE方面5年工作经验;ORACLE使用经验48个月;熟练掌握JAVA缓存机制;了解工作流、ERP、EAI工作机制并有实际项目经验;老实说,一般面试官看到上面的简历就会想让这个人来面试了,因为真的你SSH,ORACLE,ERP或者是EAI等工作过5年很利害了已经,于

打造全国最全的AI Agent开发知识领域的博客 1万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

think in java interview-高级开发人员面试宝典(四)

算出num个数内的质数 质数即大于1的一个自然数,这个数可以被1和自身整除,如算出20之内的质数,它们有2,3,5,7,11,13,17,19这样的数字。这道题也是面试过程中笔试常问的一道题。 这道题的其目的在于: 1. 看笔试者的数学还记不记得 2. 看笔试者平时的算法 因此答题有两种。 第一种,通用做法 [java] view pl

islittletan的专栏 856

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: think in java interview-高级开发人员面试宝典(一)
下一篇: think in java interview-高级开发人员面试宝典(三)
7star_java
博客等级 码龄15年 80粉丝 127原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值