1、实例变量与类变量的比较
(1)、在类中定义的变量成为成员变量,对于带static关键字的变量成为类变量或静态变量,反之成为实例变量或非静态变量
(2)、在类中定义的变量成为成员变量,对于带static关键字的变量成为类变量或静态变量,反之成为实例变量或非静态变量。
(3)、类变量属于类本身,伴随着类本身的初始化而完成内存分配,无论该类new了多少个实例,改变只有一个。类变量的初始化总是在实例变量的前面。
(4)、实例变量就是在new一个对象的时候才初始化,分配内存空间
(5)、static关键字可以修饰在类中定义的成员,包括成员变量、方法、内部类、初始化块、内部枚举;不能修饰外部类、局部变量、局部内部类。
创建一个人员类:
public class Person {
private String name;
private int age;
public static int money;
public void display() {
System.out.println("姓名:" + getName() + ";年龄:" + getAge());
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
System.out.println("Person的类变量money初始值:" + Person.money);
Person.money = 10;
System.out.println("Person的类变量money:" + Person.money);
Person p1 = new Person();
p1.setName("张三");
p1.setAge(21);
p1.money = 20;//这样用也可以、但是建议用Person.money = 10;
p1.display();
System.out.println("Person的类变量money:" + Person.money);
Person p2 = new Person();
p2.display();
}
结果为:
Person的类变量money初始值:0
Person的类变量money:10
姓名:张三;年龄:21
Person的类变量money:20
姓名:null;年龄:0
money为static变量,只创建一次,这里设置为public,其他的实例都可以直接访问它,并且访问的还是同一个。最好将其设置为private,不给其他实例直接访问,只能通过类本身来访问
2、实例变量初始化先后顺序
(1)、定义实例变量时指定初始值
(2)、非静态初始化块对实例变量赋值
构造方法赋值
public class Cat {
private String name;
private int age;
public Cat(String name, int age,double weight) {
this.name = name;
this.age = age;
this.weight=weight;
}
{
System.out.println("执行非静态初始化块——重量:" + getWeight());
System.out.println("执行非静态初始化块");
setWeight(22.2);
System.out.println("执行非静态初始化块——重量:" + getWeight());
}
private double weight = 12.3;
static {
System.out.println("执行静态初始化块");
}
public void display() {
System.out.println("名称:" + getName() + ";年龄:" + getAge() + ";重量:" + getWeight());
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return the weight
*/
public double getWeight() {
return weight;
}
/**
* @param weight the weight to set
*/
public void setWeight(double weight) {
this.weight = weight;
}
}
public static void main(String[] args) {
Cat c1 = new Cat("测试1", 10,10.1);
c1.display();
Cat c2 = new Cat("测试2", 20,20.1);
c2.display();
}
结果为:
执行静态初始化块
执行非静态初始化块——重量:0.0
执行非静态初始化块
执行非静态初始化块——重量:22.2
名称:测试1;年龄:10;重量:10.1
执行非静态初始化块——重量:0.0
执行非静态初始化块
执行非静态初始化块——重量:22.2
名称:测试2;年龄:20;重量:20.1
从上面可以看出,静态初始化块总是执行在前面,且每new一个对象就执行一次,构造方法赋值总是在最后面;
这里并没有输出weight=12.3而是输出为0.0说明非静态初始化块执行顺序在定义变量时赋值的前面,然后并非如此,交换非静态初始化块与weight定义时赋值赋值语句的先后顺序者的顺序
结果为:
执行静态初始化块
执行非静态初始化块——重量:12.3
执行非静态初始化块
执行非静态初始化块——重量:22.2
名称:测试1;年龄:10;重量:10.1
执行非静态初始化块——重量:12.3
执行非静态初始化块
执行非静态初始化块——重量:22.2
名称:测试2;年龄:20;重量:20.1
得出结论:静态初始化块最早,构造方法最晚,非静态初始化块与定义实例变量赋值的语句按先后顺序来判断
3、类变量初始化先后顺序
(1)、定义类变量时指定初始值
(2)、静态初始化块指定初始值
public class Test {
static int count = 1;
static {
count = 2;
}
static {
name = "测试2";
}
static String name = "测试1";
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
System.out.println("count值:" + Test.count);
System.out.println("name值:" + Test.name);
}
得出结论:
这两种方式执行顺序与他们在代码中的先后顺序一致
4、构造方法执行先后顺序
当用构造方法创建一个类的实例的时候,首先执行父类的非静态初始化块、构造方法,然后再执行本类的非静态初始化块、构造方法
(1)、执行Object类非静态非静态初始化块(没有就不执行)
(2)、执行Object类的构造方法(有时候是隐式调用的)
(3)、执行父类的非静态初始化块(没有就不执行)
(4)、执行父类的构造方法(有时候是隐式调用)
(5)、执行本类非静态初始化块(没有就不执行)
(6)、执行本类的构造方法
public class Son extends Parent {
static {
System.out.println("儿子的静态初始化块");
}
{
System.out.println("儿子的非静态初始化块");
}
public Son() {
super("张三", 25);
System.out.println("儿子无参构造方法");
}
public Son(String name) {
this();
System.out.println("儿子有参构造方法" + name);
}
}
class Parent extends GrandFather {
static {
System.out.println("父亲的静态初始化块");
}
{
System.out.println("父亲的非静态初始化块");
}
public Parent(String parent) {
super(parent);
System.out.println("父亲一个参数构造方法" + parent);
}
public Parent(String name, int age) {
this(name);
System.out.println("父亲两个参数构造方法" + name);
}
}
class GrandFather {
static {
System.out.println("爷爷的静态初始化块");
}
{
System.out.println("爷爷的非静态初始化块");
}
public GrandFather() {
System.out.println("爷爷无参构造方法");
}
public GrandFather(String name) {
this();
System.out.println("爷爷有参构造方法" + name);
}
}
public class Test {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Son s = new Son("三毛");
}
}
结果为:
爷爷的静态初始化块
父亲的静态初始化块
儿子的静态初始化块
爷爷的非静态初始化块
爷爷无参构造方法
爷爷有参构造方法张三
父亲的非静态初始化块
父亲一个参数构造方法张三
父亲两个参数构造方法张三
儿子的非静态初始化块
儿子无参构造方法
儿子有参构造方法三毛
结论:可以看出
(1)、首先是加载静态的资源,然后再是非静态初始化块,然后再是构造方法
(2)、系统总是从最顶层的父类开始初始化操作
5、访问子类对象的实例变量
continue………………