文章目录
前言
在平时我们创建一个对象的时候,往往都是一个new就完了,这篇文章只要讲的就是在初始化对象的时候,对象的属性,方法,构造方法,带static关键字的属性,还有方法块,等它们的初始化顺序是怎么样的。
先给出结果:
在不考虑继承的情况下:
静态属性和代码块随类的加载而加载,不需要创建对象也会加载。
所以加载的顺序是:
静态属性/代码块---->非静态属性和代码块---->构造器
属性和代码块的顺序与代码的顺序有关。
在考虑继承的情况下
同样静态属性和代码块会随类的加载而加载。
加载的顺序为:
父类静态代码块—>父类静态属性—>子类静态代码块—>子类静态属性—>父类非静态代码块—>父类非静态属性—>父类无参构造方法—>子类非静态代码块—>子类非静态属性—>子类无参构造方法
无继承情况下的对象
非静态属性,非静态代码块,构造器的初始化顺序
//对象
public class Oop {
public static void main(String[] args) {
Oop o = new Oop();
}
private Property pro = new Property("非静态属性") ;
{
System.out.println("非静态代码块");
}
public Oop(){
System.out.println("无参构造方法");
}
}
class Property {
public Property(String str) {
System.out.println("这是一个"+str);
}
}
运行结果:属性—>代码块—>构造器。
考虑到代码的初始化可能跟代码的顺序有关,我们将顺序做个调整
我们将构造器放在最前面,属性放在最后面
代码:
//对象
public class Oop {
public static void main(String[] args) {
Oop o = new Oop();
}
public Oop(){
System.out.println("无参构造方法");
}
{
System.out.println("非静态代码块");
}
private Property pro = new Property("非静态属性") ;
}
class Property {
public Property(String str) {
System.out.println("这是一个"+str);
}
}
结果:代码块—>属性—>构造器
由结果可知,构造器总是最后才初始化的,属性和代码块的初始化取决于他们的顺序。
非静态属性、代码块、构造器,和静态属性、静态代码块
我们将静态属性和代码块放到最后面
代码:
//对象
public class Oop {
public static void main(String[] args) {
Oop o = new Oop();
}
public Oop(){
System.out.println("无参构造方法");
}
{
System.out.println("非静态代码块");
}
static {
System.out.println("静态代码块");
}
private Property pro = new Property("非静态属性") ;
private static Property pro1 = new Property("静态属性") ;
}
class Property {
public Property(String str) {
System.out.println("这是一个"+str);
}
}
结果:静态代码块—>静态属性---->非静态代码块---->非静态属性---->构造器
考虑到上面出现的情况,属性和代码块的初始化顺序跟代码的顺序有关,我们可以得到结果,静态属性和代码块会先于非静态属性和代码块执行。
静态修饰的属性和方法只会初始化一次。
有继承情况下的对象
父类和子类-非静态属性、代码块、构造器,和静态属性、静态代码块
父类代码:
//对象
public class Oop {
public static void main(String[] args) {
Oop o = new Oop();
}
public Oop(){
System.out.println("父类无参构造方法");
}
{
System.out.println("父类非静态代码块");
}
static {
System.out.println("父类静态代码块");
}
private Property pro = new Property("父类非静态属性") ;
private static Property pro1 = new Property("父类静态属性") ;
}
class Property {
public Property(String str) {
System.out.println(str);
}
}
子类代码:
//子类
public class SunOop extends Oop {
public static void main(String[] args) {
Oop sunOop = new SunOop();
}
{
System.out.println("子类非静态代码块");
}
public SunOop(){
System.out.println("子类无参构造方法");
}
static {
System.out.println("子类静态代码块");
}
Property1 pro2 = new Property1("子类非静态属性");
static Property1 pro1 = new Property1("子类静态属性");
}
class Property1 {
public Property1(String str) {
System.out.println( str);
}
}
运行结果:父类静态代码块—>父类静态属性—>子类静态代码块—>子类静态属性—>父类非静态代码块—>父类非静态属性—>父类无参构造方法—>子类非静态代码块—>子类非静态属性—>子类无参构造方法
由此我们可以直到,在初始化子类的时候,会率先初始化父类的属性和方法。
下面我们再看一下,如果我们不创建对象,初始化的情况。
即main方法中不new对象
public static void main(String[] args) {
//Oop sunOop = new SunOop();
}
结果:
可以发现,在不new对象的情况下,static方法和属性也是会加载的。
关于static修饰的属性和方法
静态方法会随类的加载而加载。
只会初始化一次。
且在前面初始化。
看代码:
类代码:
package com.dyit.tanruike;
public class Pet {
//用来保存宠物
private static Pet[] pets = new Pet[10];
private static int index =0;
//宠物的名字
private String name ;
//添加宠物
public void add(String name) {
Pet p = new Pet();
p.setName(name);
//添加进数组
pets[index++] =p ;
}
//显示宠物信息
public void show() {
for (Pet p : pets) {
if (p!=null) {
System.out.println(p.getName());
}
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试类:
package com.dyit.tanruike;
public class PetTest {
public static void main(String[] args) {
Pet p1 = new Pet();
p1.add("猫");
Pet p2 = new Pet();
p2.add("狗");
p2.show();
}
}
结果:
我们分别创建了两个对象,一个添加的猫,一个添加的是狗,但是最后用第二个对象调用show()方法,也显示了第一个对象添加的猫。
由此,可以看出来static修饰的属性和方法在加载是指挥加载一次,随类的加载而加载,并不是在对象创建的时候随对象的创建二创建。static修饰的属性和方法,是类所具有的。是公共的。