前言

最近无聊的在逛某 tube 网站,本来想看看大家是怎么吐槽川普的,结果无意间点进了一个老外面试 Java 的视频,对于常年面试被吊打的我瑟瑟发抖,于是决定进去一探究竟。

毕竟不是专业的后台开发,所以我在面试到后台知识的时候果断的退了出来,才让自己免受了侮辱。

不过鉴于我手速出众,飞速的记录下了 Java 的基础题,所以准备贡献出来,供大家享乐。

鉴于题目比较多,会分成上下 2 篇 来整理,主要是面对 Java 的基础,看看老外的面试题和我们有什么区别。

当然问题是老外问的,答案是我编的。

正文

Java 中有哪些可用的分配内存

Java 虚拟机在执行程序时候会将内存划分为不同的数据区域

  • 方法区 - Method Area

    • 方法区(Method Area)与 Java 堆一样,是所有线程共享的内存区域。
    • 虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫 Non-Heap(非堆),目的应该是与 Java 堆区分开。
    • 运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本/字段/方法/接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将类在加载后进入方法区的运行时常量池中存放。运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的是 String.intern() 方法。受方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。
    • 方法区的大小和堆空间一样,可以选择固定大小也可选择可扩展,方法区的大小决定了系统可以放多少个类,如果系统类太多,会导致方法区溢出,虚拟机同样会抛出内存溢出错误
    • JVM 关闭后方法区即被释放
  • 堆 - Heap Area
    • 对于大多数应用,Java 堆是 Java 虚拟机管理的内存中最大的一块,被所有线程共享。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数据都在这里分配内存。
    • Java 虚拟机规范规定,Java 堆可以是处于物理上不连续的内存空间中,只要逻辑上是连续的即可,像磁盘空间一样。实现时,既可以是固定大小,也可以是可扩展的,主流虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制),如果堆中没有完成实例分配,并且堆无法再扩展时,就会抛出 OutOfMemoryError 异常。
  • 栈 - Stack Area
    • 栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器
    • JVM 直接对虚拟机栈的操作只有两个:每个方法执行,伴随着入栈(进栈/压栈),方法执行结束出栈
    • 栈不存在垃圾回收问题
  • 程序计数器 - Program Counter Register
    • 它是一块很小的内存空间,几乎可以忽略不计。也是运行速度最快的存储区域
    • 在 JVM 规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期一致
    • 任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。如果当前线程正在执行的是 Java 方法,程序计数器记录的是 JVM 字节码指令地址,如果是执行 native 方法,则是未指定值(undefined)
    • 它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
    • 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
    • 它是唯一一个在 JVM 规范中没有规定任何 OutOfMemoryError 情况的区域
  • 本地方法栈 - Native Method Stack Area
    • Java 虚拟机栈用于管理 Java 方法的调用,而本地方法栈用于管理本地方法的调用
    • 本地方法栈也是线程私有的
    • 允许线程固定或者可动态扩展的内存大小
      • 如果线程请求分配的栈容量超过本地方法栈允许的最大容量,Java 虚拟机将会抛出一个 StackOverflowError 异常
      • 如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么 Java虚拟机将会抛出一个 OutofMemoryError 异常
    • 它的具体做法是 Mative Method Stack 中登记 native 方法,在 Execution Engine 执行时加载本地方法库当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有同样的权限。
    • 并不是所有 JVM 都支持本地方法。因为 Java 虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方式、数据结构等。如果 JVM 产品不打算支持 native 方法,也可以无需实现本地方法栈
    • 在 Hotspot JVM 中,直接将本地方法栈和虚拟机栈合二为一

如果我写 static public void main,程序还会运行吗?

刚看到这个题目的时候懵逼了,在国内面试真没见过这么问的,所以还是有些不确定,所以赶紧搜索。

在 Java 中的修饰符出现在字段声明中时的顺序与 oracle 规定的 FieldModifier 顺序一致,这是习惯顺序,形成规范。不遵守这个约定没有技术影响,但是会降低代码的可读性,因为大多数开发人员都习惯于标准顺序。

所以程序变成 static public void main() 也可以运行。

下面仅列举方法修饰符:

局部变量中的默认值是什么?

在 Java 中的局部变量不会初始化。

public class staticFactory {
public static void main(String[] args) {
int temp;
System.out.println(temp);
}
}
// 打印信息:Error:(10, 28) java: 可能尚未初始化变量 temp

如果是静态变量不赋值,会直接默认值为 0

public class staticFactory {
static int temp;
public static void main(String[] args) {
System.out.println(temp);
}
}
// 打印值为 0

如果是成员变量

public class staticFactory {
public static void main(String[] args) {
LocalVariables obj = new LocalVariables();
System.out.println("a="+obj.a);
System.out.println("b="+obj.b);
System.out.println("c="+obj.c);
System.out.println("d="+obj.d);
}
}
class LocalVariables {
int a;
char b;
float c;
String d;
}
/*
打印结果:
a=0 int 默认值为 0
b="" char 默认值为 ""
c=0.0 float 默认值为 0.0
d=null String 默认值为 null
*/

在 Java 中如何拷贝构造函数

Java 中的拷贝构造方法是一种使用该类的一个对象构造另外一个对象的构造方法。

如何创造拷贝构造方法

// 要创建拷贝构造方法,首先需要声明带有和本类相同类型的参数构造函数:
public class Employee {
private int id;
private String name; public Employee(Employee employee) { }
}
// 然后,将参数对象的每个属性都复制给新的实例。
public class Employee {
private int id;
private String name; public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
}
}

上面的做法属于浅拷贝。

上面定义的属性是基本类型和不可变类型 (int 和 String),因此使用前拷贝就没问题。

但是如果类中包含可变类型就要通过该构造函数实现深拷贝。

为了实现深拷贝,我们需要根据原始可变对象类型构造新的实例。

public class Employee {
private int id;
private String name;
private Date startDate; public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
this.startDate = new Date(employee.startDate.getTime());
}
}

什么是标记接口

标记接口是没有任何方法和属性的接口,它仅仅表明它的类属于一个特定类型,供其他代码测试允许做一些事情。并且标记接口不是 Java 这门语言特有的,而是计算机科学中的一种通用化的设计理念。

使用标记接口的唯一目的是使得可以用 instanceof 进行类型查询,例如:

if (obj instanceof Cloneable) {………}

在 Java 中,有一个常用的标记接口类

  • java.io.Serializable:未实现此接口的类将无法使其任何状态序列化或反序列化。为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。
  • java.lang.Cloneable:表明 Object.clone() 方法可以合法地对该类实例进行按字段复制。实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。
  • java.util.RandomAccess:用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
  • java.rmi.Remote:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。

为什么 Java 不完全面向对象

首先什么才是纯面向对象语言?

纯面向对象语言或完全面向对象语言是指完全面向对象的语言,它支持或具有将程序内的所有内容视为对象的功能。它不支持原始数据类型(如 int,char,float,bool 等)。编程语言满足七种标准可以就可以称为纯粹的面向对象语言,他们是:

  1. 封装 / 数据隐藏
  2. 继承
  3. 多态性
  4. 抽象化
  5. 所有预定义类型都是对象
  6. 所有用户定义的类型都是对象
  7. 对对象执行的所有操作必须仅通过对象公开的方法

为什么 Java 不是纯面向对象语言?

Java 支持属性 1、2、3、4 和 6 但不支持上面给出的 5 和 7。 Java 语言不是纯面向对象语言,因为它包含以下属性:

原始数据类型例如对象:

Smalltalk 是一种 “纯粹的” 面向对象的编程语言,与 Java 和 C++ 不同,因为作为对象的值和作为基本类型的值之间没有区别。在 Smalltalk 中,原始值,例如整数,布尔值和字符也是对象。在 Java 中,我们将预定义类型作为非对象 (基本类型)。

int a = 5;
System.out.print(a);

static 关键字:

当我们将一个类声明为 static 时,可以在不使用 Java 中的对象的情况下使用它。

以上两点可以解释为什么 Java 不是完全面向对象。

你能在 Java 程序中实现指针吗

Java 虚拟机隐式地负责内存管理。Java 的主要格言是保持编程简单。因此,不建议直接通过指针访问内存。所以,指针在 Java 中被消除了,Java 中并没有指针。

解释一下 Java String 池

在 Java 的堆内存空间中,有一块区域用来存放 Java 字符串池。当需要创建一个新的字符串的时候,JVM 首先检查对象是否存在于字符串池中,如果存在,这个引用的对象将指向该变量,如果不存在则创建一个新对象。

由于String实例对象不可修改,因此,“多个 String 实例对象引用变量引用同一个 String 实例对象”在节省 Java 堆内存的情况下,并不会带来任何问题。

直接赋值的方式

使用 new 的方式

  • 此时,如果判断 S1 == S2 是否相等是返回 true 的,因为他们指向同一个值。
  • 如果判断 S3 == S4 是否相等返回 false,因为他们比较的是 S3 和 S4 的地址。

当 main() 方法没有生命成静态会发生什么?

main() 方法是 Java 程序的入口,也可以理解为一个接口,在 java 编程中,JVM 会查找类中的 public static void main ( String [] args ),如果找不到该方法就抛出错误 NoSuchMethodError:main 程序终止。main() 方法必须严格遵循它的语法规则,方法签名必须是 public static void,参数是字符串数组类型。

当然还有其他一些意义:

  • 正因为 main() 方法是静态的,JVM 调用这个方法就不需要创建任何包含这个 main() 方法的实例。
  • 因为 C 和 C++ 同样有类似的 main() 方法作为程序执行的入口。
  • 如果 main() 方法不声明为静态的,JVM 就必须创建 main() 类的实例,因为构造器可以被重载,JVM 就没法确定调用哪个 main() 方法。
  • 静态方法和静态数据加载到内存就可以直接调用而不需要像实例方法一样创建实例后才能调用,如果 main() 方法是静态的,那么它就会被加载到 JVM 上下文中成为可执行的方法。

总结

以上可以看的出来,老外的面试的偏向性和我们还是有些区别的,这些题有一半在我们的面试中是不常问到的,所以取长补短。

你见过老外的 Java 面试题吗 (上)?的更多相关文章

  1. 你见过老外的 Java 面试题吗(下)?

    前言 上一篇文章总结了 老外常见的 Java 面试题上,如果有感兴趣的同学可以点击查看,接下来补上下半部. 正文 finalize 方法调用了多少次 关于 finalize 总结了以下几点: fina ...

  2. java面试题全集(上)

    1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...

  3. 发一些Java面试题,上海尚学堂Java学员面试遇到的真题,值得学习

    1. 下面哪些是Thread类的方法() A start()       B run()       C exit()       D getPriority() 答案:ABD 解析:看Java AP ...

  4. Java 面试题史上最强整理

    https://mp.weixin.qq.com/s/kJpRgfI3zT77XqMeRfmmQQ

  5. 年底了,该跳槽了,全套高级Java面试题及答案整理~

    又到年底了,又是一轮跳槽季 城外的人想进去,城里的人想出来 为什么离职? 马云说过,要么工资低,要么受了委屈 我想大多数人离职是这个原因 出来混的,跳槽也都是为了更好的生活 干技术的,工资都是跳出来的 ...

  6. Java笔试题解答和部分面试题

    面试类  银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...

  7. 尚学堂Java面试题整理

    博客分类: 经典分享   1. super()与this()的差别? - 6 -  2. 作用域public,protected,private,以及不写时的差别? - 6 -  3. 编程输出例如以 ...

  8. 金三银四季来了!Java 面试题大放送,能答对70%就去BATJTMD试试~

    摘要: 2019,相对往年我们会发现今年猎头电话少了,大部分企业年终奖缩水,加薪幅度也不如往年,选择好offer就要趁早,现在开始准备吧,刷一波Java面试题,能回答70%就去BATJTMD大胆试试~ ...

  9. 20 几个知名公司的 Java 面试题汇总

    查看不同公司新鲜真实的Java面试题,摘自Glassdoor.com 巴克莱投资: 假设有一个 getNextparson() 方法返回 Person 对象,Person 类实现了 comparabl ...

随机推荐

  1. 5.DHCP新建作用域及添加地址保留(Windows2012)

    1.新建作用域 右键IPv4 点击新建作用域 点击下一步 命名,下一步 填写子网,下一步 在上一步已经预留了,直接点下一步即可. 设置租用期限,建议为3天,下一步. 下一步,配置DHCP选项 配置默认 ...

  2. 利用PWM脉宽调制实现呼吸灯

    1.设计目标 完成一个呼吸灯,从亮到灭的时间为2秒,从灭到亮的时间为2秒,以此不断往复. 2.设计步骤 2.1设计分析 利用PWM(脉冲宽度调制)实现led灯亮度的变化,只需要改变占空比就可以实现,具 ...

  3. Joomla 3.4.6 RCE复现及分析

    出品|MS08067实验室(www.ms08067.com) 本文作者:whojoe(MS08067安全实验室SRST TEAM成员) 前言 前几天看了下PHP 反序列化字符逃逸学习,有大佬简化了一下 ...

  4. LCA算法——倍增

    概况 LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 实现过程 预处理:通过dfs遍历,记录每个节点到根节点的距离dis ...

  5. 2020 CCPC-Wannafly Winter Camp Day2

    2020 CCPC-Wannafly Winter Camp Day2 A 托米的字符串 虽然每个子串出现的概率是相同的,但是同一长度的子串个数是不同的,所以要分别处理.计算出某一长度的情况下,元音字 ...

  6. Grakn Forces 2020

    比赛链接:https://codeforces.com/contest/1408 A. Circle Coloring 题意 给出三个长为 $n$ 的序列 $a,b,c$,对于每个 $i$,$a_i ...

  7. Codeforces Gym-102219 2019 ICPC Malaysia National J. Kitchen Plates (暴力,拓扑排序)

    题意:给你5个\(A,B,C,D,E\)大小关系式,升序输出它们,如果所给的大小矛盾,输出\(impossible\). 题意:当时第一眼想到的就是连边然后排序,很明显是拓扑排序(然而我不会qwq,之 ...

  8. javascript——function类型(this关键字)

    如果不用分组的话,当用exec检测rar的时候会错误 结果: Function: 返回值为三(不推荐)

  9. Atcoder Educational DP Contest I - Coins (概率DP)

    题意:有\(n\)枚硬币,每枚硬币抛完后向上的概率为\(p[i]\),现在求抛完后向上的硬币个数大于向下的概率. 题解:我们用二维的\(dp[i][j]\)来表示状态,\(i\)表示当前抛的是第\(i ...

  10. Ancient Printer HDU - 3460 贪心+字典树

    The contest is beginning! While preparing the contest, iSea wanted to print the teams' names separat ...