java语言特点(与C++对比)
继承、编译型解释型、多线程、网络编程、指针、GC、运算符重载
JDK JVM JRE
标识符与关键字
default的特殊性
静态方法为什么不能调用非静态成员?(结合JVM相关知识解释)
- 静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
- 在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
重载和重写
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理(发生在同一个类中或父类和子类之间)→重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法
重写的限制(两同两小一大):
重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。
- 方法名、参数列表必须相同,子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
- 如果父类方法访问修饰符为private/final/static则子类就不能重写该方法,但是被static修饰的方法能够被再次声明。
- 构造方法无法被重写
综上:重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
hashCode() 与 equals()
比较相等:
- 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
- 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。
- 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。
为什么重写equals也要重写hashCode方法?
因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。 如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。
可变长参数
从 Java5 开始,Java 支持定义可变长参数。可变参数只能作为函数的最后一个参数。
遇到方法重载的情况会优先匹配固定参数。固定参数的方法匹配度更高。
Java 的可变参数编译后实际会被转换成一个数组。
基本数据类型及对应的包装类
- 6 种数字类型:
- 4 种整数型:byte、short、int、long
- 2 种浮点型:float、double
- 1 种字符类型:char
- 1 种布尔型:boolean
(注意char占两个字节)
对于 boolean,官方文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1 位,但是实际中会考虑计算机高效存储因素。
Java 的每种基本类型所占存储空间的大小不会像其他大多数语言那样随机器硬件架构的变化而变化。这种所占存储空间大小的不变性是 Java 程序比用其他大多数语言编写的程序更具可移植性的原因之一。
包装类的常量池技术
Java 基本类型的包装类的大部分都实现了常量池技术。 (valueOf()的底层实现)
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。
如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。
两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。
例子:
Integer i1=40 这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40) 。因此,i1 直接使用的是常量池中的对象。而Integer i2 = new Integer(40) 会直接创建新的对象。
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
自动装箱与拆箱(原理)
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
装箱其实就是调用了 包装类的valueOf()方法,拆箱其实就是调用了 xxxValue()方法