1. String 是最基本的数据类型吗?
不是,String是类,String是不可变的,对String类的任何改变,都会返回一个新的String类对象。
2. java的八大数据类型?
整型:byte,short,int,long
字符型:char
浮点型:float,double
boolean型:boolean
3. float f=3.4;是否正确?
不正确,java内,整数默认是int,浮点默认是double,支持向上转型,即int自动转long,float自动转double,但不支持自动向下转型。float f = (float)3.4; float f= 3.4f;都是对的。
4. short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
第一个有错,还是那句话,整数java默认是int。s1是short,1是int,相加,向上转型是int,int不能赋值给short,需要强转。s1 = (short) s1 + 1;
第二个没错,s1 += 1;其实就是s1 = (short) s1 + 1;
5. int和Integer的区别?
Integer是int的包装类,int是基本数据类型;Integer默认为null,int默认为0;
用代码例子说明。
package test;
public class IntTest {
public static void main(String []args) {
Integer a1 = new Integer(100);
Integer a2 = new Integer(100);
Integer b1 = 100;
Integer b2 = 100;
Integer b3 = 128;
Integer b4 = 128;
int c1 = 100;
int c2 = 100;
//false 原因:两个对象,内存地址不同
System.out.println(a1==a2);
//true 原因:非new的Integer比较时,变量在-128到127之间为true,反之为false
System.out.println(b1==b2);
//false 原因:非new的Integer比较时,变量在-128到127之间为true,反之为false
System.out.println(b3==b4);
//true
System.out.println(c1==c2);
//false 原因:new Integer()指向堆中新建的对象,
//非new的Integer指向java常量池中的对象。内存地址不同。
System.out.println(a1==b1);
//true 原因:Integer自动拆包,其实就是int之间的比较
System.out.println(a1==c1);
//true 原因:Integer自动拆包,其实就是int之间的比较
System.out.println(b1==c1);
}
}
需要注意的是java在编译Integer i = 1;时,会变成 Integer i = Integer.valueOf(1);
以下是Integer.valueOf()的源码
public static Integer valueOf(int i){
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high){
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
也就是说非new的Integer范围是-128到127之间的数,会进行缓存,下次不会再new,而是直接从缓存里取。
6. 堆(heap),栈(stack),静态区(static area)的分配?
在网上查完资料之后,总结如下:
heap区:(存储的基本单位)
1.保存对象的实例(new创建的对象和数组),实例属性,属性类型,对象本身的类型标记。
2.存储的对象包含一个与之对应的class信息。
3.JVM只有一个heap区,被所有的线程共享。
4.一般人为释放,否则程序结束时由OS回收。
stack区:(运行的基本单位)
1.stack区存对象的引用,和基础数据类型。
2.保存一个4个字节的heap内存地址,用来定位该对象引用的实例在heap区的位置。
3.每个线程都有一个stack区,互相之间不能访问。
静态区/方法区:
1.被所有线程共享。
2.包含所有class和static变量。
3.初始化的全局变量和初始化的静态变量在一个区域,未初始化的全局变量和未初始化的静态变量在一个区域。
7. 最有效率的方法算出2 乘以8?
位运算:System.out.println(2<<3);即可。其实就是2乘(2的三次方)
2的二进制往左移两位。
2的二进制0010,移动之后,1000。换成十进制就是16。
8. System.err.println(i-=i+=i-=i+=i-=i--);怎么算?
这类题要记住两点,
1、i的值都不会在这串运算中改变。
2、从右往左算。
public static void main(String[] args) {
int i = 5;
//i=i-i+i-i+i-(i-1)
//5-5+5-5+5-4
System.out.println(i-=i+=i-=i+=i-=--i);//1
i = 5;
//i=i-i+i*i+i-(i-1)
//5-5+5*5+5-4
System.out.println(i-=i+=i*=i+=i-=--i);//-30
}
9.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
这个本质在考 “x和y是两个对象,x.equals(y)是true的时候,x和y的hash code一样吗?”
答:不对,因为java中的规定是——
1)如果两个对象相同(equals 方法返回 true),那么它们的hashCode 值一定要相同;
2)如果两个对象的 hashCode 相同,它们并不一定相同。
关键就是搞清楚equals判断的是什么,看源码。
public boolean equals(Object obj) {
return (this == obj);
}
那么这里引出来 == 和 equals 的区别了。
如果是基本变量,根本没有equals方法,就是用 == ,比较的就是内容。
如果是new出来的对象,父类是object的这种,==比较地址,equals也比较地址。
如果是java中重写了equals的类,比较什么就看重写内容了。(一般重写都是为了比较内容)
举两个例子。
1)String中equals源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
2)ArrayList的父类AbstractList的源码
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
所以,如果非要实现equals 方法返回 true,hashCode还不同的情况,也可以。重写equals方法。
再举个例子。
public class Equals {
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof Equals) {
return true;
}
return false;
}
public static void main(String[] args) {
Equals A = new Equals();
Equals B = new Equals();
System.out.println(A.equals(B) == true);//true
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
10.new String()创建了几个对象这类问题
首先明白创建了几个对象就是在说把对象放在了几个地方。
那么一共就俩地方,一个是String池,一个是堆。
然后开始各种String的测试。
定义String,无非两种。
1)String s1 = "hello";
2)String s2 = new String("hello");
第一种,会先验证String池中有没有"hello",有的话s1指向"hello"。没有的话创建新的"hello"存入String池中并指向"hello"。
第二种,会先验证String池中有没有"hello",有的话对String池不做任何操作。没有的话创建新的"hello"并存入String池中。然后继续在堆里创建new String("hello"),并指向它。
11.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
这个问题,查了资料之后,算是有点想法了。
一点一点来。
先说结论:java中没有引用传递,只有值传递。所以这种情况也是值传递。
值传递的定义是:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参。
引用传递的定义是:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
看了值传递的定义后,有了疑问。
问:“这种情况应该不是值传递吧?违反了值传递的定义呀,因为对象的属性变化了。”
答:“对象属性改了没问题,但是传递的参数并不是对象呀,所以它改不改不违反值传递。”
问:“传递的参数不是对象,那是啥?”
答:“是对象的引用的一个副本。”
问:“这不还是引用吗?为啥不是引用传递?”
答:“还是看定义,引用传递 直接传地址。这种情况传的引用,指向地址。所以这是通过传递对象引用副本的方式实现了引用传递的效果,但是,它是值传递。”
问:“确定是值传递的问题可以了,那String对象作为参数传递的话,为什么没有返回变化后的结果呢?”
答:“额,那照这么说,Integer,Double等也会有此疑问是吧?”
问:“是的。”
答:“因为,Integer是int的包装类,Double是double的包装类,String是char[]的包装类。对包装类的值操作实际上是通过对其对用的基本类型操作实现的。”
网友评论