2.1.6 static静态成员
1.静态类成员
通常,类的成员必须属于一个具体化对象才能访问。但Java也提供了不用创建对象而直接让类中成员工作的机制。只要在该成员的声明前面加上关键字static即可。当声明一个成员为static时,可以在类的任何对象创建之前访问它。static成员的最常见的例子是main()方法,该方法不是作为一个对象的成员被运行的。
被声明为static的成员变量就是静态变量,也称为类变量。当声明该类的对象时,在对象中不生成static变量的副本,类的所有实例将共享同一个static变量。
同理,被声明为static的成员方法是静态方法,也称为类方法。静态方法有几条限制:
(1)它们仅可以调用其他static方法。
(2)它们只能访问static数据成员。
(3)它们不能以任何方式引用this或super(关键字super与继承有关,下一节介绍),因为this和super都是指向一个具体对象。
2.静态代码块
static块(即静态代码块),这个块仅在该类被第一次加载时执行一次。静态代码块的语法格式:
static { // 程序块 }
静态代码块不是类的方法,没有方法名、返回值和参数表。静态代码块也与类方法一样,不能使用非静态变量及方法,也不能使用this或super关键字。
【例2-4】 static方法、static变量、static初始块演示。
public class UseStatic{ static int a=3; // 静态变量(类变量),并初始化 static int b; // 静态变量 int c=10; // 实例变量 static void display(int x){ // 静态方法(类方法) System.out.println("x = " + x); System.out.println("a = " + a); System.out.println("b = " + b); //System.out.println("c="+c); //静态方法不能直接调用非静态成员 } static{ // 静态代码块 System.out.println("静态代码块执行开始"); b=a*4; // 初始化静态变量b } public static void main(String args[]){ display(42); // 直接调用静态方法 } }
一旦装载了UseStatic类,所有的static语句都被运行。首先,a被设置为3;然后static块执行(打印一条信息),最后,b被初始化为a*4即12;然后执行main()方法,main()中调用display()类方法,把42传递到x。三条println()语句引用两个static变量a、b,一个局部变量x。而c由于是非静态变量,因此不能直接被静态方法调用。
下面是该程序的输出:
静态代码块执行开始 x = 42 a = 3 b = 12
静态方法和变量可以独立于任何对象使用,仅需指定它们的类名,后跟一个“.”(点)运算符。可以用两种方式调用静态成员,它们的作用相同,因为不管该类有多少个对象都只存在一个静态成员。
静态变量: 类名.静态变量名
类对象.静态变量名
静态方法: 类名.静态方法名( )
类对象.静态方法名( )
例如,如果希望从类UseStatic外调用一个static方法,可以使用下面的形式:
UseStatic.display(42);
其中UseStatic是类的名字,在该类中直接调用static方法,这种格式与通过对象调用非static方法的格式类似。可以用同样的方式来访问static变量——类名加上“.”(点)运算符。
请看如下代码,注意static方法callme()和static变量b是如何被访问的。
class StaticDemo{ static int a=42; // 静态变量 static int b=99; // 静态变量 static void callme(){ // 静态方法 System.out.println("a = " + a); } } public class StaticByName{ public static void main(String args[]){ StaticDemo.callme(); // 不需创建对象,通过类名直接调用静态方法 System.out.println("b="+StaticDemo.b); // 通过类名直接调用静态变量 } }
下面是该程序的输出:
a = 42 b = 99
特别提示:
静态成员表示该类所有对象将共有同一个成员,如果一个对象将静态成员改变,将造成由该类生成的所有对象中的该成员发生相同改变。就好比如果全世界人只有一个钱罐,任何人往钱罐中放入一块钱,对于其他人来说他们的钱罐中也多了一块钱。
工作分解-操作方案
1.分析抽象出类;
2.按照类图编制出类框架;
3.实现类方法;
4.创建对象;
5.调用对象中的方法完成计算功能。
工作实施
1.分析抽象出类
根据类成员的访问权限可知,要使长和宽两个属性不允许另一个类访问,那么其只能是private类型的。存在一个矩形类Rectangle,该类包含两个private类型成员变量:长length和宽width,以及7个成员方法:setter和getter方法分别用于设置和获取各属性,一个带参构造方法Rectangle(double width, double length)用于初始化数据成员,perimeter()和area()方法分别用于计算长方形的周长和面积,如图2-4所示。另外,还有两个包:一个包com.bean,用于存放Rectangle类;另一个包com.test,用于存放主类RectangleTest。
图2-4 长方形类(Rectangle)图
2.按照类图编制出类框架
先创建包com.bean,然后在该包中定义Rectangle类。
// 源文件Rectangle.java package com.bean; public class Rectangle { // 声明private类型的成员变量,类外不能被访问 private double length; // 长 private double width; // 宽 // 带参构造方法(可以在所有包内被访问) public Rectangle(double length, double width) { } /*********以下定义成员方法*********/ public double getLength(){ // 获取长方形的长 } public void setLength(double length){ // 设置长方形的长 } public double getWidth(){ // 获取长方形的宽 } public void setWidth(double width){ // 设置长方形的宽 } public double perimeter(){ // 求长方形的周长 } public double area(){ // 求长方形的面积 } }
3.实现类中的方法
// 带参构造方法,用于初始化长方形的长和宽 public Rectangle(double length, double width){ this.width=width; //this关键字表示当前对象 this.length = length; } public void setLength(double length){ // 设置长方形的长 this.length = length; } public double getLength(){ // 获取长方形的长 return length; } public void setWidth(double width){ // 设置长方形的宽 this.width = width; } public double getWidth(){ // 获取长方形的宽 return width; } public double perimeter(){ // 求长方形的周长 return 2*(this.getLength() + this.getWidth()); } public double area(){ // 求长方形的面积 return this.length*this.width; // 调用当前对象的成员变量 }
4.定义主类
先新建一个包com.test,然后在该包中定义一个主类RectangleTest。
// 源文件RectangleTest.java package com.test; // 用import引入包 public class RectangleTest { public static void main(String[] args) { // 创建类的对象 } }
5.创建类的对象
// 第1步:将主类中“// 用import引入包”一行语句替换成下面一行语句 import com.bean.Rectangle; // 导入com.bean包中的Rectangle类 // 第2步:在主类的主方法main()中创建对象 Rectangle rect=new Rectangle(10.0,5.0);// 调用带参构造方法
6.访问对象中成员方法完成具体工作
// 通过调用成员方法来打印出指定长方形的长、宽、周长和面积 System.out.println("调用帶参构造方法创建的长方形类对象rect:"); System.out.print("length = " + rect.getLength() + " width = "+ rect.getWidth()); System.out.println("perimeter="+rect.perimeter()+" area="+rect.area());
7.代码调试运行
(1)完整源代码如下:
// 源文件Rectangle.java package com.bean; /** * 长方形类 * @author lee */ public class Rectangle { // 声明private类型的成员变量,类外不能被访问 private double length;// 长 private double width;// 宽 // 带参构造方法(可以在所有包内被访问),用于初始化长方形的长和宽 public Rectangle(double length, double width) { this.length=length; //this关键字表示当前对象 this.width = width; } public double getLength(){ // 获取长方形的长 return length; } public void setLength(double length){ // 设置长方形的长 this.length = length; } public double getWidth(){ // 获取长方形的宽 return width; } public void setWidth(double width){ // 设置长方形的宽 this.width = width; } public double perimeter(){// 求长方形的周长 return 2 * (this.getLength() + this.getWidth()); } public double area(){// 求长方形的面积 return this.length*this.width;// 调用当前对象的成员变量 } } // 源文件RectangleTest.java package com.test;// 所属包 import com.bean.Rectangle; // 导入com.bean包中的Rectangle类 public class RectangleTest { public static void main(String[] args) { Rectangle rect=new Rectangle(10.0,5.0);// 调用带参构造方法 // 通过调用成员方法来打印出指定长方形的长、宽、周长和面积 System.out.println("调用带参构造方法创建的长方形类对象rect:"); System.out.print("length="+rect.getLength()+" width="+rect.getWidth()); System.out.println(" perimeter="+rect.perimeter()+" area="+rect.area()); } }
(2)调试结果:
调用带参构造方法创建的长方形类对象rect: length=10.0 width=5.0 perimeter=30.0 area=50.0