Java 中被static 修饰的域或方法常被称作静态的,那么什么叫做静态的呢?下面我们就来了解一下Java中的静态域与静态方法。
1、静态域
如果将静态域定义为static ,那么每个类中只有一个这样的域,而每一个对象对于所有的实例域都有自己的一份拷贝本。例如,学生类中有一个实例域studentId和一个静态域nextId, 如下所示:
那么,每一个学生对象,都会有自己的studentId, 但是这个类的所以对象将共享一个nextId域, 换句话说就是: 如果有100个Student类对象 ,那么有100个实例域studentId,每一个student都有自己的一份,但是只有一个静态域nextId , 100个学生对象共享这一个静态域nextId, 使没有学生对象,静态域也是存在的,它是属于类的,而不是属于任何独立的对象。静态域(静态方法)可以直接用类名来调用,而不用创建对象用对象来调用(在绝大多数的面向对象的语言中,静态域被称作为类域。术语“static” 只是沿用了C++的叫法,并无实际意义)。
下面在Student类中实现一个setId() 方法:
public void setId(){ studentId = nextId + ""; nextId++; }
假定为student1 对象设置studnetId 即: student1.setId(); 那么studnet1的实例域studentId 被设置为静态域nextId当前的值,并且静态域nextId 的值进行了自增运算。这个的作用相当于:
student1.id = Student.nextId;
Student.nextId++;
2、静态常量
静态变量使用的比较少,但是静态常量却使用的比较多(在实际的开发中,静态常量可以做到:该改一处而改全处作用,大大的减少修改和出错的地方),例如在Java中的Math类中定义了一个圆周率的静态常量:
在使用的时候,我们就可以跟使用静态变量、静态方法方法一样使用静态常量(用静态static修饰的都是可以直接用类名来使用) Math.PI来使用这个常量。
如果关键字static被省略,那么PI就变成Math类的一个实例域,需要通过Math类的对象访问PI,并且每一个Math对象都有它自己的一个PI复制本。
另外一个多次使用的静态常量是Java中System.out. 它在System类中声明:
- public class System{
- ...
- public static final PrintStream = ...;
- ...
- }
我们都知道每个类对象都可以对公有域进行修改,所以,最好不要将域设计成为public ,然而,公有常量(即final域)却没有问题,因为out被声明为final, 所以,不允许再将其他的打印流赋值给它:
System.out = new PrintStream(...); //这是做法是错误的
注意: 查看System类,就会发现有一个setOut方法,它可以将System.out.设置为不同的流,那么我们可能会感到奇怪,为什么这个方法可以修改final 变量的值,原因在于,setOut方法是一个本地方法,而不是用Java语言实现的(用的是C语言实现),本地方法可以绕过Java语言的存取控制机制,这是一种特殊的方法,在编写程序的时候,我们不应该这样处理,但是在android开发中有些开发是要写本地方法,然后用C语言实现,再再Java环境中调用C语言,这里就不做过多的讲解了。
3、静态方法
静态方法是一种不能由对象操作的方法, 例如Math类中的求取一个数的次方的pow()方法就是一个静态方法。表达式是: Math.pow(x, a),在运算时,不使用任何Math对象,换句话说,没有隐式的参数。可以认为静态方法是没有this参数的方法(在一个非静态的方法中,this参数表示这个方法的隐式参数)。
Student 类的静态方法不能访问Id实例域,因为Id它不是静态的,Student的静态方法它不能操作对象,但是静态方法可以访问自身类中的静态域。总之就是常说的:静态方法中只能调用静态的东西,非静态的是不能使用的。
- public static int getNextId{
- return nextId; // 返回静态域
- }
这个方法通过类名Student.getNextId()来调用,那么这个方法可以省略关键字static吗? 回答是肯定的,但是需要通过Student类的对象来调用这个方法了。
在下面两种情况下使用静态方法:
1、一个方法不需要访问对象状态,其所需参数都是通过显示参数提供(例如: Math.pow()).
2、一个方法只需要访问类的静态域(例如:Student.getNextId() ).
4、工厂方法
静态方法还有一种常见的用途,例如:NumberFormat类使用工厂方法产生不同风格的格式对象:
-
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(); NumberFormat percentFormatter = NumberFormat.getPercentInstance(); doublen n = 0.3; System.out.println(currencyFormatter.format(n)); // 输出 ¥0.30 System.out.println(percentFormatter.format(n)); //输出 30%
为什么NumberFormat类不利用构造器完成这些操作呢?主要的原因有两个:
1、无法命名构造器。构造器的名字必须与类名相同,但是,这里希望将得到的货币实例和百分比实例采用不同的名字。
2、当使用构造器时,无法改变所构造的对象类型。而Factory方法将返回一个DecimalFormat类对象,这是NumberFormat的子类。
5、main方法
我们学习java的时候,程序中大多会有一个main 方法,我们都称作程序的入口,main方法不对任何对象进行操作,事实上,在启动程序的时候,还没有任何一个对象,静态的main方法将执行并创建程序所需的对象。