开封市做网站的公司,软件界面设计工具下载,灯饰模板网站,免费域名注册可解析2019独角兽企业重金招聘Python工程师标准 一、static关键字 原来一个类里面的成员变量#xff0c;每new一个对象#xff0c;这个对象就有一份自己的成员变量#xff0c;因为这些成员变量都不是静态成员变量。对于static成员变量来说#xff0c;这个成员变量只… 2019独角兽企业重金招聘Python工程师标准 一、static关键字 原来一个类里面的成员变量每new一个对象这个对象就有一份自己的成员变量因为这些成员变量都不是静态成员变量。对于static成员变量来说这个成员变量只有一份而且这一份是这个类所有的对象共享。 1.1.静态成员变量与非静态成员变量的区别 以下面的例子为例说明 1 package cn.galc.test;2 3 public class Cat {4 5 /**6 * 静态成员变量7 */8 private static int sid 0;9
10 private String name;
11
12 int id;
13
14 Cat(String name) {
15 this.name name;
16 id sid;
17 }
18
19 public void info() {
20 System.out.println(My Name is name ,NO. id);
21 }
22
23 public static void main(String[] args) {
24 Cat.sid 100;
25 Cat mimi new Cat(mimi);
26 Cat pipi new Cat(pipi);
27 mimi.info();
28 pipi.info();
29 }
30 } 通过画内存分析图了解整个程序的执行过程 执行程序的第一句话Cat.sid 100;时这里的sid是一个静态成员变量静态变量存放在数据区(data seg)所以首先在数据区里面分配一小块空间sid第一句话执行完后sid里面装着一个值就是100。 此时的内存布局示意图如下所示 接下来程序执行到 Cat mimi new Cat(“mimi”); 这里调用Cat类的构造方法Cat(String name)构造方法的定义如下 Cat ( String name){ this.name name; idsid; } 调用时首先在栈内存里面分配一小块内存mm里面装着可以找到在堆内存里面的Cat类的实例对象的地址mm就是堆内存里面Cat类对象的引用对象。这个构造方法声明有字符串类型的形参变量,所以这里把“mimi”作为实参传递到构造方法里面由于字符串常量是分配在数据区存储的所以数据区里面多了一小块内存用来存储字符串“mimi”。此时的内存分布如下图所示 当调用构造方法时首先在栈内存里面给形参name分配一小块空间名字叫name,接下来把”mimi”这个字符串作为实参传递给name字符串也是一种引用类型除了那四类8种基础数据类型之外其他所有的都是引用类型所以可以认为字符串也是一个对象。所以这里相当于把”mimi”这个对象的引用传递给了name所以现在name指向的是”mimi”。所以此时内存的布局如下图所示 接下来执行构造方法体里面的代码: this.namename; 这里的this指的是当前的对象指的是堆内存里面的那只猫。这里把栈里面的name里面装着的值传递给堆内存里面的cat对象的name属性所以此时这个name里面装着的值也是可以找到位于数据区里面的字符串对象“mimi”的此时这个name也是字符串对象“mimi”的一个引用对象通过它的属性值就可以找到位于数据区里面的字符串对象“mimi”。此时的内存分布如下图所示 接下来执行方法体内的另一句代码 idsid; 这里是把sid的值传递给id所以id的值是100sid传递完以后自己再加1此时sid变成了101。此时的内存布局如下图所示。 到此构造方法调用完毕给这个构造方法分配的局部变量所占的内存空间全部都要消失所以位于栈空间里面的name这块内存消失了。栈内存里面指向数据区里面的字符串对象“mimi”的引用也消失了此时只剩下堆内存里面的指向字符串对象“mimi”的引用没有消失。此时的内存布局如下图所示 接下来执行Cat pipi new Cat(“pipi”); 这里是第二次调用构造方法Cat()整个调用过程与第一次一样调用结束后此时的内存布局如下图所示 最后两句代码是调用info()方法打印出来打印结果如下 通过这个程序看出来了这个静态成员变量sid的作用它可以计数。每当有一只猫new出来的时候就给它记一个数。让它自己往上加1。 程序执行完后内存中的整个布局就如上图所示了。一直持续到main方法调用完成的前一刻。 这里调用构造方法Cat(String name) 创建出两只猫首先在栈内存里面分配两小块空间mimi和pipi里面分别装着可以找到这两只猫的地址mimi和pipi对应着堆内存里面的两只猫的引用。这里的构造方法声明有字符串类型的变量字符串常量是分配在数据区里面的所以这里会把传过来的字符串mimi和pipi都存储到数据区里面。所以数据区里面分配有存储字符串mimi和pipi的两小块内存里面装着字符串“mimi”和“pipi”字符串也是引用类型除了那四类8种的基础数据类型之外其他所有的数据类型都是引用类型。所以可以认为字符串也是一个对象。 这里是new了两只猫出来这两只猫都有自己的id和name属性所以这里的id和name都是非静态成员变量即没有static修饰。所以每new出一只新猫这只新猫都有属于它自己的id和name即非静态成员变量id和name是每一个对象都有单独的一份。但对于静态成员变量来说只有一份不管new了多少个对象哪怕不new对象静态成员变量在数据区也会保留一份。如这里的sid一样sid存放在数据区无论new出来了多少只猫在堆内存里面sid都只有一份只在数据区保留一份。 静态成员变量是属于整个类的它不属于专门的某个对象。那么如何访问这个静态成员变量的值呢首先第一点任何一个对象都可以访问这个静态的值访问的时候访问的都是同一块内存。第二点即便是没有对象也可以访问这个静态的值通过“类名.静态成员变量名”来访问这个静态的值所以以后看到某一个类名加上“.”再加上后面有一个东西那么后面这个东西一定是静态的如”System.out”这里就是通过类名(System类)再加上“.”来访问这个out的所以这个out一定是静态的。 再看下面的这段代码 1 package cn.galc.test;2 3 public class Cat {4 5 /**6 * 这里面的sid不再是静态成员变量了因为没有static修饰符7 * 此时它就是类里面一个普通的非静态成员变量和idname一样8 * 成为每一个new出来的对象都具有的属性。9 */
10 private int sid 0;
11
12 private String name;
13
14 int id;
15
16 Cat(String name) {
17 this.name name;
18 id sid;
19 }
20
21 public void info() {
22 System.out.println(My Name is name ,NO. id);
23 }
24
25 public static void main(String[] args) {
26 //Cat.sid 100;这里不能再使用“类.静态成员变量”的格式来访问sid了因为sid现在变成了非静态的成员变量了。所以必须要把这句话注释掉否则无法编译通过。
27 Cat mimi new Cat(mimi);
28 Cat pipi new Cat(pipi);
29 mimi.info();
30 pipi.info();
31 }
32 } 这段代码与上一段代码唯一的区别是把声明sid变量的static修饰符给去掉了此时的sid就不再是静态成员变量而是非静态成员变量了此时每一个new出来的cat对象都会有自己单独的sid属性。所以这段代码执行完成后内存中的布局如下图所示 由于sid变成了非静态成员变量所以不再有计数的功能了。sid与id和name属性一样成为每一个new出来的对象都具有的属性所以每一个new出来的cat都加上了一个sid属性。由于不能再使用”类名.静态成员对象名”的格式访问sid所以代码的第一句”Cat.sid 100;”不能这样使用否则编译会出错必须把这句话注释掉才能编译成功。既然无法访问得到sid的值所以sid的值就一直都是初始化时赋给的值0。直到调用构造方法时执行到方法体内的代码idsid;时sid首先把自身的值0赋值给id所以id的值是0然后sid自己加1所以sid变成了1。 所以静态变量和非静态变量的区别就在于静态变量可以用来计数而非静态变量则不行。 理解了内存就理解了一切就理解了各种各样的语言。所有的语言无非都是这样局部变量分配内存永远在栈里面new出来的东西分配内存永远是在堆里静态的东西分配内存永远是在数据区。剩下的代码肯定是在代码区。所有的语言都是这样。 在一个静态方法里如果想访问一个非静态的成员变量是不能直接访问的必须在静态方法里new一个对象出来才能访问。如果是加了static的成员变量那么这个成员变量就是一个静态的成员变量就可以在main方法里面直接访问了。 main方法是一个静态的方法main方法要执行的时候不需要new一个对象出来。 动态方法是针对于某一个对象调用的静态方法不会针对某一个对象来调用没有对象照样可以用。所以可以使用”classname.method()”.的形式来调用静态方法。所以想在main方法里面访问非静态成员变量是不可以的想在main方法里面访问非静态方法也是不可以的因为非静态方法只能针对于某个对象来调用没有对象就找不到方法的执行者了。 成员变量只有在new出一个对象来的时候才在堆内存里面分配存储空间。局部变量在栈内存里面分配存储空间。 静态方法不再是针对某一个对象来调用所以不能访问非静态的成员。 非静态成员专属于某一个对象想访问非静态成员必须new一个对象出来才能访问。 静态的变量可以通过对象名去访问也可以通过类名去访问两者访问的都是同一块内存。 转载于:https://my.oschina.net/zhanghaiyang/blog/594766