我的定位:中高级人才(框架熟练、Java语法精通、数据库会用、Linux会用、中间件会用、有大数据经验!)
开始,我以为自己什么都知道。后来发现,其实我什么都不知道。

面试题整理03

1 servlet是单例还是多例? struts2的action是单例还是多例?

servlet是单例多线程

struts2的action是多实例

 

2 二分法

/**
 * 二分(折半)查找法
 * @author rong.zhou
 *
 */
public class SearchNum {
    public static void main(String[] args) {
        int[] arr = {0,1,2,3,4,5,6,7,8,9};  //定义有序数组
        int searchNum = 10; //定义要查找的数
        int startIndex = 0;  //定义开始下标
        int endIndex = arr.length-1;  //定义结束下标
        int midIndex = -1; //定义中间位置下标
        boolean isFind = false;  //标记是否找到
        do{
            midIndex = (startIndex+endIndex)/2;   //获取中间位置下标            
            if(arr[midIndex] == searchNum){ //如果中间位置元素值与要查找的值相等,则找到啦
                System.out.println("恭喜你,找到啦,下标为"+midIndex);
                isFind = true;
                break;
            }else if(arr[midIndex]>searchNum){ //如果比要找到的数大,则将结束下标更新为midIndex-1
                endIndex = midIndex-1;
            }else{
                startIndex = midIndex+1; ///如果比要找到的数小,则将开始下标更新为midIndex+1
            }
        }while(startIndex<=endIndex);
        
        if(!isFind){
            System.out.println("抱歉,要查找的数不在此数列中");
        }
    }
}

 

3 基本数据类型的包装类 装箱 拆箱 ***

 

在JAVA中,数据类型可分为两大种,基本数据类型(值类型)和类类型(引用数据类型)。基本类型的数据不是对象,所以对于要将基本数据类型当对象使用的情况,JAVA提供的包装类。基本类型和包装类的对应关系如下:

int -- Integer

char -- Character

double -- Double

float -- Float

byte -- Byte

short -- Short

long -- Long

boolean -- Boolean

所谓装箱,就是把基本类型用他们相对应的引用类型包装起来,使他们可以具有对象的特质,如我们可以把int型包装成Integer类的对象,或者把double包装成Double等等。

所谓拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据。

J2SE5.0后提供了自动装箱和拆箱的功能,此功能事实上是编译器来帮忙,编译器在编译时依照编写的方法,决定是否进行装箱或拆箱动作。

自动装箱的过程:每当需要一种类型的对象时,这种基本来兴就自动的封装到与它相同类型的包装中。

自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动的提取出来,没必要再去调用intValue()和doubleValue()方法。

自动装箱只需将该值赋给一个类型包装器引用,java会自动创建一个对象。例如:

 

Integer i = 100;//没有通过new建立,java自动完成


自动拆箱只需将该对象值赋给一个基本类型即可。例如:

 

 

int i = 10;
Integer j = new Integer(i);//手动装箱操作
int k = j.intValue();//手动拆箱操作

int i = 11;
Integer j = i;//自动装箱
int k = j;//自动拆箱


然而在Integer的自动拆箱会有些细节值得注意:

 

 

	public static void main(String[] args) {
		Integer a = 100;
		Integer b = 100;
		
		Integer c = 200;
		Integer d = 200;
		
		System.out.println(a == b); //1
		System.out.println(a == 100); //2
		
		System.out.println(c == d); //3
		System.out.println(c == 200); //4
	}


在java中,“==”是比较object的reference而不是value,自动装箱后,abcd都是Integer这个Object,因此“==”比较的是其引用。按照常规思维,1和3都应该输出false,但结果是:

 

true

true

false

true

结果2和4,是因为ac进行了自动拆箱,因此其比较是基本数据类型的比较,就跟int比较是一样,“==”在这里比较的是他们的值,而不是引用。对于结果1,虽然比较的时候还是比较对象的引用,但是自动装箱时,java在编译的时候Integer a = 100;被翻译成Integer a = Integer.valueOf(100);关键就在于这个valueOf()的方法。

 

	public static Integer valueOf(int i) {
		final int offset = -128;
		if (i >= -128 && i <= 127) {
			return IntegerCache.cache[i + offset];
		}
		return new Integer(i);
	}

	private static class IntegerCache {
		private IntegerCache() {
		}
	
		static final Integer cache[] = new Integer[-(-128) + 127 + 1];
		static {
			for (int i = 0; i < cache.length; i++) {
				cache = new Integer(i - 128);
			}
		}
	}


根据上面的jdk源码,java为了提高效率,IntegerCache类中有一个数字缓存了值从-128到127的Integer对象,当我们调用Integer.valueOf(int i)的时候,如果i的值是>=-128且<=127时,会直接从这个缓存中返回一个对象,否则就new一个Integer对象。

 

下面一段代码:

 

	public static void main(String[] args) {
		Integer m = new Integer(10);
		Integer n = new Integer(10);
		System.out.println(m == n);

		m = m - 1;
		n = n - 1;
		System.out.println(m == n);
	}


输出结果为:

 

false

true

原因:m和n都是new出来的对象,内存地址不一样,所以第一次m == n比较的引用不一样。但是m = m - 1首先进行了自动拆箱m.intValue,相减之后在进行装箱的动作:m = Integer.valueOf(m.intValue - 1),而m和n都在-128到127之间,所以自动装箱后,引用的都是缓存内的Integer,所以第二次输出为true.

4 == equals 区别

 

(单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚)

 

==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。

 

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

 

equals方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。例如,对于下面的代码:

 

String a=new String("foo");

 

String b=new String("foo");

 

两条new语句创建了两个对象,然后用a/b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。

 

在实际开发中,我们经常要比较传递进行来的字符串内容是否等,例如,String input = …;input.equals(“quit”),许多人稍不注意就使用==进行比较了,这是错误的,随便从网上找几个项目实战的教学视频看看,里面就有大量这样的错误。记住,字符串的比较基本上都是使用equals方法。

 

如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的实现代码如下:

 

boolean equals(Object o){

 

return this==o;

 

}

 

这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object类继承的)就是使用==操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用==会得到同样的结果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象的内容是相同的。

 

-----------------------------------------------------------------

 

简单的说,==比较两个人是否究竟是真正同一个人,equals一般用来比较两个人在逻辑上是否相等(比如规定两人成年之后身高相同就算两人相同等等),想怎么定义就怎么定义,如果不覆盖equals方法的话,默认仍然是比较两人是否同一个人(废话,两个人都还处于胚胎状态,都没有具体特征,怎么可能在逻辑上比较)。

 

posted @ 2017-03-07 15:29  想太多先森  阅读(146)  评论(0编辑  收藏  举报