资讯专栏INFORMATION COLUMN

Java 面试准备

chanjarster / 403人阅读

摘要:网站的面试专题学习笔记非可变性和对象引用输出为,前后皆有空格。假定栈空间足够的话,尽管递归调用比较难以调试,在语言中实现递归调用也是完全可行的。栈遵守规则,因此递归调用方法能够记住调用者并且知道此轮执行结束之返回至当初的被调用位置。

ImportNew 网站的Java面试专题学习笔记

1. 非可变性和对象引用
String s = " Hello ";
s += " World ";
s.trim( );
System.out.println(s);

输出为“ Hello World ”,前后皆有空格。
字符串是不可变对象。
s.trim()虽然生成了一个新的字符串对象,但是却没有变量指向这个心生成的对象,s 仍然指向字符串s += " World "。
下图说明了,生成对象以及垃圾回收过程。

可用StringBuilder来构造,因为其底层使用的是字符数组,所有操作都直接在字符数组上直接操作,而且他不是一个线程安全的类,执行速度上,相比于StringBuffer要快。

这一点如果深入理解了String的Interning机制,就更好理解了。
Java程序在编译时,会将所有确定下来的,存在双引号内的字符串,都存入常量池中,该常量池是类文件(.class)的一部分。常量池中存着许多表,其中 Constant_Utf8_info 表中,记录着会被初始化为 String 对象的字符串的字面值(iteral)。 在JVM 中,相应的类被加载运行后,常量池对应的映射到 JVM 的运行时常量池(run time constant pool)中。

关于String的intern()方法

当 intern 方法被调用,如果字符串池中已经拥有一个与该 String 的字符串值相等(即 equals()调用后为 true)的 String 对象时,那么池中的那个 String 对象会被返回。否则,池中会增加这个对象,并返回当前这个 String 对象。

现代的 JVM 实现里,考虑到垃圾回收(Garbage Collection)的方便,将 heap 划分为三部分: young generation 、 tenured generation(old generation)和 permanent generation( permgen )。字符串池是为了解决字符串重复的问题,生命周期长,它存在于 permgen 中。

因此,对于

String str = new String("abc");

JVM会生成两个字符串,一个是在常量池中,另外一个是new在heap堆中。

2. equals 和 ==
Object s1 = new String("Hello");
Object s2 = new String("Hello");
 
if(s1 == s2) {
  System.out.println("s1 and s2 are ==");
}else if (s1.equals(s2)) {
  System.out.println("s1 and s2 are equals()");
}

输出结果为s1 and s2 are equals()
主要考察对equals和==的理解,==比较引用的地址是否相同,equeal比较对象中真正的值。
详细的过程可见下图

另外,如果不是用 new关键字强制创建字符串对象的话,而是采用==,那么Java会默认采用字符串池,减少对象的创建。

String对象会创建一个字符串池(a pool of string),如果当前准备新创建的字符串对象的值在这个池子中已经存在,那么就不会生成新对象,而是复用池中已有的字符串对象。flyweight 模式的精髓就是对象复用。

3. 重载(overloading)和重写(overriding)

重写发生在子类继承父类时,子类覆盖父类的方法时发生,是在运行时发生。
重载是在同一个类中,同一个方法,不同参数时发生,是在编译期发生。

在Java 5中使用注解@override,来标示方法重写,如果编译时发现没有重写,则JVM会抛出编译异常。

4. 迭代和递归

可重入方法(re-entrant method)是可以安全进入的方法,即使同一个方法正在被执行,深入到同一个线程的调用栈里面也不会影响此次执行的安全性。一个非可重入方法则不是可以安全进入的。例如,加入写文件或者向文件中写入日志的方法不是可重入方法时,有可能会毁坏那个文件。

如果一个方法调用了其自身的话,我们称之为递归调用。假定栈空间足够的话,尽管递归调用比较难以调试,在Java语言中实现递归调用也是完全可行的。递归方法是众多算法中替代循环的一个不错选择。所有的递归方法都是可重入的,但是不是所有可重入的方法都是递归的。

栈遵守LIFO(Last In First Out)规则,因此递归调用方法能够记住“调用者”并且知道此轮执行结束之返回至当初的被调用位置。递归利用系统栈来存储方法调用的返回地址。 Java是一种基于栈设计的编程语言。

循环的方式可以达到目的,不必采用递归。但是在某些情况下采用递归方式则代码会更加简短易读。递归方法在循环树结构以及避免丑陋的嵌套循环的情况下是非常好用的。

常规递归方法(亦称,头递归)在上面演示了,这种方式会增加调用栈的大小。每次递归,其入口需要被记录在栈中。方法返回之前需要给countA(input.substring(1)的结果加一个count。因此,最后需要做的事其实是加法运算,而非递归本身。

在尾递归中,最后要做的是递归,加法运算在之前就已经完成了。栈调用减少带来了内存消耗减少并且程序的性能更好。如下代码

public class TailRecursiveCall {
 
 public int countA(String input) {
 
  // exit condition – recursive calls must have an exit condition
  if (input == null || input.length() == 0) {
   return 0;
  }
 
  return countA(input, 0) ;
 }
 
 public int countA(String input, int count) {
  if (input.length() == 0) {
   return count;
  }
 
  // check first character of the input
  if (input.substring(0, 1).equals("A")) {
   count = count + 1;
  }
 
  // recursive call is the last call as the count is cumulative
  return countA(input.substring(1), count);
 }
 
 public static void main(String[] args) {
  System.out.println(new TailRecursiveCall().countA("AAA rating"));
 }
}
5. 关于ArrayList

ArrayList的大小是如何自动增加的?你能分享一下你的代码吗?

使用ensureCapacity, 在进行添加元素时,检查容量是否足够,不够的话,就将容量扩大3/2,并将旧数组中的元素使用Arrays.copyOf拷贝到新数组中。

什么情况下你会使用ArrayList?什么时候你会选择LinkedList?

ArrayList是在访问的次数远大于插入和删除的次数,使用ArrayList,因为ArrayList底层使用数组,访问的复杂度为O(1), 但是插入和删除就得频繁使用System.arraycopy复制数组。 LinkList主要在访问次数远小于插入和删除的次数时使用,其删除和插入的复杂度,但访问元素时几乎为O(n)。

当传递ArrayList到某个方法中,或者某个方法返回ArrayList,什么时候要考虑安全隐患?如何修复安全违规这个问题呢?

当array被当做参数传递到某个方法中,如果array在没有被复制的情况下直接被分配给了成员变量,那么就可能发生这种情况,即当原始的数组被调用的方法改变的时候,传递到这个方法中的数组也会改变。

将其副本拷贝出来再进行修改。

如何复制某个ArrayList到另一个ArrayList中去?写出你的代码?

使用clone()方法,比如ArrayList newArray = oldArray.clone();

使用ArrayList构造方法,比如:ArrayList myObject = new ArrayList(myTempObject);
使用Collection的copy方法...

注意1和2是浅拷贝(shallow copy),何为浅拷贝?

浅拷贝就比如像引用类型,而深拷贝就比如值类型。浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。

深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。

还可用序列化技术来进行深拷贝,对象实现序列化接口,然后写入流,并读出来

// 将对象写到流里
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(this);
        // 从流里读出来
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (oi.readObject());

但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

在索引中ArrayList的增加或者删除某个对象的运行过程?效率很低吗?解释一下为什么?

频繁插入和删除,会频繁调用System.arrayCopy....效率低

参考地址
-[1] http://www.importnew.com/2228...
-[2] http://www.importnew.com/2223...
-[3] http://www.importnew.com/2217...
-[4] http://www.importnew.com/2329...
-[5] http://www.importnew.com/9928...
-[6] http://www.cnblogs.com/shuaiw...
-[7] http://blog.csdn.net/biaobiao...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64144.html

相关文章

  • 如何准备校招技术面试

    摘要:网易跨境电商考拉海购在线笔试现场技术面面。如何看待校招面试招聘,对公司而言,是寻找劳动力对员工而言,是寻找未来的同事。 如何准备校招技术面试 标签 : 面试 [TOC] 2017 年互联网校招已近尾声,作为一个非 CS 专业的应届生,零 ACM 经验、零期刊论文发表,我通过自己的努力和准备,从找实习到校招一路运气不错,面试全部通过,谨以此文记录我的校招感悟。 写在前面 写作动机 ...

    MkkHou 评论0 收藏0
  • 一位大佬的亲身经历总结:简历和面试的技巧

    摘要:我觉得了解简历和面试的技巧可以帮助你更好的去学习重要的知识点以及更好地去准备面试以及面试,说实话,我个人觉得这些东西还挺重要的。在本文里,我将介绍我这段时间里更新简历和面试的相关经历。 分享一篇很不错的文章!本文作者曾经写过《Java Web轻量级开发面试教程》和 《Java核心技术及面试指南》这两本书。我觉得了解简历和面试的技巧可以帮助你更好的去学习重要的知识点以及更好地去准备面试以...

    pingan8787 评论0 收藏0
  • 我是如何准备阿里的社招面试,给准备java社招的朋友的一个建议!

    摘要:第一个问题阿里面试都问什么这个是让我最头疼的一个问题,也是群里的猿友们问的最多的一个问题。我参加的是阿里的社招面试,而社招不同于校招,问题的范围其实是很随机的。所以,不妨就这两个阶段,谈谈社招面试的准备,而不是去把阿里面试的过程背一遍。 引言其实本来真的没打算写这篇文章,主要是记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来。自己当初面试完以后,除...

    BoYang 评论0 收藏0
  • 求职准备 - 收藏集 - 掘金

    摘要:一基础接口的意义百度规范扩展回调抽象类的意义想不想通过一线互联网公司面试文档整理为电子书掘金简介谷歌求职记我花了八个月准备谷歌面试掘金原文链接翻译者 【面试宝典】从对象深入分析 Java 中实例变量和类变量的区别 - 掘金原创文章,转载请务必保留原出处为:http://www.54tianzhisheng.cn/... , 欢迎访问我的站点,阅读更多有深度的文章。 实例变量 和 类变量...

    cuieney 评论0 收藏0

发表评论

0条评论

chanjarster

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<