Java工程师面试1000题11-20

11、复制对象和复制引用的区别?

有如下程序:

Person p = new Person(23,"zhang");
Person p1 = p;
System.out.println(p);
System.out.println(p1); 

程序执行后看打印结果:

com.xidian.Person@2f4ee1ac
com.xidian.Person@2f4ee1ac

可以看出,两个对象的地址相同,所以执行“Person p1 = p;”并不是创建了一个新对象,p和p1是同一个引用,他们都指向了一个相同的对象Person(23,“zhang”)。我们把这种现象叫做引用的复制,上面的代码执行完成之后,内存中的情形如下图所示:

在这里插入图片描述
而下面的代码才是实现真正克隆了一个对象:

Person p = new Person(23,"zhang");
Person p1 = (Person) p.clone();
System.out.println(p);
System.out.println(p1); 

打印结果如下:

com.xidian.Person@2f4ee1ac
com.xidian.Person@67f1fba0

从打印结果可以看出,两个对象地址是不同的,也就说创建了新的对象,而不是把原来的对象地址赋值给一个新的引用变量。执行完以上打码后,内存中的情形如下图所示:

在这里插入图片描述

12、什么是深拷贝什么是浅拷贝?

示例代码中,Person有两个成员变量,分别是name和age,name是String类型,age是int类型,代码非常简单,如下所示:

public class Person implements Cloneable {
    
    private int age;
    
    private 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;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (Person)super.clone();
    }
}

由于age是基本数据类型,那么对它的拷贝没什么疑义,直接讲一个4字节的整数值拷贝过来就行了。但是name是String类型,他只是一个引用,指向一个真正的String对象,所以对他的拷贝方式有两种,分别是:直接将原对象中的name的引用值拷贝给新对象的name字段,或者是根据原对象的name指向的字符串对象创建一个新的,相同的字符串对象,将这个新字符串对象的引用赋值给新拷贝的Person对象的name字段。这两种方式分别叫做浅拷贝深拷贝。深拷贝和浅拷贝示例图如下所示:

在这里插入图片描述
在这里插入图片描述

总结:如果两个Person对象的name的地址值相同,说明两个对象的name都指向同一个String对象,也就是浅拷贝,而如果两个对象的name地址值不相同,那么就说明指向不同的String对象了,也就是说在拷贝Person对象的时候,同时拷贝了name引用的String对象,也就是深拷贝。如果想要深拷贝一个对象,这个对象必须要实现Cloneable接口,实现clone方法,并且在clone方法内部,把该对象引用的其他对象也要clone一份,这就要求这个被引用的对象也必须要实现Cloneable接口并且实现clone方法。

扫描二维码关注公众号,回复: 5545140 查看本文章

13、两个对象值相同(即x.equals(y) == true)是否可以有不同的hashCode?

不可以。如果两个对象x和y满足x.equals(y) == true,他们的hashCode应当相同。

Java对于equals方法和hashCode方法是这样规定的:
(1)如果两个对象相同(equals方法返回true),那么他们的hashCode值一定相同。
(2)如果两个对象的hashCode相同,他们并不一定相同。当然了,我们可以违背以上两个原则,但是如果违背了这两个原则,我们就会发现,再使用容器的时候,相同的对象可以同时出现在Set集合中,对于使用哈希存储的系统,哈希碰撞的概率会大大提升。

关于equals方法,首先equals方法必须要满足
自反性:x.equals(x) == true ;
对称性:x.equals(y) == true ==> y.equals(x) == true;
传递性:x.equals(y) == true && y.equals(z) == true ==> x.equals(z) == true;
一致性:x和y如果没有做任何修改时,多次调用x.equals(y)应该得到相同的值。

实现高质量equals方法的诀窍有:

使用“==”操作符检查参数是否为这个对象的引用;
使用instanceof操作符检查参数是否为正确的类型
对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;
编写完equals方法后,检查是否满足对称性、一致性、传递性;
重写equals方法时,总是要重写hashCode;
不要将equals方法参数中Object对象替换成其他类型,在重写时不要忘记加上@Override注解。

14、是否可以继承String类?

不可以。String是final类,所以不可以继承。

15、String s = “Hello”; s = s + “World”;执行完这两行代码后,原始String对象的内容变了吗?

没有,因为String被设计成不可变类(immutable),所以它的所有对象都是不可变对象,在这两句代码中,s原先指向一个String对象,对象内容为Hello,然后我们对s进行了“+”操作,这时候,s不指向原来那个对象了,转而指向另外一个String对象了,这个对象的内容是“HelloWorld”,原来那个对象仍然存在于内存中,只是s这个引用变量不再指向它了。

所以,如果经常需要对字符串进行各种修改操作,那么使用String对象来代表字符串的话会引起很大的内存开销。因为String对象建立之后就不能再修改了,对一个不同的String就需要一个不同的String对象来表示。面对这种情况,应该考虑使用StringBuffer类,它允许修改,而不是每一个不同的字符串都要新创建一个对象来表示,并且这两种类的对象很容易进行转换。另外,如果要使用内容相同的字符串,不必每一次都new一个String,因为String对象不可变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。

对于字符串常量,如果内容相同,Java认为他们代表同一个String对象,但是使用关键字new调用构造器的时候,无论内容是否相同,总是会创建一个新对象。至于为什么要把String对象设计成不可变类呢,这是由于它的用途决定的,不可变类有一个优点,比如因为他的对象是只读的,所以多线程并发访问的时候也不会有任何问题

16、Java中实现多态的机制是什么?

Java中实现多态的机制靠的是父类或者接口定义的引用变量可以指向子类或者具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体事例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

17、Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11,四舍五入的原理是在参数上加0.5然后进行取整。

18、数组有没有length()方法?String有没有length()方法?

数组没有length()方法,但是有length属性。String有length()方法。

19、Java中的异常分类?

按照异常需要处理的时机可以将异常分为编译时异常(也称为强制异常)也叫做CheckedException运行时异常(也称为非强制异常)也叫做RunntimeException

只有Java语言提供了Checked异常。Java认为Checked异常都是可以处理的异常,所以Java程序必须显式的处理,如果程序中存在Checked异常,该程序在编译的时候就会发出错误,无法通过。这体现了Java的设计哲学:没有完善错误处理的代码根本没有运行的机会。对Checked异常通常有两种处理方法,第一是当前方法知道如何处理该异常,则使用try…catch块来处理该异常,第二是不知道该如何处理,则在定义该方法的时候声明抛出该异常。

运行时异常只有当代码在运行的时候才发出的异常,编译时不需要try…catch块,RunntimeException比如除数是0和数组下标越界,其产生频繁,处理麻烦,若要声明或者捕获将会对程序的可读性和运行效率产生很大影响,所以交由系统自动检测并将它们交给缺省的异常处理程序。

20、说出常见的RunntimeException?

java.lang.NullPointerException 空指针异常:原因是出现了未经初始化的对象或者是不存在的对象。
java.lang.ClassNotFoundException:指定的类找不到:类的名称或者路径加载错误。
java.lang.NumberFormatException:字符串转换为数字异常:字符串数据中包含非数字字符
java.lang.IndexOutOfBoundsException:数组角标越界
java.lang.IllegalArgumentException:方法传递参数错误
java.lang.ClassCastException:数据类型转换异常。
java.lang.NoClassDefFoundException:未找到类定义错误
java.lang.NoSuchMethodException:方法不存在异常

原文:https://blog.csdn.net/qq_21583077/article/details/88127317

猜你喜欢

转载自blog.csdn.net/Mr_Quinn/article/details/88561160