Object-C中的变量类型以及程序内存的内存分区

一, 内存分配, 一般来说有几个分区:

1.栈区(stack)  2堆区(heap)  3.全局区(静态区)(static) 4.文字常量区 5 程序代码区


二.作用域
全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。(C和C++)
局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。(在栈区中)
静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量
从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。 

三. 在Object-C中使用全局变量与静态变量

   1.首先说明 extern 关键字. 

     语义为:外部的, 外来的.extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他类中寻找其定义。 另外,extern也可用来进行链接指定。
      需要注意的是: 在使用extern的时候要对应声明时候的格式. 比如


A.h中

 //声明count标识符为int类型, 因为是基本数值类型, 所以在OC编译器在全局数据区中分配了空间, 初值为0;
NSString *globalStr; //声明str标识符, 不属于基本类型, 并未初始化与分配空间, str指向nil

@interface A : NSObject

B.m中

//********************************************
//这里告诉编译器, 这个文件中需要两个如下标识符的全局变量, 但是是从外部(extern)引入的
//也就是说声明了两个外部全局变量. 在编译的时候, 编译器会从外部文件中根据声明的标识符寻找变量.
extern int globalCount;
extern NSString *globalStr;
//********************************************


@interface B ()

测试:

A中写初始化方法:

+(void)initvariable
{
    globalCount = 999;
    globalStr = @"我被初始化了";
}


B.m中引入头文件:

<span style="font-size:14px;"><span style="font-size:12px;">#import "A.h"</span></span>
然后调用.

NSLog(@"初始化后输出变量");
    
    NSLog(@"globalCount is '%d'", globalCount);
    
    NSLog(@"globalStr is '%@'", globalStr);

    [A initvariable];
    
    NSLog(@"初始化后输出变量");
    
    NSLog(@"globalCount is '%d'", globalCount);
    
    NSLog(@"globalStr is '%@'", globalStr);
输出结果:

2014-07-28 17:04:37.379 VariableTestDemo[16716:60b]直接输出变量

2014-07-28 17:04:37.380 VariableTestDemo[16716:60b] globalCount is '0'

2014-07-28 17:04:37.380 VariableTestDemo[16716:60b] globalStr is '(null)'

2014-07-28 17:04:38.035 VariableTestDemo[16716:60b]初始化后输出变量

2014-07-28 17:04:38.036 VariableTestDemo[16716:60b] globalCount is '999'

2014-07-28 17:04:38.036 VariableTestDemo[16716:60b] globalStr is '我被初始化了'



以上说明了, 在文件中声明了全局变量, 就在所属文件内声明了一个全局标识符, 存放于全局数据区的未初始化区(NSString). 而作为基本数据类型的int, 则分配了空间放于已初始化区中.

    2.static变量 

		2.1.静态变量使用Static修饰符来进行修饰, 对变量使用Static修饰符, 则使变量在全局数据区中创建, 这个区也叫静态区(static area) 
 上代码:
tatic int staticCount; //声明静态的全局变量, 因为是基本数值类型, 编译器也进行了内存分配与赋值了, OC中初值为0;
static NSString *staticString; //声明静态全局变量, 对象类型, 没有初始化.
看看输出:

2014-07-28 17:20:58.174 VariableTestDemo[16849:60b] 初始化后输出变量

2014-07-28 17:20:58.175 VariableTestDemo[16849:60b] staticCount is '0'

2014-07-28 17:20:58.175 VariableTestDemo[16849:60b] staticString is '(null)'

		2.2静态全局变量有个区别, 就是可以在声明的时候进行初始化(定义),上代码:
static int staticCount = 2333333;
static NSString *staticString = @"我在这就能初始化!";
输出:

2014-07-28 17:23:03.279 VariableTestDemo[16879:60b] 初始化后输出变量

2014-07-28 17:23:03.279 VariableTestDemo[16879:60b] staticCount is '2333333'

2014-07-28 17:23:03.279 VariableTestDemo[16879:60b] staticString is '我在这就能初始化!'

 

   3.静态变量和外部全局变量的区别

网上搜了一下, 这问题挺让人混乱的, 这里试着理清一下, C/C++里面是这样的, 不知道OC里面是否一样, 不过介于OC与C/C++的关系, 应该是一样的.

实际上, 在变量声明的时候加上了static修饰符, 那个变量就可以叫做静态变量. 静态有个特点, 就是在声明的时候, 可以进行初始化, 大家可以看看上面小实验.  按着这个思路, 那么静态的变量是不是有 静态局部变量, 静态全局变量,  静态常量,? 对, 是有这些变量.

其实关于静态的 static, 只需要理解几点:

                             1.static声明的变量, 存放于静态区(全局数据区),对于当前文件,有且仅有一个

                             2.static声明的变量, 作用域最大就是声明这个变量的文件, 不会被其他文件引用. 

                             3.static声明的变量, 生命周期和整个程序相当. 

                             4.在编译的过程中, 编译器会对静态变量进行初始化一次, 在运行时不再进行初始化了. 也就是说你程序运行了, 所有的静态变量就已                                  经出生了, 这也验证了上面一条.

     3.1再来说说和全局变量的关系, 全局变量声明于函数之外, 作用域是整个文件, 但是对于其他文件, 可以通过对指定的变量标识符, 在函数外用extern          修饰符再声明一次, 获取其他文件的全局变量, 变为外部全局变量(这个称呼是针对使用extern的文件来说的)如以上例子中B.m, 对于B.m来说,                     globalCount与globalStr是外部全局变量(从A.h里面引进的)

          若对全局变量在声明时加上static, 称作静态全局变量, 根据以上静态变量的第2点, 这个静态全局变量的作用域被限制在声明它的文件中了, 也就是说, 如果再有其他文件对其使用extern修饰符来引用外部全局变量的话编译器在编译期间就会禁止这个行为, 导致无法编译通过. 这样就保护了文件中的全局变量, 不被外部引用作为外部全局变量. 减少使用外部全局变量可以减少文件(模块之间的耦合度), 所以不推荐使用外部全局变量.

     3.2 说说静态局部变量, 同样的, 只是因为是局部变量, 所以静态局部变量的作用域被缩小到了函数体内. 根据以上静态变量的第1第3点第4, 静态局部变量还是保存在静态区(全局数据区), 并且在编译期间就创建了, 直到程序结束才释放.只不过只能在其定义的函数之外就无法使用了,.

     3.3静态常量: 其实还是一样的, 静态特性:编译期间初始化, 存于静态区, 限定作用域不可大于其声明文件, 常量特性, 不可更改.

   4.补充

     1.全局变量和实例变量的区别 , 全局变量独立于实例, 是实例无关的, 也就是说, 多少个实例都共用一个全局变量.  但是每个实例变量都和一个单独的实例相关. 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 准备工作 在使用Spark抽取MySQL数据之前,需要进行一些准备工作。首先需要安装Spark和MySQL驱动程序,并设置好环境变量。 其次,需要创建好MySQL数据库,并在其创建需要抽取数据的数据表。 最后,需要创建好目标分区表,并在其添加好分区。 2. 编写Spark程序 以下代码展示了如何使用Spark抽取MySQL数据,并将其写入到分区: ```scala import org.apache.spark.SparkConf import org.apache.spark.SparkContext import org.apache.spark.sql.SQLContext import org.apache.spark.sql.SaveMode object MysqlToHive { def main(args: Array[String]) { val conf = new SparkConf().setAppName("MysqlToHive") val sc = new SparkContext(conf) val sqlContext = new SQLContext(sc) //设置MySQL连接参数 val url = "jdbc:mysql://localhost:3306/test" val driver = "com.mysql.jdbc.Driver" val username = "root" val password = "root" val database = "test" val table = "user" //设置Hadoop配置参数 val hadoopConf = sc.hadoopConfiguration hadoopConf.set("mapreduce.input.fileinputformat.input.dir.recursive", "true") //读取MySQL原始数据 val df = sqlContext.read.format("jdbc").options( Map("url" -> url, "driver" -> driver, "dbtable" -> table, "user" -> username, "password" -> password, "useSSL" -> "false") ).load() //取出最新数据 val latestData = df.groupBy("id").agg( max("update_time").alias("update_time") ) //将最新数据写入Hive分区 latestData.write.partitionBy("date").mode(SaveMode.Append).format("parquet").saveAsTable("ods.user") sc.stop() } } ``` 在上述代码,首先通过读取MySQL数据表获取原始数据,然后使用groupBy和agg操作进行分组和聚合,得到最新的数据。最后将最新数据写入到Hive分区。 3. 运行Spark程序 编写好Spark程序之后,就可以通过以下命令来运行程序了: ``` spark-submit --master local[*] --class com.example.MysqlToHive mysql-to-hive.jar ``` 其,--master参数表示使用本地模式运行程序,--class参数指定运行的名,mysql-to-hive.jar表示编译后的jar包。运行程序后,就可以从MySQL数据表抽取数据,并将其写入到Hive分区了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值