文章目录
- 声明
- Java与C++的区别
- JRE和JDK的区别
- 为什么说Java程序一次编译,处处运行?
- 基本数据类型有哪些?占用的字节?
- Java中有了基本类型为什么还需要包装类?
- 包装类的缓存机制
- 什么是自动装箱和拆箱?原理是什么?
- 哪些场景会用到装箱和拆箱
- 为什么浮点数运算的时候会有精度丢失的风险?
- 为什么不能用BigDecimal的equals方法做等值比较?
- BigDecimal(double)和BigDecimal(String)有什么区别?
- 重载和重写的区别
- 面向对象的三大特征
- 如何理解Java中的多态?
- 为什么Java不支持多继承?
- 接口和抽象类有什么区别?
- 深拷贝和浅拷贝
声明
Java与C++的区别
- 平台无关性:Java是可以跨平台的语言,C++依赖于特定的平台
- 指针:Java不提供指针直接访问内存,程序内存更加安全
- 继承:Java类只支持单继承,C++支持多重继承
- 重载:C++支持方法重载和操作符重载,但是Java只支持方法重载
- 垃圾回收:Java有自动内存管理垃圾回收机制,不需要程序员手动释放内存
JRE和JDK的区别
- JDK是提供给开发者使用,能够创建和编译Java程序的开发套件,它包含了JRE,同时还包含了编译Java源码的编译器javac以及一些其他工具比如javadoc(文档注释工具)、jdb(调试器)、jconsole(可视化监控工具)、javap(反编译工具)等等
- JRE是Java运行时环境,他是运行已编译Java程序所需的所有内容的集合,主要包括Java虚拟机(JVM),java基础类库(Class Libiary)
- 总的来说JRE是Java运行时环境,仅包含Java应用程序的运行环境和必要的类库,JDK包含了JRE同时还包括了javac、javadoc、jdb、javap等工具,可以用于java应用程序的开发和调试
为什么说Java程序一次编译,处处运行?
Java通过其’编译一次,到处运行’的理念实现了平台无关性。这个理念主要依赖于Java虚拟机和字节码的设计。
- Java的源代码首先通过编译器(javac)编译成字节码(.class)文件,字节码是一种中间表示形式,与具体的硬件平台无关,可以在任何支持JVM的环境中运行
- 每种操作系统和硬件平台都有对应的JVM实现,所有JVM都遵循Java虚拟机规范,确保字节码在不同平台上的一致性。
JVM提供一个抽象层,屏蔽了底层硬件和操作系统的差异,使得字节码可以在不同平台上运行.
基本数据类型有哪些?占用的字节?
首先要记住Java基础数据类型8种
- 整数类型
- byte Byte 1字节
- short Short 2字节
- int Integer 4字节
- long Long 8字节
- 浮点类型
- float Float 4字节
- double Double 8字节
- 字符类型
- char Character 2字节
- 布尔类型
- boolean Boolean Java规范未明确规定,通常实现为1字节
Java中有了基本类型为什么还需要包装类?
- Java是一种面向对象的语言,很多地方需要使用对象而不是基本数据类型,比如在集合类中,是无法将int、double等基本类型放进去的,因为集合的容器要求元素是Object类型
- 为了让基本类型也具有对象的特征,就出现了包装类型,使得它具有对象的性质,并且添加了属性和方法,丰富了基本类型的操作
包装类的缓存机制
- 介绍一下是什么:在类初始化的时,提前创建好会频繁使用的包装类对象,当需要使用某个类的包装类对象时,如果该对象包装的值在缓存的范围内,就返回缓存的对象,否则就创建新的对象并返回
- 怎么实现的:包装类的缓存机制是通过包装类中定义了一个静态数组cache[]来缓存常用的值
- 各类型区别:Byte、Short、Integer、Long默认范围为-127~128,但是Integer的最大值可以修改,Character默认范围为0~127。Float、Double、Boolean无缓存机制。
- 优点:
- 提高性能:避免重复创建相同的包装类对象,减少了内存开销和垃圾回收的压力
- 节省内存空间:对于常用的数值,在缓存范围内包装类对象可以被多个引用共享,减少了内存占用
- 缺点:
- 缓存范围有限:只是在特定的范围内才会被缓存,超出范围仍然要创建新对象
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
什么是自动装箱和拆箱?原理是什么?
- 装箱:将基本类型用它们对应的引用类型包装起来
- 拆箱:将包装类型转换成对应的基本类型
- 装箱其实就是调用了包装类的
valueOf()
方法,拆箱就是调用了xxxValue()
方法
哪些场景会用到装箱和拆箱
- 装箱:
- 将基本数据类型放入集合类
- 函数的参数与返回
- 拆箱:
- 包装类型和基本类型比较大小:先将包装类进行拆箱成基本数据类型再比较
- 包装类型的运算:两个包装类之间的运算,会被自动拆箱成基本类型进行
- 三目运算符的使用:当第二、三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作
为什么浮点数运算的时候会有精度丢失的风险?
- 计算机是二进制,并且计算机在表示一个数字的时候,宽度是有限的
- 对于无限循环小数来说,只能截断,所以就会导致小数精度发生损失
为什么不能用BigDecimal的equals方法做等值比较?
- 因为BigDecimal的equals方法会比较两部分内容,分别是值(intVal)和标度(scale),对于0.1和0.10这两个数字,他们的值虽然一样,但是精度是不一样的,所以在使用equals方法的时候会返回false
@Override
public boolean equals(Object x) {
// 检查传入的对象是否是BigDecimal类型,如果不是,返回false
if (!(x instanceof BigDecimal))
return false;
// 将传入的对象强制转换为BigDecimal类型
BigDecimal xDec = (BigDecimal) x;
// 如果传入的对象和当前对象是同一个对象,返回true
if (x == this)
return true;
// 比较两个BigDecimal对象的scale(小数位数),如果不同,返回false
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED) {
return xs == compactValFor(this.intVal);
}
return this.inflated().equals(xDec.inflated());
}
BigDecimal(double)和BigDecimal(String)有什么区别?
- double本身是不精确的,所以使用一个不精确的数字来创建BigDecimal,得到的数字也是不精确的。例如0.1这个数字,double只能表示它的近似值。所以当new BigDecimal(0.1)创建一个BigDecimal的时候,其实创建出来的值并不是正好等于0.1的。而是0.1000000000000000055511151231257827021181583404541015625。这是因为double自身表示的只是一个近似值。
- 对于BigDecimal(String),当我们使用new BigDecimal(“0.1”)创建一个BigDecimal的时候,创建出来的值就是等于0.1的,它的标度就是1。
重载和重写的区别
时间原因,后续会更新
面向对象的三大特征
- 封装:把一个对象的状态信息(也就是属性)封装在对象的内部,不允许外部的对象直接访问对象的内部信息,但是可以提供一些被外界访问的方法来操作属性。
- 继承:在已有类的基础上建立新类,新类的定义可以增加新的属性和方法,也可以用父类的方法,但是不能选择性的继承。
- 子类拥有父类的所有属性和方法(包括私有方法和私有属性),但是父类的私有方法和私有属性子类无法访问
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
- 子类可以用自己的方式去重写父类的方法
- 多态:表示一个对象具有的多种状态,具体表现为父类的引用指向子类的实例
- 对象类型和引用类型之间具有继承/实现的关系
- 引用类型发出的方法调用到底是哪个类的方法,必须在程序运行期间才能确定
- 多态不能调用只在子类存在而在父类不存在的方法
如何理解Java中的多态?
- 多态就是相同的操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
- 需要满足下面三个条件
- 存在类继承或接口实现
- 子类重写父类的方法
- 父类的引用指向子类的实例
为什么Java不支持多继承?
后续会更新
接口和抽象类有什么区别?
- 方法定义:接口中的方法必须是抽象方法,抽象类可以拥有普通的成员变量和成员方法
- 修饰符:抽象类中修饰符可以有public、protected、private,接口中默认的修饰符是public,不可以用其他的修饰符进行修饰
- 构造器:抽象类可以有构造器,接口不能有构造器
- 继承和实现:一个类可以实现多个接口,但是只能继承一个抽象类
- 接口主要用于制定规范,抽象类是为了代码的复用
深拷贝和浅拷贝
- 浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
- 深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象
- 引用拷贝:引用拷贝就是两个不同的引用指向同一个对象