本文主要包括Java基础及面向对象相关面试题。
JRE主要包含JVM,用于运行Java程序。
JDK包含了JRE,除此之外,包含了比如像javac等程序开发需要用到的工具。
先来说说什么是JDK,JRE。
JDK:Java Development Kit Java开发工具包【开发Java程序用】
JRE:Java Runtiome Environment Java运行环境【运行Java程序用】
【注:下载的JDK包是包含了JDK和JRE的,JDK和JRE是逻辑上的区分,两者在JDK下载的包中都有】
JDK与JRE的关系:以Java代码运行为例,编写好Java代码之后,通过javac将java源文件编译成class字节码文件,然后通过java命令,运行字节码文件。那么运行字节码的环境就是JRE。(JRE的核心就是JVM)
了解完JDK和JRE是什么之后,再聊聊为什么开发者当时要把一个安装包分成两部分呢?
平常使用的软件都是一键安装的,但JDK需要安装两次。JDK的发明者不会这么无聊,故意给开发者增加麻烦。
【我想】:这应该跟生产环境的部署问题有关,关于生产环境部署JDK还是JRE一直饱受争议,具体情况根据项目而定。
出于对性能的考虑,尽可能的使服务器轻,能少装一个软件就少装一个,这样生产环境部署JRE就OK了。【又省了资源】
除了这个方面之外,还有一种可能。JDK的开发也有可能是分团队的,JDK和JRE可能是交由不同团队开发,JDK和JRE的耦合也可能因此而减小,从而加快JDK的迭代版本。(毕竟现在JDK一年更新两次)
JVM有两个功能
- 将class字节码转换为机器码
- 兼容不同的操作系统
跨平台和Java 虚拟机有关。
JVM有两个主要的功能:
(Oracle官网上下载JDK,不同操作系统的JDK是不一样的,对应不同的虚拟机)
在解决这个问题之前,先来了解一些环境变量是干嘛的:
环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程。
简单来说,运行一个程序(命令),操作系统会从当前目录寻找,或者从环境变量中寻找。
换句话说,如果在java,javac的目录下执行这个两个命令,是没有问题的。但是如果更换了目录,系统在当前目录找不到,就会去环境变量中寻找。所以设置环境变量的根本目的是在电脑的任何一个文件夹下都可以编译运行Java程序。
题外话,Java和C++有什么区别?(据说有些面试官老爱干这种事)
表示变量:4个字节(转换为int存储)
表示byte数组:1个字节
float,double采用指数方式存储,能表示的数比long更大
System.out.println(Long.MAX_VALUE);
System.out.println(Float.MAX_VALUE);
System.out.println(Double.MAX_VALUE);
System.out.println(Float.MAX_VALUE>Long.MAX_VALUE);
9223372036854775807
3.4028235E38
1.7976931348623157E308
true
float和double使用指数表示,取值范围在
-3.4*10^38 - 3.4*10^38
顺便看看float和double的精度:7位和16位。
初始值:包装类型的初始值为null,基本数据类型的初始值基本上是0,char是'u000'
存储方式:包装类型存在堆里,基本数据类型存在栈中
- 可变性
String底层使用fina修饰的数组实现,是不可变的,StringBuffer和StringBuilder是可变的
- 安全性
String不可变,自然线程安全,StringBuffer使用synchronized同步锁实现线程安全,StringBuilder是线程不安全的
没有,只是指向了另外一个对象。
因为String被设计成不可变(immutable)类(final修饰),所以它的所有对象都是不可变对象。
在这段代码中,s原先指向一个String对象,内容是 "Hello",然后对s进行了+操作
这时,s不指向原来那个对象了,而指向了另一个 String对象,内容为"Hello world!"
原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。
前者会被JVM分配到常量池中,常量池中没有重复的元素,如果再次创建一个字符串变量等于i的话,就会直接指向常量池中的i。
后者是new了一个对象,堆中是允许对象重复的。
前者会被JVM分配到常量池中,常量池中没有重复的元素。
String str1 =“i”;
String str2 =“i”;
str2不会重新创建一个常量,而是指向str1。
String str1 = new String("i");
String str2 = new String("i");
str1会在堆内存中创建对象
str2还是会再次创建一个新的对象
使用StringBuilder或者StringBuffer的reverse()方法。
StringBuffer str1 = new StringBuffer("12345");
StringBuffer str2 = str1.reverse();
System.out.println(str2);
54321
equals用于比较内容是否相同(源自Object类,通常被重写)
==对于基本数据类型比较值相同,对于引用数据类型比较内存地址是否相同(是否是同一个对象)
知乎上非常形象的一张图:
& : 两边都为true时才为true
|:两边有一个为false即为false
短路逻辑运算符
&&:左边为fasle直接返回flase(不计算右边)
||:左边为true直接返回true(不计算右边)
就是为了简化计算量
^表示异或,相同为false,不同为true
如果摒弃软件开发的范畴,这是一种通过明确社会分工而提高效率的方法。
在软件开发的范围内,就是通过抽象出系统功能而实现最大化代码复用的开发模式。
equals和hashCode位于Object类中,所有的类都会继承Object类。
equals通常被用来比较对象的内容是否相同,hashCode是用来返回对象Hash值的一种方法。
如果不重写hashCode会导致,equals相同但hashCode不相同,equals不相同但hashCode相同。
重写的目的一来为了避免hash冲突,二来提高对象访问速度。