java中static关键字

文章大部分内容来自:http://blog.sina.com.cn/s/blog_577d2a00010008ke.html

                                                     http://developer.51cto.com/art/200701/37490.htm

学习本文你到底要学到什么:
1、 static在java中到底代表什么,为何要用它?
2、 static在java中怎么用?
3、 static 有那些特点和使用的“局限”?

1、 static在java中到底代表什么,为何要用它?

      static――静态―― “指定位置”      

      首先,我们来看看java的内存:java把内存分为栈内存和堆内存,栈内存用来存放一些基本类型的变量和数组及对象的引用变量,而堆内存主要是来放置对象的。
      用static的修饰的变量和方法,实际上是指定了这些变量和方法在内存中的“固定位置”-static storage。既然要有“固定位置”那么他们的“大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在栈中或堆中开辟空间那就是非常的方便了。如果静态的变量或方法在不出其作用域的情况下,其引用句柄是不会发生改变的。
      我们常看到:static变量有点类似于C中的全局变量的概念;静态表示的是内存的共享,就是它的每一个实例都指向同一个内存地址。把static拿来,就是告诉JVM它是静态的,它的引用(含间接引用)都是指向同一个位置,在那个地方,你把它改了,它就不会变成原样,你把它清理了,它就不会回来了。我们常可看到类似以下的例子来说明这个问题:

class Student{
static int numberOfStudents=0;
Student(){
numberOfStudents++;
}}

     每一次创建一个新的Student实例时,成员numberOfStudents都会不断的递增,并且所有的Student实例都访问同一个numberOfStudents变量,实际上int numberOfStudents变量在内存中只存储在一个位置上。

  多个实例共享一个变量似乎不足以让我们对static那么的热情,实际上java引入static却有另外的含义:
       (1)、引用static的方法和变量,不需要和实例捆绑在一起,这可以提高代码的编写的效率(意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用),这样的例子我们随处可见:java的主类中main()方法本身就是一个static的,所以main方法的执行就是在没有产生新的实例的情况;

       (2)、如果需要创建一个脱离于实例的变量或方法(只与整个类有关),那么用static作修饰是再好不过了,如我们经常看到要统计实例实现的个数(通常的例子就是计数)。
     (3)、使用一种静态的方法的编程通常叫做防御(defensive)编程,它可以在API供应商突然中断支持的情况下保护代码 
 

静态方法:

     通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示:

class Simple{
static void go(){
	System.out.println("Go...");
}}
public class Cal{
	public static void main(String[] args){Simple.go();}} 

    调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。

 

静态变量:
     静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。

    值得探讨的是静态变量的初始化问题。

class Value{
   static int c=0;
   Value(){c=15;}
   Value(int i){c=i;}
   static void inc(){c++;}
}
class Count{
   public static void prt(String s)
   {
     System.out.println(s);
   }
   Value v=new Value(10);
   static Value v1,v2;
   static{
   prt("v1.c="+v1.c+" v2.c="+v2.c);
   v1=new Value(27);
   prt("v1.c="+v1.c+" v2.c="+v2.c);
   v2=new Value(15);
   prt("v1.c="+v1.c+" v2.c="+v2.c);
  }
  public static void main(String[] args)
  {
    Count ct=new Count();
    prt("ct.c="+ct.v.c);
    prt("v1.c="+v1.c+" v2.c="+v2.c);
    v1.inc();
    prt("v1.c="+v1.c+" v2.c="+v2.c);
    prt("ct.c="+ct.v.c);
  }
} 

运行的结果如下:

    首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。非静态变量不是本文的主题,在此不做详细讨论,请参考Think in Java中的讲解。

静态类:
   通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。
 

public class StaticCls{
  public static void main(String[] args){
     OuterCls.InnerCls oi=new OuterCls.InnerCls();
}
}
class OuterCls{
  public static class InnerCls{
   InnerCls(){System.out.println("InnerCls");}
}
} 

输出结果正如你所料为:InnerCls

 

2、 static 有那些特点和使用的“局限”?

   从上面的分析可知,static修饰的东西在类加载时,就分配了内存空间,即编译时就为这些成员变量的实例分配了空间。

   在static的方法中仅能够调用其他的static方法和static变量;在static方法中不能以任何方式引用this或super;static变量在定义时必须进行初始化,并且初始化的时间早于非静态。还有一个局限,static的变量的初始化仅能一次。


你可能感兴趣的:(java)