黑马程序员技术交流社区

标题: 总结static所有知识点 [打印本页]

作者: 王雷    时间: 2012-9-28 12:37
标题: 总结static所有知识点
本帖最后由 屈俊材 于 2012-9-28 13:57 编辑

小弟听课感觉很不理想,所以想请大神给讲讲关于static的所有知识点,同时也给大多数不了解或者懵懂的人一起共同进步下,小弟在这里谢过了
作者: 李健_8    时间: 2012-9-28 12:50
public class MyClass{
        public static void aStaticMethod()  {  ... };  //静态方法
        public  void aNonStaticMethod()  {  ...  } ;   //非静态方法
...
}
当你定义了一个类,如果里面的方法或变量定义为static的,那么该方法或函数对于该类的对象只有一个,因此可以用类名来引用并访问,比如MyClass.aStaticMethod()

而非静态的方法或变量,你是必须创建一个该类的新的对象的,比如上面的非静态方法,就必须用new MyClass().aNonStaticMethod( ).

说起来,这个很好理解的。
举个简单例子,你买了某个品牌的小汽车,你的小汽车对于这个品牌的车子就应该创建个对象,你开车,自己修车都应该是非静态方法。
而街上那些汽车修理店对你这种牌子的车所有来修车的来说是公共的,他们的修车,洗车这些方法应该是静态方法。

另外,还有一些规则,比如静态方法内部不能有非静态方法,而非静态方法内是可以用静态方法的,这就要你多练习来掌握了。赞同10| 评论
作者: 柳彬    时间: 2012-9-28 13:35
1.关键字static(先记住这些,再往下看)

1)静态方法和静态变量是属于某一个类,而不属于类的对象。

2)静态方法和静态变量的引用直接通过类名引用。

3)在静态方法中不能调用非静态的方法和引用非静态的成员变量。反之,则可以。

4)静态变量在某种程序上与其他语言的全局变量相类似,如果不是私有的就可以在类的外部进行访问。

2.何时使用static

在我们创建一个类的实例时(对象),通常使用new方法,这样这个类的数据空间才会被创建,其方法才能被调用。

     但是,有时候我们希望一个类虽然可以被创建n个对象(显然这n个对象的数据空间是不相同的),但这n个对象的某些数据是相同的,即不管这个类有多少的实例,这些数据对这些实例而言之有一份内存拷贝(见示例1)。这是静态变量的情形。

另一种情形是,你希望某个方法不与包含它的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用这个方法。static 方法的一个重要用法就是在不创建任何对象的前提下,就可以调用它(见示例2)。这是静态方法的情形。

还有一种特殊的用法出现在内部类中,通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类(见示例3)。这是静态类的情形。

示例1




public class TStatic {

    static int i;



    public TStatic() {

       i = 4;

    }



    public TStatic(int j) {

       i = j;

    }



    public static void main(String args[]) {

       System.out.println(TStatic.i);

       TStatic t = new TStatic(5); // 声明对象引用,并实例化。此时i=5

       System.out.println(t.i);

       TStatic tt = new TStatic(); // 声明对象引用,并实例化。此时i=4

       System.out.println(t.i);

       System.out.println(tt.i);

       System.out.println(t.i);

    }

}




结果:

0

5

4

4

4

static变量在类被载入时创建,只要类存在,static变量就存在。它们在定义时必须进行初始化。上例中没有初始化i,所以会得到默认的初始值0。static的变量的初始化仅能一次,static变量只是接受了最后一次的初始化。

实际这还是多个实例共享一个静态的变量的问题。



示例2

未声明为static




class ClassA {

    int b;



    public void ex1() {}



    class ClassB {

       void ex2() {

           int i;

           ClassA a = new ClassA();

           i = a.b; // 这里通过对象引用访问成员变量b

           a.ex1(); // 这里通过对象引用访问成员函数ex1

       }

    }

}




声明为static




class ClassA {

    static int b;



    static void ex1() {}

}



class ClassB {

    void ex2() {

       int i;

       i = ClassA.b; // 这里通过类名访问成员变量b

       ClassA.ex1(); // 这里通过类名访问成员函数ex1

    }

}


在使用静态方法时要注意,在静态方法中不能调用非静态的方法和引用非静态的成员变量(在static方法中也不能以任何方式引用this或super)。理由很简单,对于静态的东西,JVM在加载类时,就在内存中开辟了这些静态的空间(所以可以直接通过类名引用),而此时非静态的方法和成员变量所在的类还没有实例化。

所以如果要使用非静态的方法和成员变量,可以直接在静态方法中实例化该方法或成员变量所在的类。public static void main就是这么干的。



示例3




public class StaticCls {

    public static void main(String[] args) {

       OuterCls.InnerCls oi = new OuterCls.InnerCls();// 这之前不需要new一个OuterCls

    }

}



class OuterCls {

    public static class InnerCls {

       InnerCls() {

           System.out.println("InnerCls");

       }

    }

}




结果:

InnerCls

3.静态初始化

static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。静态代码块(在“static{”后面跟着一段代码),是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。看下面示例。




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("in the static block of calss Count v1.c=" + v1.c + "  v2.c="

              + v2.c);

       v1 = new Value(27);

       prt("in the static block of calss Count v1.c=" + v1.c + "  v2.c="

              + v2.c);

       v2 = new Value();

       prt("in the static block of calss Count v1.c=" + v1.c + "  v2.c="

              + v2.c);

    }

}



public class TStaticBlock {

    public static void main(String[] args) {

       Count ct = new Count();

       Count.prt("in the main:");

       Count.prt("ct.c=" + ct.v.c);

       Count.prt("v1.c=" + Count.v1.c + "  v2.c=" + Count.v2.c);

       Count.v1.inc();

       Count.prt("v1.c=" + Count.v1.c + "  v2.c=" + Count.v2.c);

       Count.prt("ct.c=" + ct.v.c);

    }

}




结果:

in the static block of calss Count v1.c=0  v2.c=0

in the static block of calss Count v1.c=27  v2.c=27

in the static block of calss Count v1.c=15  v2.c=15

in the main:

ct.c=10

v1.c=10  v2.c=10

v1.c=11  v2.c=11

ct.c=11

不管是v,v1还是v2,它们操作的成员变量都是同一个静态变量c。

在类Count中先初始化v1,v2(static Value v1, v2;),再初始化静态代码块(static{}),最后初始化v。

4.参考资料

[1]Thinking in java 3rd

[2] java中的关键字(static和final),http://blog.sina.com.cn/u/4b86f2ee010006uf

[3] Java修饰符之static,http://blog.sina.com.cn/u/4a4aa31a0100050f

[4] java 中的 static,http://hi.baidu.com/ihondy/blog/item/5ec0085501eac1c4b645ae81.html

[5] Java之static学习 ,http://2049.bokee.com/6057945.html

[6]张孝祥,Java就业培训教程
作者: yangfengxiao    时间: 2012-9-28 13:39
可以看一下我总结的java中静态代码块的用法 static用法详解 或许对你有用。http://blog.csdn.net/yangfengxiao/article/details/8022089
作者: 汪小照    时间: 2012-9-28 13:45
这是我在写博客时总结出来的static所涉及到的知识点,在此回复,希望能帮到你

java中static静态关键字的知识点      

                static是一个修饰符,用于修饰java类中的成员(包括成员变量和成员方法,甚至内部类)

                当成员被静态修饰后 ,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用,格式:类名.静态名

          static的特点:

                1.随着类的加载而加载(也就是说,静态会随着类的消失而消失,说明它的生命周期最长)

                2.优先于对象存在

                3.被所有对象所共享

                4.可以直接被类名所调用

注意:类变量就是静态变量,而实例变量就是没有static修饰的变量。

          实例变量和类变量的区别:

                 1.存放位置的不同

                          类变量随着类的加载而存在于方法区中

                          实例变量随着对象的建立而存在于堆内存中

                 2.生命周期不同

                         类变量生命周期最长,随着类的消失而消失

                          实例变量的周期随着对象的消失而消失

           静态的使用注意事项:

                  1.静态方法只能访问静态成员,非静态方法既能访问静态成员又能访问非静态成员。

                  2.静态方法中不可定义this,super关键字。因为静态优先于对象存在,所以静态方法中不可以出

现this,super等。

           静态的利与弊

                  利:对对象的共享数据可以进行单独空间的存取。可以被类名直接调用。

                  弊:生命期过长。访问出现局限性(不能访问非静态成员)

           那我们在什么时候使用静态呢?

                 首先,考虑从两方面着手,当对象中出现共享数据时,该数据可以定义为静态的。

           当功能内部没有访问到非静态数据(即对象的特有数据时),那么该功能可以定义为静态的。

         静态代码块:(格式如下)

        static {

        静态代码块中的执行语句;

         }

         静态代码块的特点:随着类的加载而执行,并且只执行一次。

       对象的初始化过程:

        class Person

      {

         private String name;

         private int age;

        private static String country="cn";

        Person (String name,int age)

       {

                this.name = this.name;

                this.age = age;

       }

      public void setName(String name)

     {

            this.name = name;

     }

    //静态代码块

    {    System.out.println("haha");}

    //构造代码块

    {   System.out.println(this.name + this.age);}

   public static void showCountry()

    {

     System.out.println("country="+country);

    }

  }

  class PersonDemo

   {

        public static void main(String [] args)

       {

           Person p = new Person("张三",20);

            p.setName("Lisi");

         }

}

    在这条语句上分析对象初始化执行的过程:(以Person p = new Person("张三',20))

    1,因为用到的了Person.class文件,所以会先找到Person.class文件,并加载到内存中。

    2,执行该类中的static代码块,如果有的话给Person.class类初始化。

    3,在对内存中开辟空间,分配内存地址。

    4,在对内存中建立对象的特有属性,并进行默认初始化。

    5,对属性进行显示初始化。

    6,对对象进行构造代码初始化。

    7,对对象进行与之对应的构造函数初始化。

    8,将内存地址赋给栈中的p变量。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2