基本概念
成员与初始化
- 对象是数据和行为的集合(主观能动性)
- 一切使用new运算符创造出来的都是对象
- new Object()
- 特例 new Integer() \ new String() \ new Object[]
- 所有对象都在内存堆上被分配
- 每个对象都包含自己的数据(成员变量)
- 原生类型的成员,保存于对象开辟的内存空间中
- 引用类型的成员,再对象开辟的内存空间中保存了一个地址
- 新建对象的过程是
- 再堆上分配空间
- 执行必要的初始化工作,成员赋默认值
- 执行构造器函数,如果没有构造器,编译器自动生成一个
其他概念
重载overload与重写\覆盖(overide)是不同的
- 重载可以使用相同的方法名,但参数表类型不同(仅仅返回值不同是不行的)
- 当遇到类型自动装箱问题,最匹配的的优先(方法重载的顺序),如果多个类型匹配优先级相同,会有歧义bug(取决于继承树顺序)
null 没有类型,发生匹配歧义时,需要对null先进行强制类型转换
public class Main {
public static void main(String[] args) {
// 实际调用的方法是print(HashMap)
print((HashMap)null);
}
public static void print(int i) {
System.out.println("I'm int!");
}
public static void print(Integer i) {
System.out.println("I'm Integer!");
}
public static void print(Number i) {
System.out.println("I'm Number!");
}
public static void print(Object i) {
System.out.println("I'm Object!");
}
public static void print(HashMap i) {
System.out.println("I'm HashMap!");
}
}
仅仅返回值不同是不能重载的,因为java允许忽略返回值对函数进行调用,此时会产生歧义(但这种情况在jvm中是合法的)
- 方法参数的默认值常需要重载实现,比如在void返回值类型的函数中调用其他参数类型的同名函数,此时提供指定参数值,如下段构造器默认值的实现方案,HashMap API也使用此方式
public class Cat {
int age;
String name;
// 创建一只默认的猫,1岁,名为张三
public Cat(){
this("张三"); // 调用第二个构造器
}
// 创建一只默认的猫,1岁,名为name
public Cat(String name){
this(1,name);// 调用第三个构造器
}
// 创建一只有age和name的猫
public Cat(int age,String name){
this.age = age;
this.name = name;
}
}
对象的初始化顺序
- 划分内存空间
- 必要的初始化工作顺序
- 静态成员的初始化
- 静态初始化块
- 成员的初始化
- 初始化块
执行构造器函数
public class Cat {
// 静态部分,不属于任何对象,执行顺序在main函数的调用前面(对main函数分析完就先执行了,main函数栈帧还未被压栈)
// 最先执行的是类的静态部分
static int a = 123;
static {
}
// 成员部分
int age = 1;
String name = "张三";
{
for(int i = 0; i<5; i++){
age += i;
}
}
public Cat(int age,String name){
this.age = age;
this.name = name;
}
public static void main(String[] args){
new Cat(2,"ABC");
}
}
对象的生命周期
- jvm通过GC roots沿引用链可达的对象都是活对象,其他被判断没有被引用的对象被执行垃圾回收机制对其进行回收
- 没有被引用的对象,jvm的GC(Garbage Collection)会结合内存压力等情况自动判断是否对其回收
一直创建对象可能引起爆内存Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
public class Main {
public static void main(String[] args) {
// 请想办法在这里写一些代码,占用尽可能多的内存,令JVM抛出内存不足的OutOfMemoryError异常
Object[] array = new Object[10000];
for (int i = 0; i < 10000; i++) {
array[i] = new byte[1024 * 1024];
}
}
}
GC回收时机
- Allocation Failure 在堆内存中分配时,如果因为可用剩余空间不足导致对象内存分配失败,这时系统会触发一次GC
- System.gc() 在应用层,Java开发工程师可以主动调用此API来请求一次GC