对成员变量、静态变量、常量、实例变量以及方法变量的基本理解整理

成员变量和方法变量

成员变量定义在方法外即全局变量(包括静态变量和实例变量),方法变量定义在方法内,也叫局部变量。

静态变量(类变量)

静态变量是static修饰的类成员变量,也叫类变量,可以不设置初始值,静态变量的值存储在方法区的常量池中

可以直接通过类名调用,也可以通过实例调用,但一般不推荐此种方式。

在类加载的准备阶段进行分配空间以及初始化为该类型的默认值,在类加载的初始化阶段赋值为初始值。如下:String类型的variable2没有设置初始值,在类加载的准备阶段初始化为null,在初始化阶段因为没有设置初始值,就没有赋值过程;int类型的variable0设置了初始值为100,在准备阶段初始化为0,在初始化阶段赋为100。

public class TestClass {
    public static String variable2;
    public static int variable0 = 100;

    public static void main(String[] args) {
        //静态变量没有设置初始值时,类加载的准备阶段会将String类型初始化为null
        System.out.println(TestClass.variable2);//null
        //虽然通过实例也可以调用静态,但一般不推荐此种方式
        System.out.println(new TestClass().variable2);//null
        //静态变量设置了初始值时,类加载的准备阶段会将int类型初始化为0,然后在类加载的初始化阶段赋为初始值100
        System.out.println(TestClass.variable0);//100
    }
}

静态变量与实例无关,被所有对象共享,可以一处修改多处使用,如下:

public class TestClass {
    public static int variable0 = 100;

    public static void main(String[] args) {
        TestClass test1 = new TestClass();
        test1.variable0 = 200;
        System.out.println(test1.variable0);//200
        TestClass test2 = new TestClass();
        System.out.println(test2.variable0);//200
    }
}

在多线程情况下,被所有线程共享,如下: 

public static void main(String[] args) {
	new Thread(()->{
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"---"+TestClass.variable0);
	},"thread1").start();
	new Thread(()->{
		TestClass.variable0 = 200;
		System.out.println(Thread.currentThread().getName()+"---"+TestClass.variable0);
	},"thread2").start();
}

 

常量

常量是final修饰的类静态成员量必须要设置初始值并且该值不可修改,常量除了值不可修改之外其他属性同静态变量类似。常量的值也是存储在方法区的常量池中。可以直接通过类名调用,也可以通过实例调用,但一般不推荐此种方式。

在类加载的准备阶段进行分配空间以及直接初始化为初始值,在初始化阶段没有赋值过程。被所有线程所有对象共享。

实例变量

实例变量即为实例对象的变量(属性),是类的非静态成员变量,可以不设置初始值只能通过实例调用

实例变量作为实例对象的属性存储在堆内存中,生命周期和实例对象一样,随着实例一起创建、使用和销毁。在类实例化的时候初始化为默认值,随后设置为初始值(有待验证)。

实例变量和实例直接挂钩,自然不存在跨对象共享问题。

在多线程环境下操作同一实例对象的实例变量会存在安全性问题。如下:

public class TestClass {
    public int variable1 = 20;

    public static void main(String[] args) {
        TestClass test1 = new TestClass();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"---"+test1.variable1);
            for (int i = 0; i < 1000000; i++) {
                test1.setVariable1(test1.getVariable1()+1);
            }
            System.out.println(Thread.currentThread().getName()+"---"+test1.variable1);
        },"thread1").start();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"---"+test1.variable1);
            for (int i = 0; i < 1000000; i++) {
                test1.setVariable1(test1.getVariable1()+1);
            }
            System.out.println(Thread.currentThread().getName()+"---"+test1.variable1);
        },"thread2").start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(test1.getVariable1());
    }
}

 上述代码的想得到的数据为2000020,实际打印的数据如下:

解决:在循环读取和赋值时给实例加锁,代码如下:

for (int i = 0; i < 1000000; i++) {
	synchronized (test1) {
		test1.setVariable1(test1.getVariable1() + 1);
	}
}

 方法变量(局部变量)

方法变量即为方法内部定义的变量或者是方法被调用时传递的参数,存储在虚拟机栈的栈帧中的局部变量表里(具体参看JVM系列之栈帧(Stack Frame)结构)。

虚拟机没有给局部变量初始化为默认值的过程(因为局部变量一般比较多,生命周期短,虚拟机做变量初始化开销会很大),所以一般在定义时就赋值为初始值,如果没有设置初始值,那么在被使用前一定要进行赋值,否则会抛异常,如下:

public String method(boolean flag){
	String methodVariable;
	if(flag){
		methodVariable = "test1";
	}else{
		methodVariable = "test2";
	}
	return methodVariable;
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值