在Java中要想实例化一个对象必须调用构造器,调用构造器这个类必须在jvm已经被加载了,在类加载和对象初始化的过程有些顺序问题是值得我们去留意的。
一个Java类中主要包含以下几部分:
静态代码块:在类加载完的时候就执行可以调用静态成员,在整个类的生命周期只执行一次,优先于该类中的main方法执行。
静态属性、静态方法:随着类的加载而加载,类加载了静态变量静态方法就存在了,是所有对象所共享的。
构造代码块:每次实例化对象都会执行且优先于构造方法。
构造方法:实例化对象是调用。
成员变量:普通变量。
成员方法:普通方法。
这些部分中构造器是必须的,一个类默认有一个无参数的构造器,如果自定义了一个有参数的构造器,那无参构造器就没了需要显式的写出来。
下面我们就来看下,实例化一个对象会经历那些步骤。
package com.lcx.tj.test;
/**
*
* @author
*/
class Father {
private String name = "张三";//姓名,显式赋值初始化
private String job = "老师";//职业,显式赋值初始化
//测试默认初始化
String String_;
Father Father_;
byte byte_;
short short_;
int int_;
long long_;
float float_;
double double_;
char char_;
boolean boolean_;
//静态代码块,在类加载完的时候就执行可以调用静态成员,在整个类的生命周期只执行一次,优先于该类中的main方法执行。
static {
System.out.println("Father静态代码块 begin------------");
System.out.println("调用静态方法doSometing");
doSometing();
sex = "男";
System.out.println("Father静态代码块 over------------");
}
/*
* 静态属性、静态方法随着类的加载而加载
*/
public static final String sex;
public static void doSometing(){
System.out.println("Father静态方法doSometing:照顾小孩");
}
{//构造块,每次实例化对象都会执行且优先于构造方法
System.out.println("Father构造块");
}
public Father(){
System.out.println("Father无参数构造器");
}
public Father(String name, String job) {
System.out.println("Father有参数构造器");
this.name = name;
this.job = job;
}
//主方法
public static void main(String[] args) {
System.out.println("Father主方法");
/**
* 1、类首次加载 静态属性静态方法已经存在,执行静态代码块
* 2、实例化对象时 会先执行构造块 然后调用构造器
* 需要注意:
* 调用构造器生成对象时,非静态属性会先进行赋值初始化,如果没有赋值就会采取默认初始化,如果是对象默认初始化为null如果是基本类型会初始化为相应的值。
* 但是我们在普通的方法中定义了基本类型或者对象没有进行显式的赋值初始化就去使用 是会编译出错的。
*/
//没有进显式的赋值初始化就去使用 会编译报错的。
// Father f8 ;
// f8.toString();
// int i;
// System.out.println(i);
Father f1 = new Father();
System.out.println("Father toString():"+f1);
Father f2 = new Father("李四", "程序员");
System.out.println("Father toString():"+f2);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Father [name=" + name + ", job=" + job + ", String_=" + String_ + ", Father_=" + Father_ + ", byte_="
+ byte_ + ", short_=" + short_ + ", int_=" + int_ + ", long_=" + long_ + ", float_=" + float_
+ ", double_=" + double_ + ", char_=" + char_ + ", boolean_=" + boolean_ + "]";
}
}
程序运行结果:
如果这个有一个子类呢?在实例化子类对象的时候 顺序又是咋样的呢?那我们接下再瞅瞅。
先看下子类代码:
class Son extends Father{
private String grade;//班级
//静态代码块,在类加载完的时候就执行可以调用静态成员,在整个类的生命周期只执行一次,优先于该类中的main方法执行。
static {
System.out.println("Son静态代码块");
}
{//构造块,每次实例化对象都会执行且优先于构造方法
System.out.println("Son构造块");
}
public Son() {
super();
System.out.println("Son无参数构造器");
}
public Son(String grade,String name,String job) {
super(name,job);
System.out.println("Son有参数构造器");
this.grade = grade;
}
//静态属性
public static final String like = "小女孩";
//静态方法
public static void doSometing(String a){
System.out.println("Son学习");
}
//主方法
public static void main(String[] args) {
System.out.println("Son主方法");
Son s1 = new Son();
System.out.println("Son toString:"+s1);
Son s2 = new Son("五年级", "王五", "学生");
System.out.println("Son toString:"+s2);
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Son [grade=" + grade + ", getName()=" + getName() + ", getJob()=" + getJob() + "]";
}
}
程序运行结果:
最后我们总结一下初始化一个对象要经历那些步骤,其实很简单, 如果类是首次加载 就先加载类 然后调用 构造器就OK。
加载类class执行静态代码块-->类构造块-->类构造器。
如果是子类实例化的话,其实也一样,只不过 先有父对象在 再才有子对象,所有 先加载父类class再加载子类class 然后 先调用父构造器 再调用子构造器。
加载父类class执行父类静态代码块-->加载子类class执行子类静态代码块-->父类构造块-->父类构造器-->子类构造块-->子类构造器。
以上均是个人的一些理解哈,如果有不对的地方敬请指教。