码迷,mamicode.com
首页 > 其他好文 > 详细

关于静态与非静态之详细总结

时间:2015-03-14 18:36:21      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

花费了些功夫,差不多搞明白了:

大家会看到有些地方不停重复出现——那就是你要找的东西

本文参考多处,具体出处就不写了。

静态和非静态:

字段、函数成员的声明中含static修饰符时是静态成员,否则是非静态成员(实例成员);

数据成员可以分静态变量、非静态变量两种. 静态成员属于类,而非静态成员(实例成员)属于对象。对于类的数据成员来说,如果是静态的,那么他将是类的一部分,为所有实例共享,如果是非静态的,则每个实例有一份考贝。


类的非静态成员属于类的实例所有,每创建一个类的实例都在内存中为非静态成员开辟了一块区域;而类的静态成员属于类所有,被这个类的所有实例所共享,无论这个类创建了多少个副本,一个静态成员在内存中只占有一块区域。


假如以E.M形式访问静态成员,E必须为类;访问实例成员,E必须是实例。
类的静态字段只分配一个存储单元,类的每个实例字段都有单独拷贝。
静态函数成员中不能访问实例成员,不能使用this;实例函数成员中可以访问实例成员和静态成员,可以使用this。

静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于内存,所以非静态成员可以直接访问类中静态的成员.

 
 非成静态员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成员的生存期决定于该类的生存期..而静态成员则不存在生存期的概念,因为静态成员始终驻留在内容中..


语法上来讲,静态函数没有this指针。由于没有this指针,就不能通过对象来引用,只能通过类名引用,
在静态函数内部也不能引用非静态的成员变量。调用普通函数的时候,类实例的this指针是作为第一个参数隐式传给函数的。从这里说,普通函数是依赖于类的实例的,没有类实例就不能调用。而static函数没有this这个隐含参数。所以调用它时不用依赖类实例。也就是可以采用className::funName的方式调用。类静态函数对于全局函数来说有一个好处就是可以使用类的private和protected成员(当他获得类实例指针的时候,比如参数传入)。

抽象的语义上来讲,静态函数的动作就是属于整个类的,不属于某个具体的对象。


静态和非静态主要有以下差别:
1.从存储的角度看,静态变量和方法在静态存储区分配内存,而非静态的在栈区或者堆上分配内存
2.从作用域来讲,静态变量在其作用域范围内存在于整个程序的运行过程中,而非静态变量的作用时间也是局部的。
3.从使用角度来讲,静态变量和方法没有this指针,只能通过类名引用。
4.对于类的数据成员来说,如果是静态的,那么他将是类的一部分,为所有实例共享,如果是非静态的,则每个实例有一份考贝。


 一个类中也可以包含静态成员和非静态成员,类中也包括静态构造函数和非静态构造函数..

对于类的数据成员来说,如果是静态的,那么他将是类的一部分,为所有实例共享,如果是非静态的,则每个实例有一份考贝。

静态成员函数只有一份拷贝,而普通成员函数在每个类对象中都有一份拷贝。

构造函数是对类或实例进行初始化的函数成员。
析构函数是在撤销类的实例时自动调用的函数成员。
出了构造函数和析构函数不能被继承,其他所有的成员都可以被继承。

静态构造函数:实现对一个类进行初始化的函数成员。

实例构造函数:创建实例时,用于执行对类的实例进行初始化的函数成员。
 
 对于winApp来说,静态成员对于程序员本身省了很多事,而且因为静态成员驻留内存,在方法与方法之间传递共享数据的时候,所以静态成员成了我的首选..但是不要因为方便,大量使用,尤其是在内存紧张或者
 用静态方法操作一些共享值的时候.或者要写多用户系统的时候,要慎之又慎.比如:
 static int id = 0;
 sql = "select * from table where id=" + id;

 
 如果这样写的话,在单机测试的时候没有问题,但是在多人同时对数据进行测试的时候,就会有问题了.假如,A用户访问他的id是20,则id的值在内存中为20,而此时B用户访问,他的id是30,则id在内存中的值是30..A用户的id值则被更改了..如果此时你将这个方法用非静态成员来写,则不会出现这样的情况..因为非静态成员是你声明的时候,实例化的时候才会分配内存..所以A用户访问的时候,App会因为A实例化而给A用户的请求分配内存..而B用户访问的时候也一样会因为B用户的访问而分配内存..所以两个用户访问的是不同的内存块..所以不会出现数据覆盖和错乱的现象...
 
我想这样的情况应该能很好的说明静态变量和非静态成员的区别..
  
相对于webApp而言,在winApp下使用static的时候要比webApp下考虑的因素要少的多,因为webApp本来就是一个多用户的系统,所以使用static的时候更应该小心..

而我对static在webApp下的使用存在一个疑问,如果一个静态方法,例如:

static string aa(string str){
 //经过一系列操作..
 return str;
}

或者返回一个DataSet的静态方法
static DataSet aa(string str){
 //经过一系列操作..
 return DataSet;
}

这个时候,在访问量大的时候,程序出现了并发,会不会发生错乱??我以前的项目使用的公用函数类中使用了大量的静态方法,不过好在访问量不大,一直没有问题..在发这个文章之前,我查找了MSDN,CSDN,搜索了一些关于静态成员的文章,但是都没有一个明确的说明..虽然,自己在项目中也测试了这么长时间也没有问题..但是总觉得有这个可能发生..

不知道大家是否在项目中碰到类似的疑惑呢??请有过这方面经验的朋友指教..


答案:
不说是否滥用,如果你出现冲突,说明你没有理解静态成员变量和静态方法的区别,静态方法本身只是一段代码,不管怎么调用他都不会出现问题。但静态成员变量就不行了,他被所有用户共享,如果一个用户改变了他,肯定会影响到别人,这就是常说的并发冲突问题,一般来说在修改共享成员变量时要lock!


关于静态方法和实例方法的一些误区。

一、    静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存。
 
    事实上,方法都是一样的,在加载时机和占用内存上,静态方法和实例方法是一样的,在类型第一次被使用时加载。调用的速度基本上没有差别。
 
 
二、    静态方法在堆上分配内存,实例方法在堆栈上。
 
    事实上所有的方法都不可能在堆或者堆栈上分配内存,方法作为代码是被加载到特殊的代码内存区域,这个内存区域是不可写的。
 
 
三、    实例方法需要先创建实例才可以调用,比较麻烦,静态方法不用,比较简单。
    事实上如果一个方法与他所在类型的实例无关,那么它就应该是静态的,决不会有人把它写成实例方法。所以所有的实例方法都与实例有关,既然与实例有关,那么创建实例就是必然的步骤,没有麻烦简单一说。实际上上你可以把所有的实例方法都写成静态的,将实例作为参数传入即可。
    有些方法看似与所在的实例无关,如IComparer.Compare方法,但实际上每一个实现这个接口的类都只会负责自己类型实例的比较,这是C#1.x规范中没有泛型所带来的历史遗留问题。
    大部分静态方法是与类的实例有关的,如各种Parse方法,他做成静态的原因是他没有实例作为参数。其他的大多是出于语义或者其他目的的考虑。
 
下面做了个简单的例子
技术分享技术分享Code

关于静态与非静态之详细总结

标签:

原文地址:http://blog.csdn.net/lxw907304340/article/details/44260927

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!