<Java><!!!><面试题>
装箱 & 拆箱
public class Test03 {
public static void main(String[] args) {
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);
System.out.println(f3 == f4);
}
}
这个题有几个知识点要明确:1)上面4个变量都是object,所以 == 比较的不是值,而是引用。2)要清楚装箱的本质:我们给一个Integer赋int值的时候,会调用Integer类的静态方法valueOf,该方法的源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
其中IntegerCache是Integer的内部类,如果整形字面量的值在-128 ~ 127之间,那么就不会new新的Integer对象,而是直接引用常量池中的Integer对象。
综上,答案是 true & false。
2. 内存中的栈、堆和方法区的用法(JVM)
通常我们定义一个基本数据类型的变量,一个对象的引用,以及函数调用的现场都保存在JVM的栈中。而通过new关键字和构造器创建的对象则放在堆中。
堆是垃圾收集器管理的主要区域由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured。
- 堆、栈、方法区的区别:
- 栈由系统自动分配释放,使用一级缓存,它们通常是被调用时处于存储空间,调用完毕立即释放;每个线程都有一个栈区,只保存基础数据类型和对象的引用。栈分为三个部分:基本类型变量区、执行环境上下文、操作指令区。
- 堆由程序员分配释放,使用二级缓存,生命周期由虚拟机的垃圾回收算法来决定。jvm只有一个堆区,被所有线程共享,堆中只存放对象本身。
- 方法区又叫静态区,也被所有线程共享。方法区包含所有的class和static变量。
- 堆、栈、方法区的区别:
以上,栈空间操作起来最快,但是栈很小,通常大量对象都是放在堆空间,栈和堆的大小都可以通过JVM启动参数来调整。栈用完会引发StackOverflowError,而堆和常量池空间不足会引发OutOfMemoryError。
String str = new String("hello");
上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而"hello"这个字面量是放在方法区的。
3. 用最有效率的方法计算2乘以8?
答: 2 << 3。在HashCode()的源码中,hashCode的公式是 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] ,为什么这里要使用31?这里有两个考虑:
- 31是素数(质数),使用素数可以降低冲突概率;
- 31 * num 等价于(num << 5) - num,左移5位相当于乘以2的5次方再减去自身就相当于乘以31,现在的VM都能自动完成这个优化。
4. equals & hashCode
两个对象值相同(x.equals(y) == true), 那它们可能有不同hash code吗?
答:不能。Java规定,若两个对象相同(equals返回true),那么它们的hashCode一定相同。但是相反不一定成立。
当然,你未必一定按要求去做,但是如果你违背了上述原则就会发现使用在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(hashCode频繁冲突造成的存取性能急剧下降)。
关于equals方法:必须满足自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(当x和y引用的对象信息没有被修改时,多次调用x.equals(y)应该得到同样的返回值),而且对于任何非null值的引用x,x.equals(null)必须返回false。
5. 如何实现对象克隆
有两种方式:
1)实现Cloneable接口并重写Object类中的clone()方法;
2)实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。[implements Serializable接口,实现toString()方法]
6. GC
Java提供的gc功能可以自动监测对象是否超过作用域,从而达到自动回收内存的目的。可以通过System.gc()或Runtime().gc()请求垃圾收集,但是JVM可以屏蔽掉显式地垃圾回收调用。
垃圾回收通常作为一个低优先级的线程运行。垃圾回收机制有很多种,包括分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
- - 伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
- - 幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
- - 终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
7. Java类加载机制
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
上面这段代码的执行结果是1a2b2b。
类加载机制的相关知识比较多一点,专门整理了一篇博客 点我点我点我
8. String
private void testString(){
String s1 = "Programming";
String s = "Programming";
String s2 = new String("Programming");
System.out.println(s2.getClass().toString());
String s3 = "Program";
String s4 = "ming";
String s5 = "Program" + "ming";
String s6 = s3 + s4;
System.out.println(s1 == s); // true
System.out.println(s1 == s2); // false
System.out.println(s1 == s5); // true
System.out.println(s1 == s6); // false
}
对于上述代码:
- s == s1,很好理解,因为他俩都是字符串常量,指向常量池中的同一块空间;
- s1 != s2, 因为s2是在堆中new出来的一块内存
- s1 == s5,因为s5也是字符串常量,编译时被确定,仍然与s1指向同一块常量池空间;
- s1 != s6, 这里由于s3和s4的拼接需要额外创建一个StringBuffer(或StringBuilder),之后再将StringBuffer转换为String,此处很明显new了一个对象,因此是在堆中进行的。(最后得到的s6是StringBuilder.toString()的返回值。看了下源码,返回的是 return new String(value, 0, count);
这里有一个很重要的点,既然直接用 + ,底层也会用StringBuilder去实现,那么为什么在实际中我们通常会说用StringBuilder,而不去用 + 呢?考虑的是这样的情况:
public class Test4 {
public static void main(String[] args) {
String s = "s";
for (int i = 0; i < 20; i++) {
s += i;
}
}
}
上述代码中,用String+的方式,每循环一次,就会重新new一个StringBuffer对象,这样的内存消耗完全是不必要的(在数据量大的情况下,还会导致内存不足的错误)。# 据说字符串的加法是java唯一一个实现了运算符重载的地方。
<Java><!!!><面试题>的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- POJ-3693/HDU-2459 Maximum repetition substring 最多重复次数的子串(需要输出具体子串,按字典序)
http://acm.hdu.edu.cn/showproblem.php?pid=2459 之前hihocoder那题可以算出最多重复次数,但是没有输出子串.一开始以为只要基于那个,每次更新答案的时 ...
- jenkins+maven+git+tomcat+salt自动构建
jenkins 安装步骤 环境: centos7,jdk1.8.0,jenkins2.165,maven3.5.2 一. 安装配置java环境 JDK1.8下载地址:http://www.orac ...
- mac 配置homebrew
1.终端下输入export PATH=/usr/local/bin:$PATH 2.echo $PATH 3.安装homebrew 地址:ruby -e "$(curl -fsSL htt ...
- python记录_day27 tcp/ip五层模型
## 网络协议按照不同的功能分为多层,目前存在的模型有osi七层模型.tcp/ip五层和tcp/ip四层模型 我们主要用的是tcp/ip五层模型 那么每层的作用是什么呢,现在就从设计者的角度自下到上逐 ...
- 四则运算Java语言实验设计过程1
题目要求: 像二柱子那样,花二十分钟写一个能自动生成三十道小学四则运算题目的 “软件”.要求:除了整数以外,还要支持真分数的四则运算(需要验证结果的正确性).题目避免重复.可定制出题的数量. 设计思路 ...
- 杂记-格式化Date默认格式,日期加一天,jstl判断字符类型,ajax模拟from表单后台跳转页面,jstl访问数据库并在页面显示
1.格式化Date默认格式 String str="Sun Oct 08 22:36:45 CST 2017"; SimpleDateFormat sdf = new Simple ...
- 为什么要使用oath协议?
一.如何查看用户是否登录? 通过cookie和session来查看用户是否登录. 如果cookie对应的session中保存了用户登录信息,则判定用户已登录 Jsessionid,也就是tomcat自 ...
- for循环的字节码
源代码: public class Wizard { private int age; private void forCycle() { for (int i = 0; i < 10; i++ ...
- QPainter、QPainterPath、QBrush
参考资料: https://blog.csdn.net/qq_35488967/article/details/70802973https://blog.csdn.net/wanghualin033/ ...
- win7 忘记密码
你可以找个PE来修改密码,用光盘或U盘做PE都行,现在很多PE都支持密码修改的!不过下面这个方法还是要用到PE:1. 进入pe2.进入c:\windows\system32下 更改magnify.ex ...