A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 那日苏 黑马帝   /  2011-7-25 00:07  /  2926 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

我对static块不怎么了解,只是知道static块会在一开始被初始化,而且只执行一次.
请讲下有什么作用?什么时候要用?最好能给个例子。谢谢了!

评分

参与人数 1技术分 +1 收起 理由
小龙 + 1

查看全部评分

6 个回复

正序浏览
黑马网友  发表于 2011-7-27 17:37:27
7#
初始化用的,在创建了该类对象时就会执行,其实当类的定义中不含有static块时,编译器会为该类提供一个默认的static块。当然这是在含有静态变量初始化操作的前提下。如果静态变量没有初始化操作,则编译器不会为之提供默认的static块。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
代码块执行顺序:静态代码块---构造代码块---构造函数----局部代码块(局部变量在函数里,作用是限定局部变量的生命周期)[code=java]            public static void main(String[] args) {
                        System.out.println("2");
                        new Day07().fun();
                }
                {
                        System.out.println("3");
                }
                static {
                        System.out.println("1");
                }       
                Day07(){
                        System.out.println("4");
                }
                static void fun() {
                        System.out.println("5");
                }[/code]以上打印结果1,2,3,4,5;1是静态代码快,2是主函数,3是构造代码快,4是构造函数,5时局部代码快(也就是函数)
[ 本帖最后由 马晓伟 于 2011-07-25  19:12 编辑 ]

评分

参与人数 1技术分 +2 收起 理由
admin + 2

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-25 13:36:38
报纸
这个问题是 实例变量和类变量的区别。用static修饰的变量是类变量,而没有的为实例变量。

   不同的对象的实例变量将被分配不同的内存空间,如果类中的成员变量有类变量,那么所以对象的这个类变量都分配给相同的一处内存,改变其中一个对象的这个类变量会影响其他对象的这个类变量,也就是说对象共享类变量。
   当java程序执行时,类的字节码文件被加载到内存,如果该类没有创建对象,类实例成员变量不会被分配内存。但是,类中的类变量被加载到内存时,就分配了相应的内存空间。如果该类创建对象,那么不同对象的实例变量互不相同,即分配不同的内存空间,而类变量不再重新分配内存,所有的对象共享类变量,即所有的对象的类变量是相同的一处内存空间,类变量的内存空间直到程序退出运行,才释放所占有的内存。类变量是与类相关联的这个类变量就同时改变了其他对象的这个类变量。因此,类变量不仅可以通过某个对象访问,也可以直接通过类名访问。实例变量仅仅是和相应的对象关联的变量,也就是说,不同对象的实例变量互不相同,即分配不同的内存空间,改变其中一个对象的实例变量不会影响其他对象的这个实例变量。实例变量可以通过对象访问,不能使用类名访问。

static{}

称为static代码块 ,也叫静态代码块,

是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次


利用静态代码块可以对一些static变量进行赋值

例子

public class Test5 {
private static int a;
private int b;

static{
Test5.a=3;
System.out.println(a);
Test5 t=new Test5();
t.f();
t.b=1000;
System.out.println(t.b);
}
static{
Test5.a=4;
System.out.println(a);
}
public static void main(String[] args) {
// TODO 自动生成方法存根
}
static{
Test5.a=5;
System.out.println(a);
}
public void f(){
System.out.println("hhahhahah");
}
}  

运行结果:
3
hhahhahah
1000
4
5

评分

参与人数 1技术分 +3 收起 理由
admin + 3 不错的同学!

查看全部评分

回复 使用道具 举报
很多人都会说statci块的执行是在第一次调用newInstance的时候调用,但是这是并不全是正确的,我们可以用以下方法来测试:[code=java]public class TestA{   
    static{   
        System.out.println("Static block executed!");;   
     }      
}   
  
public class Test{   
    public static void main(String args[]);{   
        Test test = new Test();;   
        Class.forName("TestA",true,test.getClass();.getClassLoader(););;   
    }   
}  [/code][code=java]这时没有初始话TestA的实例,打印结果为:Static block executed![/code]通过控制Class.forName中的true属性可以发现,当改变为false时,就不会执行输出语句。

------------------------------------------------------------
一个类的运行,JVM做会以下几件事情 1、类装载 2、链接 3、初始化 4、实例化;而初始化阶段做的事情是初始化静态变量和执行静态方法等的工作。所以,当Class.forName(args[0],true,off.getClass().getClassLoader());中的true变为false的时候,就是告诉JVM不需再load class之后进行initial的工作。这样,将initial的工作推迟到了newInstance的时候进行。所以,static块的绝对不是什么“只是在类被第一次实体化的时候才会被仅仅调用一次”,而应该是在类被初始化的时候,仅仅调用一次。
想也应该想到,如果是第一实例化才调用,那么JDBC Driver就没法加载了,JDBC Driver的加载就是利用了这个原理在静态块中向DriverManager注册自己的.

在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:

  装载:查找和导入类或接口的二进制数据;
  链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;
  校验:检查导入类或接口的二进制数据的正确性;
  准备:给类的静态变量分配并初始化存储空间;
  解析:将符号引用转成直接引用;
  初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

------------------------------------------------------------

以下可以参考对Class.forName()的解释:

首先java里面任何类都要加载到虚拟机上才能运行,class.forName()这句话就是装载用的(和new不一样)。JVM会执行静态代码段,要记住静态代码段是和class绑定的,class装载成功了,就代表静态代码段执行了,以后就不会再走这段代码了。

在初始化一个类,生成一个实例时,class.newInstance()和new class()除了一个是方法,一个是关键字外还有什么区别,它们的区别在于,前者是使用类加载机制,后者是创建一个新类。为什么会有两种创建方式?这主要考虑到软件的可伸缩,扩展和重用等软件设计思想。

java工厂模式中经常用到newInstance方法来创建对象,因此可以从为什么使用工厂模式中找到答案。[code=java]class c=Class.forName("Example");  
factory =(ExampleInterface)c.newInstance();(其中ExampleInterface是Example的接口)[/code]也可以写成如下形式:[code=java]String className="Example";
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();[/code]进一步可以写成如下形式:[code=java]String className= readingfromXmlConfig;(从xml配置文件中获得字符串)
class c =Class.forName(className);
factory = (ExampleInterface)c.newInstance();[/code]上面代码已经存在Example类名字,它的优点是无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example1,Example2等等,只要他们继承ExampleInterface接口就可以。JVM的角度看,使用关键字new创建一个新类时,该类可以没被加载,使用newInstance方法的时候就必须保证该类已经被加载且这个类已经连接了。类加载是通过class的静态加载方法forName()实现的。

最后简单区分new关键字和newInstance()方法的区别:

newInstance:弱类型,低效率,只能用无参构造。
new:强类型,能调用任何public构造方法。
[ 本帖最后由 詹季春 于 2011-07-25  00:56 编辑 ]

评分

参与人数 1技术分 +3 收起 理由
小龙 + 3 不错的同学

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-25 00:23:45
藤椅

回复 楼主 的帖子

就是像你所说,初始化用的,应该是在创建了该类对象时就会执行,其实当类的定义中不含有static块时,编译器会为该类提供一个默认的static块。当然这是在含有静态变量初始化操作的前提下。如果静态变量没有初始化操作,则编译器不会为之提供默认的static块。

评分

参与人数 1技术分 +1 收起 理由
小龙 + 1 答题有分!

查看全部评分

回复 使用道具 举报
黑马网友  发表于 2011-7-25 00:22:55
沙发
它是定义静态变量或者静态函数的时候使用该关键字。
被定义为static的函数,可以不需要new一个新类别而直接调用
比如Math类里有一个,public static sub()方法,那么你可以直接Math.sub()调用该方法。
所谓静态方法和静态变量,程序一启动,便在内存中初始化了。而不需要通过构造函数进行new。
下面给几个应用的例子:
1、修饰类的变量,该变量称之为静态变量
Java代码  
class A {   
    static int b;   
}  

class A {
    static int b;
}


2、修饰类的方法,该方法称之为静态方法
Java代码  
class A {   
    static void b(){   
    }   
}  

class A {
    static void b(){
    }
}


3、修饰嵌套类(接口),改类被称之为静态嵌套类(接口),通过静态的方式来访问它:
Java代码  
public class T {   
    public static void main(String[] args) {   
        A a = new A();   
        A.B b = new A.B();   
        A.C c = a.new C();   
        System.out.println("a=" + a);   
        System.out.println("b=" + b);   
        System.out.println("c=" + c);   
    }   
}   
  
class A {   
    static class B {   
    }   
  
    class C {   
    }   
}  

public class T {
    public static void main(String[] args) {
        A a = new A();
        A.B b = new A.B();
        A.C c = a.new C();
        System.out.println("a=" + a);
        System.out.println("b=" + b);
        System.out.println("c=" + c);
    }
}

class A {
    static class B {
    }

    class C {
    }
}


4、声明一个类的静态区域,静态区域的代码执行完毕,方完成类的初始化:
Java代码  
class A {   
    static {   
        System.out.println("Hello World");   
    }   
}

评分

参与人数 1技术分 +2 收起 理由
小龙 + 2 不错,不错!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马