static,静态关键字的详解
一,使用static声明属性
class Person{ // 定义Person类 String name ; // 定义name属性,暂时不封装 int age ; // 定义age属性,暂时不封装 String country = "A城" ; // 定义城市属性,有默认值 public Person(String name,int age){ this.name = name ; this.age = age; } public void info(){ // 得到信息 System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ; } }; public class StaticDemo01{ public static void main(String args[]){ Person p1 = new Person("张三",30) ; // 实例化对象 Person p2 = new Person("李四",31) ; // 实例化对象 Person p3 = new Person("王五",32) ; // 实例化对象 p1.info() ; p2.info() ; p3.info() ; } };
以上代码确实实现了功能,但是如果此时城市名称不叫A城,改叫B城,如果已经产生了5000个对象,那么意味着要修改5000遍对象中
contry属性。
所以最好使用static关键字声明属性。
范例,使用static修改。
class Person{ // 定义Person类 String name ; // 定义name属性,暂时不封装 int age ; // 定义age属性,暂时不封装 static String country = "A城" ; // 定义城市属性,有默认值,static public Person(String name,int age){ this.name = name ; this.age = age; } public void info(){ // 得到信息 System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ; } }; public class StaticDemo02{ public static void main(String args[]){ Person p1 = new Person("张三",30) ; // 实例化对象 Person p2 = new Person("李四",31) ; // 实例化对象 Person p3 = new Person("王五",32) ; // 实例化对象 System.out.println("--------------- 修改之前 -------------") ; p1.info() ; p2.info() ; p3.info() ; p1.country = "B城" ; // 修改static属性 System.out.println("--------------- 修改之后 -------------") ; p1.info() ; p2.info() ; p3.info() ; } };
修改一个对象中的属性,则其他对象的属性全部改变,则证明此属性是所有对象共享的!
分析:这是内存分配图:
每一个对象拥有各种的堆空间,堆内存空间中,保存着各自的属性,
但是static属性是保存在全局数据区之中,所有的对象共同指向全局数据的一个内容。所以一个数据修改后,所有对象内容都会改变。
JAVA中到底有多少内存区域呢?
1)栈内存:可以保存对象的名称(保存,访问的堆内存地址)。
2)堆内存:保存每个对象的全局属性。
3)全局数据区:保存static类型的属性。
4)全局代码区:保存所有方法的定义。
但是也发现一些问题:一般调用static属性,最好使用类名称调用。
采用”类名称.属性“的形式调用。如上应该用Person.contry="B城";
既然可以用static声明属性,那么static也可以声明方法。
二,声明static方法。
如果一个方法使用了static关键字声明,那么此方法可以使用类名称调用。
下面将之前代码全部属性进行封装。
class Person{ // 定义Person类 private String name ; // 定义name属性,暂时不封装 private int age ; // 定义age属性,暂时不封装 private static String country = "A城" ; // 定义城市属性,有默认值,static public static void setCountry(String c){ // 此方法可以直接由类名称调用 country = c ; } public static String getCountry(){ return country ; } public Person(String name,int age){ this.name = name ; this.age = age; } public void info(){ // 得到信息 System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",城市:" + country) ; } }; public class StaticDemo04{ public static void main(String args[]){ Person p1 = new Person("张三",30) ; // 实例化对象 Person p2 = new Person("李四",31) ; // 实例化对象 Person p3 = new Person("王五",32) ; // 实例化对象 System.out.println("--------------- 修改之前 -------------") ; p1.info() ; p2.info() ; p3.info() ; Person.setCountry("B城") ; // 调用静态方法修改static属性的内容 System.out.println("--------------- 修改之后 -------------") ; p1.info() ; p2.info() ; p3.info() ; } };
注意点:
使用static方法,不能调用非static属性或方法。(因为static属性和方法所修改的属性都是保存在共享数据区,而非static属性或方法是各自的堆内存数据区)
三,static的应用
1)从前面得知,static属性是所有对象共享的,那么就可以使用static属性统计一个类到底产生了多少对象。
因为每一个对象实例化都要调用构造方法,如果要进行统计,则直接在构造方法中增加一个static属性即可。
class Demo{ // 定义Person类 private static int count = 0 ; // 所有对象共享此属性 public Demo(){ count++ ; // 只要有对象产生就应该自增 System.out.println("产生了" + count + "个对象!") ; } }; public class StaticDemo06{ public static void main(String args[]){ new Demo() ; // 增加新对象 new Demo() ; // 增加新对象 new Demo() ; // 增加新对象 } };
2)可以使用static为对象进行自动的编名操作,此操作与上面方法非常类似。
class Demo{ // 定义Person类 private String name ; // 保存名字 private static int count = 0 ; // 所有对象共享此属性 public Demo(){ count++ ; // 有对象产生就自增 this.name = "DEMO-" + count ; // 自动进行编名操作 } public Demo(String name){ this.name = name; // 可以通过构造赋值 } public String getName(){ // 取得姓名 return this.name ; } }; public class StaticDemo07{ public static void main(String args[]){ System.out.println(new Demo().getName()) ;//使用了匿名对象。 System.out.println(new Demo("LXH").getName()) ; System.out.println(new Demo().getName()) ; System.out.println(new Demo("MLDN").getName()) ; System.out.println(new Demo().getName()) ; } };
运行结果:
DEMO-1
LXH
DEMO-2
MLDN
DEMO-3
此点在以后java中也会经常实现。
总结:
1)声明static属性与非static属性的区别。
2)使用类名可以直接调用static属性。
3)使用static方法,不能调用非static属性或方法。