Java基础知识面试题(随时更新)

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 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[]的包装类。对包装类的值操作实际上是通过对其对用的基本类型操作实现的。”

你可能感兴趣的:(Java基础知识面试题(随时更新))