static_static java - CSDN
static 订阅
像在VB,C#,C,C++,Java,PHP,Objective-C,JavaScript中我们可以看到static作为关键字和函数出现,在其他的高级计算机语言如FORTRAN、ALGOL、COBOL、BASIC、LISP、SNOBOL、PL/1、Pascal、PROLOG、Ada等语言中也是有出现的,只是有着不同的作用,对于其具体作用,读者有需要的时候是可以具体查阅的。 展开全文
像在VB,C#,C,C++,Java,PHP,Objective-C,JavaScript中我们可以看到static作为关键字和函数出现,在其他的高级计算机语言如FORTRAN、ALGOL、COBOL、BASIC、LISP、SNOBOL、PL/1、Pascal、PROLOG、Ada等语言中也是有出现的,只是有着不同的作用,对于其具体作用,读者有需要的时候是可以具体查阅的。
信息
举    例
VB,C#,C,C++,PHP
来    自
高级计算机语言
分    类
关键字
中文名
静态
外文名
static
staticC++中
C与C++#的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。 [1]  静态全局变量在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下:静态全局变量有以下特点:该变量在全局数据区分配内存;未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为0);静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下图:代码区 //low address全局数据区堆区栈区 //high address一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将static int n; //定义静态全局变量改为int n; //定义全局变量程序照样正常运行。的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突;您可以将上述示例代码改为如下:编译并运行Example 2,您就会发现上述代码可以分别通过编译,但运行时出现错误。试着将static int n; //定义静态全局变量改为int n; //定义全局变量再次编译运行程序,细心体会全局变量和静态全局变量的区别。注意:全局变量和全局静态变量的区别1)全局变量是不显式用static修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过extern 全局变量名的声明,就可以使用全局变量。2)全局静态变量是显式用static修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用extern声明也不能使用。静态局部变量在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。我们先举一个静态局部变量的例子,如下通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。静态局部变量有以下特点:该变量在全局数据区分配内存;静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;静态函数在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。静态函数的例子:定义静态函数的好处:静态函数不能被其它文件所用;其它文件中可以定义相同名字的函数,不会发生冲突;(类中的static关键字)静态数据成员在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。可以看出,静态数据成员有以下特点:对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;静态数据成员和普通数据成员一样遵从public,protected,private访问规则;因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:<数据类型><类名>::<静态数据成员名>=<值>类的静态数据成员有两种访问形式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这 有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次, 则所有存款类对象的利息全改变过来了;同全局变量相比,使用静态数据成员有两个优势:静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;静态成员函数与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部 实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指 针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。关于静态成员函数,可以总结为以下几点:出现在类体外的函数定义不能指定关键字static;静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;非静态成员函数可以任意地访问静态成员函数和静态数据成员;静态成员函数不能访问非静态成员函数和非静态数据成员;由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;调用静态成员函数,可以用成员访问操作符(.)和(->;)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:<;类名>::<;静态成员函数名>;(<;参数表>;)调用类的静态成员函数。作用static静态变量声明符。在声明它的程序块,子程序块或函数内部有效,值保持,在整个程序期间分配存储器空间,编译器默认值0。是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。为什么要引入static函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。什么时候用static需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。内部机制静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。优势可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。应用格式引用静态数据成员时,采用如下格式:<;类名>::<;静态成员名>如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。注意事项⑴类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。⑵不能将静态成员函数定义为虚函数。⑶由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。⑷由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于线程函数身上。⑸static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。⑹静态数据成员在<;定义或说明>;时前面加关键字static。⑺静态数据成员是静态存储的,所以必须对它进行初始化。⑻静态成员初始化与一般数据成员初始化不同:初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;初始化时不加该成员的访问权限控制符private,public等;初始化时使用作用域运算符来标明它所属类;所以我们得出静态数据成员初始化的格式:<;数据类型><;类名>::<;静态数据成员名>=<;值>⑼为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。在各通信公司的笔试面试中经常出现的考题就是static的作用及功能。
收起全文
精华内容
参与话题
  • 深入理解static关键字

    万次阅读 多人点赞 2019-11-23 20:47:29
    文章目录1、static存在的主要意义2、static的独特之处3、静态变量和实例变量的概念4、静态变量和实例变量【重点常用】5、static静态方法6、static代码块7、static应用场景 1、static存在的主要意义 static的主要.....

    提到static关键字,相信大家都不陌生,这是相对比较难以理解的一个关键字,相信各位也都能深深感受的到!本篇文章将好好总结一下static这个关键字。

    在开始讲static之前,我想让各位看一段有意思的代码:

    public class Test {
         
        static{
            System.out.println("test static 1");
        }
      
        static{
            System.out.println("test static 2");
        }
        
        public static void main(String[] args) {
             
        }
    }
    

    看完程序,小白童鞋发话了:啥玩意?main方法中啥都没有,能运行啥?博主你个星星星…

    运行结果:
    test static 1
    test static 2
    

    小白童鞋:那啥…那啥…博主我说啥了,我啥都没说…

    其实,上面的代码懂的自然懂,不懂的自然就不懂了,因为上面的代码涉及到JVM的类加载了!当然不在本篇博客文章的范畴内,如果有兴趣理解上面的程序,这篇文章可能会对你有所帮助

    别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】

    1、static存在的主要意义

    static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法

    static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

    为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

    2、static的独特之处

    1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享

    怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】…我觉得我已经讲的很通俗了,你明白了咩?

    2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。

    3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!

    4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。

    3、static应用场景

    因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量

    因此比较常见的static应用场景有:

    1、修饰成员变量
    2、修饰成员方法
    3、静态代码块
    4、修饰类【只能修饰内部类也就是静态内部类】
    5、静态导包

    以上的应用场景将会在下文陆续讲到…

    4、静态变量和实例变量的概念

    静态变量:
    static修饰的成员变量叫做静态变量【也叫做类变量】,静态变量是属于这个类,而不是属于是对象。

    实例变量:
    没有被static修饰的成员变量叫做实例变量,实例变量是属于这个类的实例对象。

    还有一点需要注意的是:static是不允许用来修饰局部变量,不要问我问什么,因为java规定的!

    5、静态变量和实例变量区别【重点常用】

    静态变量:
    静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

    实例变量:
    每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

    我相信各位智商都比宜春智商要高,应该都能理解上面的话。下面举了例子完全出于娱乐,理解了大可不必看,下面的例子仅供参考,仅供娱乐一下下气氛,赶时间的熊dei大可略过!

    怎么理解呢?打个比喻吧…就比方说程序员小王是一个比较温柔阳光的男孩子,这1024的这一天,老板闲的没事,非要拉着程序员小王来玩耍,怎么个玩法呢?老板和小王一人拿着一把菜刀,规则很简单,互相伤害,一人一刀,你一刀,我一刀…游戏一开始,老板二话不说,跳起来就是一刀,程序员小王二话也没说反手就是一菜刀回去,这个时候老板发飙了,双眼瞪得忒大,跳起来又是一刀,这个时候程序员小王不敢还手了,就没动手。没想到老板越来越生猛,左一刀右一刀全程下来差不多砍个半个时…程序员小王一直没有还过手,因为小王知道他是老板…

    这个程序员小王只会在老板第一次挥刀的时候,回老板一刀,之后就不还手了,这个时候我们把程序员小王看做是静态变量,把老板第一次向小王挥刀看做是类加载,把小王回老板一刀看出是分配内存空间,而一人一刀这个回合过程看成是类加载的过程,之后老板的每一刀都看成是创建一次对象。

    连贯起来就是static变量值在类第一次加载的时候分配空间,以后创建类对象的时候不会重新分配

    之后这个老板挨了一刀之后躺医院了一年,一出院回到公司第一件事就是拉程序员宜春出来玩耍,老板殊不知其然,这个博主程序员宜春性格异常暴躁,老板递给程序员宜春一把菜刀,博主宜春一接过菜刀,猝不及防的被老板跳起来就是一刀,程序员宜春痛的嗷了一声,暴躁的程序员宜春还没嗷完,在嗷的同时跳起来就是给老板一刀,接着老板跳起来又是一刀,程序员宜春嗷的一声又是回一刀,老板跳起来又一刀,程序员宜春嗷的一声又是回一刀,只要老板没停程序员宜春就没停,因为程序员宜春知道,就自己这曝脾气,暴躁起来si都敢摸,肯定有几个老铁知道…

    程序员宜春就类似实例变量,每次创建对象,都会为每个对象分配成员变量内存空间,就像老板来一刀,程序员宜春都会回一刀这样子的…

    6、访问静态变量和实例变量的两种方式

    我们都知道静态变量是属于这个类,而不是属于是对象,static独立于对象。

    但是各位有木有想过:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问【只要访问权限足够允许就行】,不理解没关系,来个代码就理解了

    public class StaticDemo {
    
            static int value = 666;
    
            public static void main(String[] args) throws Exception{
                new StaticDemo().method();
            }
    
            private void method(){
                int value = 123;
                System.out.println(this.value);
            }
    
    }
    

    猜想一下结果,我猜你的结果是123,哈哈是咩?其实

    运行结果: 666
    

    当然肯定有一些基础非常扎实的大佬会问为什么会有同学认为输出是123 。里面定义的value=123只是一个很普通的局部变量而已 。和成员变量没有半毛钱关系 。和静态变量也没有关系。是的!确实如这位大佬说的一样!只是博主我说的同学是小白同学,站在小白童鞋的角度上,所以还望大佬理解见谅!我举的这个StaticDemo例子主要目的是说明一下this也是可以访问static的变量的!!!value=123只是一个跑龙套的配角,旨在让小白同学认清其中的关系。

    回过头再去品味一下上面的那段话,你就能非常客观明了了,这个思想概念要有只是这种用法不推荐!

    因此小结一下访问静态变量和实例变量的两种方法:

    静态变量:

    类名.静态变量

    对象.静态变量(不推荐)

    静态方法:

    类名.静态方法

    对象.静态方法(不推荐)

    7、static静态方法

    static修饰的方法也叫做静态方法,不知道各位发现咩有,其实我们最熟悉的static静态方法就是main方法了小白童鞋:喔好像真的是哦。由于对于静态方法来说是不属于任何实例对象的,this指的是当前对象,因为static静态方法不属于任何对象,所以就谈不上this了。

    还有一点就是:构造方法不是静态方法

    8、static静态代码块

    先看个程序吧,看看自个是否掌握了static代码块,下面程序代码继承关系为 BaseThree——> BaseTwo——> BaseOne

    BaseOne类

    package com.gx.initializationblock;
    
    public class BaseOne {
    
        public BaseOne() {
            System.out.println("BaseOne构造器");
        }
    
        {
            System.out.println("BaseOne初始化块");
            System.out.println();
        }
    
        static {
            System.out.println("BaseOne静态初始化块");
    
        }
    
    }
    

    BaseTwo类

    package com.gx.initializationblock;
    
    public class BaseTwo extends BaseOne {
        public BaseTwo() {
            System.out.println("BaseTwo构造器");
        }
    
        {
            System.out.println("BaseTwo初始化块");
        }
    
        static {
            System.out.println("BaseTwo静态初始化块");
        }
    }
    

    BaseThree 类

    package com.gx.initializationblock;
    
    public class BaseThree extends BaseTwo {
        public BaseThree() {
            System.out.println("BaseThree构造器");
        }
    
        {
            System.out.println("BaseThree初始化块");
        }
    
        static {
            System.out.println("BaseThree静态初始化块");
        }
    }
    

    测试demo2类

    package com.gx.initializationblock;
    
    /*
         注:这里的ABC对应BaseOne、BaseTwo、BaseThree 
     * 多个类的继承中初始化块、静态初始化块、构造器的执行顺序
         在继承中,先后执行父类A的静态块,父类B的静态块,最后子类的静态块,
         然后再执行父类A的非静态块和构造器,然后是B类的非静态块和构造器,最后执行子类的非静态块和构造器
     */
    public class Demo2 {
        public static void main(String[] args) {
            BaseThree baseThree = new BaseThree();
            System.out.println("-----");
            BaseThree baseThree2 = new BaseThree();
    
        }
    }
    

    运行结果

    BaseOne静态初始化块
    BaseTwo静态初始化块
    BaseThree静态初始化块
    BaseOne初始化块
    
    BaseOne构造器
    BaseTwo初始化块
    BaseTwo构造器
    BaseThree初始化块
    BaseThree构造器
    -----
    BaseOne初始化块
    
    BaseOne构造器
    BaseTwo初始化块
    BaseTwo构造器
    BaseThree初始化块
    BaseThree构造器
    

    至于static代码块运行结果不是很清晰的童鞋,详细讲解请看这篇Static静态代码块以及各代码块之间的执行顺序

    以上仅仅是让各位明确代码块之间的运行顺序,显然还是不够的,静态代码块通常用来对静态变量进行一些初始化操作,比如定义枚举类,代码如下:

    public enum WeekDayEnum {
        MONDAY(1,"周一"),
        TUESDAY(2, "周二"),
        WEDNESDAY(3, "周三"),
        THURSDAY(4, "周四"),
        FRIDAY(5, "周五"),
        SATURDAY(6, "周六"),
        SUNDAY(7, "周日");
     
        private int code;
        private String desc;
     
        WeekDayEnum(int code, String desc) {
            this.code = code;
            this.desc = desc;
        }
     
        private static final Map<Integer, WeekDayEnum> WEEK_ENUM_MAP = new HashMap<Integer, WeekDayEnum>();
     
        // 对map进行初始化
        static {
            for (WeekDayEnum weekDay : WeekDayEnum.values()) {
                WEEK_ENUM_MAP.put(weekDay.getCode(), weekDay);
            }
        }
     
        public static WeekDayEnum findByCode(int code) {
            return WEEK_ENUM_MAP.get(code);
        }
     
        public int getCode() {
            return code;
        }
     
        public void setCode(int code) {
            this.code = code;
        }
     
        public String getDesc() {
            return desc;
        }
     
        public void setDesc(String desc) {
            this.desc = desc;
        }
    } 
    

    当然不仅仅是枚举这一方面,还有我们熟悉的单例模式同样也用到了静态代码块,如下:

    public class Singleton {
        private static Singleton instance;
     
        static {
            instance = new Singleton();
        }
     
        private Singleton() {}
     
        public static Singleton getInstance() {
            return instance;
        }
    }
    

    9、static变量与普通变量区别

    static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

    还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。

    10、静态内部类

    静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

    1、它的创建是不需要依赖外围类的创建。
    2、它不能使用任何外围类的非static成员变量和方法。

    代码举例(静态内部类实现单例模式)

    public class Singleton {
        
       // 声明为 private 避免调用默认构造方法创建对象
        private Singleton() {
        }
        
       // 声明为 private 表明静态内部该类只能在该 Singleton 类中被访问
        private static class SingletonHolder {
            private static final Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getUniqueInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    
    

    Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance()方法从而触发 SingletonHolder.INSTANCESingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。

    这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。

    11、静态导包

    静态导包格式:import static

    这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法

    //  Math. --- 将Math中的所有静态资源导入,这时候可以直接使用里面的静态方法,而不用通过类名进行调用
    //  如果只想导入单一某个静态方法,只需要将换成对应的方法名即可
     
    import static java.lang.Math.;
    //  换成import static java.lang.Math.max;具有一样的效果
     
    public class Demo {
    	public static void main(String[] args) {
     
    		int max = max(1,2);
    		System.out.println(max);
    	}
    }
    

    静态导包在书写代码的时候确实能省一点代码,可以直接调用里面的静态成员,但是会影响代码可读性,所以开发中一般情况下不建议这么使用。

    12、static注意事项

    1、静态只能访问静态。
    2、非静态既可以访问非静态的,也可以访问静态的。

    13、final与static的藕断丝连

    到这里文章本该结束了的,但是static的使用始终离不开final字眼,二者可谓藕断丝连,常常繁见,我觉得还是很有必要讲讲,那么一起来看看下面这个程序吧。

    package Demo;
    
    class FinalDemo {
        public final double i = Math.random();
        public static double t = Math.random();
    }
    
    public class DemoDemo {
        public static void main(String[] args) {
    
            FinalDemo demo1 = new FinalDemo();
            FinalDemo demo2 = new FinalDemo();
            System.out.println("final修饰的  i=" + demo1.i);
            System.out.println("static修饰的 t=" + demo1.t);
            System.out.println("final修饰的  i=" + demo2.i);
            System.out.println("static修饰的 t=" + demo2.t);
    
            System.out.println("t+1= "+ ++demo2.t );
    //      System.out.println( ++demo2.i );//编译失败
          }
    }
    运行结果:
    	final修饰的  i=0.7282093281367935
    	static修饰的 t=0.30720545678577604
    	final修饰的  i=0.8106990945706758
    	static修饰的 t=0.30720545678577604
    	t+1= 1.307205456785776
    
    

    static修饰的变量没有发生变化是因为static作用于成员变量只是用来表示保存一份副本,其不会发生变化。怎么理解这个副本呢?其实static修饰的在类加载的时候就加载完成了(初始化),而且只会加载一次也就是说初始化一次,所以不会发生变化!

    至于final修饰的反而发生变化了?是不是巅覆你对final的看法?关于final详细讲解博主也准备好了一篇文章程序员你真的理解final关键字吗?

    ok,文章就先到这里了,希望这篇文章能够帮助到你对static的认识,若有不足或者不正之处,希望谅解并欢迎批评指正!

    如果本文章对你有帮助,哪怕是一点点,那就请点一个赞呗,谢谢~

    参考:
    《java编程思想》
    http://baijiahao.baidu.com/s?id=1601254463089390982&wfr=spider&for=pc
    https://blog.csdn.net/qq_34337272/article/details/82766943
    https://www.cnblogs.com/dolphin0520/p/3799052.html

    最后,欢迎各位关注我的公众号,一起探讨技术,向往技术,追求技术

    在这里插入图片描述

    展开全文
  • static的作用与用法

    千次阅读 2018-04-20 11:08:39
    1、什么是staticstatic 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。 2、为什么要引入static? 函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在...

    1、什么是static?
           static 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。

        2、为什么要引入static?
           函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。

        3、什么时候用static?
           需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。

        4、static的内部机制:
           静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
           这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。
          静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
          static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态
    数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

        5、static的优势:
           可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。

        6、引用静态数据成员时,采用如下格式:
             <类名>::<静态成员名>
        如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。

        7、注意事项:
          (1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。
          (2)不能将静态成员函数定义为虚函数。
          (3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地址是指向其数据类型的指针,函数地址类型是一个“nonmember函数指针”。

          (4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于线程函数身上。
          (5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。
          (6)静态数据成员在<定义或说明>时前面加关键字static。
          (7)静态数据成员是静态存储的,所以必须对它进行初始化。
          (8)静态成员初始化与一般数据成员初始化不同:
           初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
           初始化时不加该成员的访问权限控制符private,public等;
               初始化时使用作用域运算符来标明它所属类;
               所以我们得出静态数据成员初始化的格式:
             <数据类型><类名>::<静态数据成员名>=<值>
          (9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。

    静态数据成员

      在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。

      使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。

      静态数据成员的使用方法和注意事项如下:

      1、静态数据成员在定义或说明时前面加关键字static。

      2、静态成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式如下:

        <数据类型><类名>::<静态数据成员名>=<值>

      这表明:

            (1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。

      (2) 初始化时不加该成员的访问权限控制符private,public等。

      (3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。

      3、静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。

      4、引用静态数据成员时,采用如下格式:

       <类名>::<静态成员名>

      如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员。

    静态成员函数

      静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。

      在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。如果静态成员函数中要引用非静态成员时,可通过对象来引用。


    下面看一个例子:
    #include <iostream.h>
    class Point
    {
    public:
    void output()
    {
    }
    static void init()
    {  

    };
    void main( void )
    {
    Point pt;
    pt.init();
    pt.output(); 
    }
    这样编译是不会有任何错误的。
    下面这样看
    #include <iostream.h>
    class Point
    {
    public:
    void output()
    {  
    }
    static void init()
    {  

    };
    void main( void )
    {
    Point::output();
    }
    这样编译会处错,错误信息:illegal call of non-static member function,为什么?
    因为在没有实例化一个类的具体对象时,类是没有被分配内存空间的。
    好的再看看下面的例子:
    #include <iostream.h>
    class Point
    {
    public:
    void output()
    {  
    }
    static void init()
    {  

    };
    void main( void )
    {
    Point::init();
    }
    这时编译就不会有错误,因为在类的定义时,它静态数据和成员函数就有了它的内存区,它不属于类的任何一个具体对象。
    好的再看看下面的例子:
    #include <iostream.h>
    class Point
    {
    public:
    void output()
    {  
    }
    static void init()

       x = 0;
       y = 0;
    }
    private:
    int x;
    int y;
    };
    void main( void )
    {
    Point::init();
    }
    编译出错:
    illegal reference to data member 'Point::x' in a static member function
    illegal
     reference to data member 'Point::y' in a static member function
    在一个静态成员函数里错误的引用了数据成员,
    还是那个问题,静态成员(函数),不属于任何一个具体的对象,那么在类的具体对象声明之前就已经有了内存区,
    而现在非静态数据成员还没有分配内存空间,那么这里调用就错误了,就好像没有声明一个变量却提前使用它一样。
    也就是说在静态成员函数中不能引用非静态的成员变量。
    好的再看看下面的例子:
    #include <iostream.h>
    class Point
    {
    public:
    void output()
    {
       x = 0;
       y = 0;
       init();  
    }
    static void init()
    {

    }
    private:
    int x;
    int y;
    };
    void main( void )
    {
    Point::init();
    }
    好的,这样就不会有任何错误。这最终还是一个内存模型的问题,
    任何变量在内存中有了自己的空间后,在其他地方才能被调用,否则就会出错。
    好的再看看下面的例子:
    #include <iostream.h>
    class Point
    {
    public:
    void output()

    }
    static void init()

       x = 0;
       y = 0;
    }
    private:
    static int x;
    static int y;
    };
    void main( void )
    {
    Point::init();
    }
    编译:
    Linking...
    test.obj : error LNK2001: unresolved external symbol "private: static int Point::y" 
    test.obj : error LNK2001: unresolved external symbol "private: static int Point::x" 
    Debug/Test.exe : fatal error LNK1120: 2 unresolved externals
    执行 link.exe 时出错.
    可以看到编译没有错误,连接错误,这又是为什么呢?
    这是因为静态的成员变量要进行初始化,可以这样:
    #include <iostream.h>
    class Point
    {
    public:
    void output()

    }
    static void init()

       x = 0;
       y = 0;
    }
    private:
    static int x;
    static int y;
    };
    int Point::x = 0;
    int Point::y = 0;
    void main( void )
    {
    Point::init();
    }
    在静态成员数据变量初始化之后就不会出现编译错误了。
    再看看下面的代码:
    #include <iostream.h>
    class Point
    {
    public:
    void output()

    }
    static void init()

       x = 0;
       y = 0;
    }
    private:
    static int x;
    static int y;
    };
    void main( void )
    {
    }
    编译没有错误,为什么?
    即使他们没有初始化,因为我们没有访问x,y,所以编译不会出错。  

    C++会区分两种类型的成员函数:静态成员函数和非静态成员函数。这两者之间的一个重大区别是,静态成员函数不接受隐含的this自变量。所以,它就无法访问自己类的非静态成员。

    在某些条件下,比如说在使用诸如pthread(它不支持类)此类的多线程库时,就必须使用静态的成员函数,因为其地址同C语言函数的地址兼容。这种铜限制就迫使程序员要利用各种解决办法才能够从静态成员函数访问到非静态数据成员。

    第一个解决办法是声明类的所有数据成员都是静态的。运用这种方式的话,静态的成员函数就能够直接地访问它们,例如:

    class Singleton
    {
    public:
       static Singleton * instance();
    private:
       Singleton * p;
       static Lock lock;
    };


    Singleton * Singleton::instance()
    {
    lock.getlock(); 
    // fine, lock is static
    if (!p)
       p=new Singleton;
    lock.unlock();
    return p;
    }

    这种解决方法不适用于需要使用非静态数据成员的类。

    访问非静态数据成员

    将参照传递给需要考量的对象能够让静态的成员函数访问到对象的非静态数据:

    class A
    {
    public:
       static void func(A & obj);
       intgetval() const; 
    //non-static member function
    private:
    intval;
    };

    静态成员函数func()会使用参照obj来访问非静态成员val

    voidA::func(A & obj)
    {
       int n = obj.getval();
    }

    将一个参照或者指针作为静态成员函数的自变量传递,就是在模仿自动传递非静态成员函数里this自变量这一行为。

    展开全文
  • c语言中static关键字用法详解

    万次阅读 多人点赞 2020-01-02 13:18:18
    static关键字在c语言中比较常用,使用恰当能够大大提高程序的模块化特性,有利于扩展和维护。 但是对于c语言初学者,static由于使用灵活,并不容易掌握。本文就static在c语言中的应用进行总结,供参考使用。错漏...

    概述

    static关键字在c语言中比较常用,使用恰当能够大大提高程序的模块化特性,有利于扩展和维护。

    但是对于c语言初学者,static由于使用灵活,并不容易掌握。本文就static在c语言中的应用进行总结,供参考使用。错漏之处,请不吝指正。

    最后一节加入了c++面向对象中static的使用特性,当作拓展阅读。


    在程序中使用static

    变量

    1. 局部变量

    普通局部变量是再熟悉不过的变量了,在任何一个函数内部定义的变量(不加static修饰符)都属于这个范畴。编译器一般不对普通局部变量进行初始化,也就是说它的值在初始时是不确定的,除非对其显式赋值。

    普通局部变量存储于进程栈空间,使用完毕会立即释放。

    静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。

    变量在全局数据区分配内存空间;编译器自动对其初始化
    其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束

    小程序体会一下静态局部变量的威力:

    #include <stdio.h>
    
    void fn(void)
    {
        int n = 10;
    
        printf("n=%d\n", n);
        n++;
        printf("n++=%d\n", n);
    }
    
    void fn_static(void)
    {
        static int n = 10;
    
        printf("static n=%d\n", n);
        n++;
        printf("n++=%d\n", n);
    }
    
    int main(void)
    {
        fn();
        printf("--------------------\n");
        fn_static();
        printf("--------------------\n");
        fn();
        printf("--------------------\n");
        fn_static();
    
        return 0;
    }
    

    运行结果如下:

    -> % ./a.out 
    n=10
    n++=11
    --------------------
    static n=10
    n++=11
    --------------------
    n=10
    n++=11
    --------------------
    static n=11
    n++=12
    

    可见,静态局部变量的效果跟全局变量有一拼,但是位于函数体内部,就极有利于程序的模块化了。

    2. 全局变量

    全局变量定义在函数体外部,在全局数据区分配存储空间,且编译器会自动对其初始化。

    普通全局变量对整个工程可见,其他文件可以使用extern外部声明后直接使用。也就是说其他文件不能再定义一个与其相同名字的变量了(否则编译器会认为它们是同一个变量)。

    静态全局变量仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。

    在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。

    函数

    函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下:

    • 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
    • 不同的文件可以使用相同名字的静态函数,互不影响

    非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明

    下面两个文件的例子说明使用static声明的函数不能被另一个文件引用:

    /* file1.c */
    #include <stdio.h>
    
    static void fun(void)
    {
        printf("hello from fun.\n");
    }
    
    int main(void)
    {
        fun();
        fun1();
    
        return 0;
    }
    
    /* file2.c */
    #include <stdio.h>
    
    static void fun1(void)
    {
        printf("hello from static fun1.\n");
    }
    

    使用 gcc file1.c file2.c编译时,错误报告如下:

    /tmp/cc2VMzGR.o:在函数‘main’中:
    static_fun.c:(.text+0x20):对‘fun1’未定义的引用
    collect2: error: ld returned 1 exit status
    

    修改文件,不使用static修饰符,可在另一文件中引用该函数:

    /* file1.c */
    #include <stdio.h>
    
    void fun(void)
    {
        printf("hello from fun.\n");
    }
    
    /* file2.c */
    int main(void)
    {
        fun();
    
        return 0;
    }
    

    同样使用 gcc file1.c file2.c编译,编译通过,运行结果如下:

    -> % ./a.out 
    hello from fun.
    

    面向对象

    静态数据成员

    在类内数据成员的声明前加上static关键字,该数据成员就是类内的静态数据成员。其特点如下:

    • 静态数据成员存储在全局数据区,静态数据成员在定义时分配存储空间,所以不能在类声明中定义
    • 静态数据成员是类的成员,无论定义了多少个类的对象,静态数据成员的拷贝只有一个,且对该类的所有对象可见。也就是说任一对象都可以对静态数据成员进行操作。而对于非静态数据成员,每个对象都有自己的一份拷贝。
    • 由于上面的原因,静态数据成员不属于任何对象,在没有类的实例时其作用域就可见,在没有任何对象时,就可以进行操作
    • 和普通数据成员一样,静态数据成员也遵从public, protected, private访问规则
    • 静态数据成员的初始化格式:<数据类型><类名>::<静态数据成员名>=<值>
    • 类的静态数据成员有两种访问方式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

    同全局变量相比,使用静态数据成员有两个优势:

    • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
    • 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能
    静态成员函数

    与静态数据成员类似,静态成员函数属于整个类,而不是某一个对象,其特性如下:

    • 静态成员函数没有this指针,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数
    • 出现在类体外的函数定义不能指定关键字static
    • 非静态成员函数可以任意地访问静态成员函数和静态数据成员

    总结

    static是一个很有用的关键字,使用得当可以使程序锦上添花。当然,有的公司编码规范明确规定只用于本文件的函数要全部使用static关键字声明,这是一个良好的编码风格。

    无论如何,要在实际编码时注意自己的编码习惯,尽量体现出语言本身的优雅和编码者的编码素质。

    展开全文
  • static作用(修饰函数、局部变量、全局变量)

    万次阅读 多人点赞 2018-12-09 20:52:50
    C语言:static作用(修饰函数、局部变量、全局变量) 一、 static全局变量与普通的全局变量有什么区别 ? 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。  全局变量本身就是静态存储方式, ...

    C语言:static作用(修饰函数、局部变量、全局变量)

    一、 static全局变量与普通的全局变量有什么区别 ?
    全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。
      全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。
      这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
      static全局变量只初使化一次,防止在其他文件单元中被引用;
    二、static局部变量和普通局部变量有什么区别 ?
      把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。  
           static局部变量只被初始化一次,下一次依据上一次结果值;
    三、static函数与普通函数有什么区别?
    static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static修饰的函数),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件.
    static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
    四、static的三条重要作用,首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0。
           1、隐藏
              1.1当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是static_extern.c,另一个是static_main.c。
              1.2static_main.c

        #include<stdio.h>
         
        void main(void)
        {
            extern char i;    // extern variable must be declared before use
            printf("%c ", i);
            msg();
            return 0;
        }

              1.3static_extern.c

        char i = 'A'; // global variable
        void msg()
        {
            printf("I Love Beijing!I Love hanyue!\n");
        }

            1.4编译&执行

           1.5你可能会问:为什么在static_extern.c中定义的全局变量i和函数msg能在static_main.c中使用?前面说过,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,i是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件static_main.c是可见的。如果加了static,就会对其它源文件隐藏。例如在i和msg的定义前加上static,static_main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。Static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏。
     
         2、static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。
           2.1 static_main.c

        #include <stdio.h>
         
        int fun(void){
            static int count = 10;    // 事实上此赋值语句从来没有执行过
            return count--;
        }
         
        int count = 1;
         
        int main(void)
        {    
            printf("global\t\tlocal static\n");
            for(; count <= 10; ++count)
                printf("%d\t\t%d\n", count, fun());    
            
            return 0;
        }

         2.2编译&执行

    3、static的第三个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是’\0’。不妨做个小实验验证一下。
       3.1 static_main.c

        #include <stdio.h>
         
        int a;
         
        int main(void)
        {
            int i;
            static char str[10];
         
            printf("integer: %d;  string: (begin)%s(end)\n", a, str);
         
            return 0;
        }

         2.2编译&执行

     

     

     

    展开全文
  • 面试|static 关键字有什么作用

    万次阅读 多人点赞 2019-07-16 00:39:00
    今天主要学习下Java语言中的static关键字。 static关键字的含义及使用场景 static是Java50个关键字之一。static关键字可以用来修饰代码块表示静态代码块,修饰成员变量表示全局静态成员变量,修饰方法表示静态方法...
  • final && static

    2009-03-25 09:19:57
    一、final 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。 ...
  • static修饰的字段在类加载过程中的准备阶段被初始化为0或null等默认值,而后在初始化阶段(触发类构造器)才会被赋予代码中设定的值,如果没有设定值,那么它的值就为默认值。final修饰的字段在运行时被初始化(可以...
  • Static&&final关键字详解

    2019-05-20 15:50:27
    Static&&final static 1.静态属性的解析,以及类加载时如何初始化 事实上我们一般都是通过new一个对象来调用类的成员方法及变量。 但有些情况下,我们不去new一个对象也能够去访问其类的成员方法和变量----...
  • static关键字的四种用法

    万次阅读 多人点赞 2018-03-26 16:34:58
    在java的关键字中,static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构。下面我们先来了解一下static关键字及其用法。...
  • static && final

    2018-02-18 17:16:42
    static内存图解 要点: final定义一个常量,不能被改变。且定义的方法不能被继承。 final static定义一个全局静态常量,不可改变 在静态方法中一定不能调用非静态成员,但在非静态方法中可以调用静态成员 ...
  • static 关键字详解

    万次阅读 多人点赞 2018-09-19 08:58:33
    static 关键字 static 关键字主要有以下四种使用场景 修饰成员变量和成员方法 静态代码块 修饰类(只能修饰内部类) 静态导包(用来导入类中的静态资源,1.5之后的新特性) 修饰成员变量和成员方法(常用) 被 static ...
  • C语言中的static 详细分析

    万次阅读 多人点赞 2011-08-23 11:31:41
    google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的初学者来说参考性不是很大。所以,我这篇博文博采众家之长,把互联网上的资料...
  • Java中static作用及用法详解

    万次阅读 多人点赞 2014-07-24 13:19:26
    static是静态修饰符,什么叫静态修饰符呢?大家都知道,在程序中任何变量或者代码都是在编译时由系统自动分配内存来存储的,而所谓静态就是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也...
  • 出现 static declaration follows non-static declaration 这种错误, 原因是 调用的静态函数没有先声明一下,就是它定义在你调用之后啦。 解决:调用之前声明一下这个函数。
  • 没有在int前加static报错。
  • centos7查看服务开机启用和禁用的方法 加入开机启动 systemctl enable mysqld; systemctl enable firewalld.service ; systemctl enable httpd.service; 先关闭,停止运行服务 ...systemctl di...
  • 今天敲代码的时候遇到了这个问题,大体这个问题可以简化成这样;public class Test1 { public String get() ... public static void main(String[] args) { String string =get(); } }显示 Ca
  • private static 与 public static的区别

    万次阅读 多人点赞 2009-09-25 22:45:00
     static: 静态成员,不能实例化,在你运行的时候他自己在内存中开辟了块空间,不用new, 有点像全局变量static是静态的意思,public或private与其他成员一样 1、访问static成员,用类而不是实例化的对象; 2、static...
  •  之所以会报Cannot make a static reference to the non-static field email这个错,  是因为在静态方法中,不能直接访问非静态成员(包括方法和变量)。  因为,非静态的变量是依赖于对象存在的,对象必须...
  • C++static类成员,static类成员函数

    万次阅读 多人点赞 2017-03-30 10:01:40
    1.static类成员 在C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处在。static类数据成员是与类关联的,但不与该类定义的对象有任何关系。这句话什么意思?就是static不会...
1 2 3 4 5 ... 20
收藏数 4,703,208
精华内容 1,881,283
关键字:

static