Java面试题详解:其他

1. 两个对象值相同(x.equals(y) == true),但可有不同的hash code,这句话对不对?

Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。

我们可以这样理解:

假设一个类有a,b,c三个基本类型属性(如果是对象则用该对象的hashCode值代替即可),那么hashCode方法的返回值可以简单的用以下表达式表示,其中A,B,C都是常数:

hashCode = A*a+B*b+C*c

所以当二个对象的equals相同,那么这二个对象的属性a,b,c的值也一样,而A,B,C都是常数,所以这个时候计算的hashCode值肯定是一样的。

但是反过来如果二个对象的hashCode一样,即:

A*a1+B*b1+C*c1 = A*a2+B*b2+C*c2

很显然通过以上表达式,我们并不能一定确定 a1=a2, b1=b2, c1=c21/

2. Java到底是值传递还是引用传递?

我个人比较讨厌这种题,因为很可能面试官和你对于什么是值传递什么是引用传递的定义就不一样,如果定义都不一样,讨论的就不是一个东西,倒不如直接举个具体的例子。

具体例子无非以下几种:

1. 方法参数是基本类型

int i = 1;
m(i);
问:i的值是?

public void m(int k) {
    k = 2;
}

对于基本类型变量其值就分配在栈空间,因此在调用m方法前,栈空间中只有i变量,值等于1,当调用m方法时,会在栈空间中分配一个新的内存空间给方法参数k,且k的值等于i的值,执行方法后,参数k的值被改成2,但是变量i的并没有改变。

2. 方法参数是引用类型:

StringBuilder sb = new StringBuilder("str");
m(sb);
问:sb.toString()的输出时是?

public void m(StringBuilder sb1) {
    sb1.append("test");
}

对于引用类型,对象是分配在堆里,栈里分配给变量的空间存的值是对象在堆空间中的内存地址,因此以上代码执行过程是这样的,在调用方法m之前,栈里分配一个变量空间给sb,同时堆里分配了一个StringBuilder类型的对象内存,栈空间里sb变量存了指向堆空间中对象的地址。

执行m方法时,栈里给方法参数sb1又分配了一块内存,这块内存的值存的是栈空间sb内存的值,即sb1和sb指向了堆中同一个地方。

 在m方法执行后,堆内存中的对象发生了改变,由于sb变量也指向这个对象,因此方法执行后,sb.toString()的值是test

 3. 方法参数是引用类型的另一种情况:

StringBuilder sb = new StringBuilder("str");

m(sb);

问:sb.toString()的值

public void m(StringBuilder sb1) {
    sb1 = new StringBuilder("test");
}

 这种情况在方法体执行前和前面一样,但是执行完方法后,内存里是这样的:

 所以这种情况最后sb.toString()的值还是str

3. 阐述静态变量和实例变量的区别?

参考答案:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。静态变量是在类初始化时初始化的,实例变量是在创建实例的时候初始化的。

4. 如何复制或克隆一个对象?

参考答案:

  1. 重写clone方法,方法内部需要调用supper.clone(); 同时类需要实现Cloneable接口(这个接口是个标记接口,如果没有实现这个接口调用了super.clone()会报错)
  2. 实现Serialization接口,利用Java的对象序列化/反序列化机制创建对象
  3. 除了Java的序列化机制,目前还有很多更主流性能更好的序列化框架同样可以实现,如FastJson,Gson,Jackson,谷歌的Protocol Buffers,Kryo等

5. 什么是闭包?Java支持吗?

闭包定义有很多版本且比较抽象难理解,有兴趣的可以自己去搜索一下,闭包概念主要在函数式编程中,下面给一个JavaScript闭包的例子

function add() {
    var counter = 0;
    return function () {return counter += 1;}
}

以上返回值是一个匿名函数,该函数可以访问外部函数的局部变量,正常情况下,一个函数执行完后,其内部局部变量会释放内存,但闭包这种写法,由于持有了局部变量,因此函数执行完,局部变量内存不能立刻得到释放。Java中可以用匿名内部类的方式实现类似效果。

6. Java 中的final关键字有哪些用法?
答:(1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改,如果变量是引用类型,表示的是引用本身不能修改(不能引用其他对象),但是引用的对象还是可以修改的。

7. 字符串编码转换,如何将GB2312编码的字符串转成UTF-8编码的字符串

String s1 = "你好"; String s2 = new String(s1.getBytes("GB2312"), "UTF-8");

8. try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

答:会执行,在方法返回调用者前执行。可能还会问,在finally里有return语句,最终返回的是哪个?返回的是finally里面的,不过应该尽量避免这样做。

9. 你常见的运行时异常?

ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下标越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)

10. ClassNotFoundException和NoClassDefFoundError区别

ClassNotFoundException是Exception的子类,是非运行时异常;NoClassDefFoundError是Error的子类。

ClassNotFoundException通常发生于以下几个场景:

  1. 调用class的forName方法时,找不到指定的类
  2. ClassLoader 中的 findSystemClass() 方法时,找不到指定的类
  3. ClassLoader 中的 loadClass() 方法时,找不到指定的类
  4. 编译Java代码时

NoClassDefFoundError通常发生在ClassLoader.defineClass() 时类名非法,主要是在需要用到这个类时,找不到这个类的定义,比如加载A类,A类引用了B类,由于某种原因现在找不到B类(jar包不存在或classpath变了)

11. 阐述final、finally、finalize的区别。

final,finally比较简单,主要说下finalize,finalize是Object中的一个空方法,这个方法会在垃圾收集器回收对象前调用,如果想要干预或记录垃圾回收情况,子类可以重写finalize方法。


12. 简述一下你了解的设计模式或spring中用到了哪些设计模式

创建性模式

单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式

结构型模式

适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式,代理模式

行为型模式

模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

这里不具体介绍每个模式了,建议重点了解:单例模式、工厂模式、抽象工厂模式、建造者模式,适配器模式、装饰模式、代理模式,模板方法模式、观察者模式、策略模式、职责链模式。

Spring几乎所有模式都用到了,但我认为工厂模式和代理模式是Spring的灵魂。

13. 用Java写一个单例类

  • 懒汉式,线程不安全
public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
     if (instance == null) {
         instance = new Singleton();
     }
     return instance;
    }
}
  • 懒汉式,线程安全
public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}
  • 双重锁检查(注意volatile关键字不能少)
public class Singleton {
    private volatile static Singleton instance; //声明成 volatile
    private Singleton (){}

    public static Singleton getSingleton() {
        if (instance == null) {                         
            synchronized (Singleton.class) {
                if (instance == null) {       
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
   
}
  • 饿汉式
public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();
    
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}
  • 静态内部类
public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE; 
    }  
}
  • 枚举
public enum EasySingleton{
    INSTANCE;

    public void doSomething() {

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

emeson_ch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值