首页 文章 精选 留言 我的

精选列表

搜索[程序设计],共1339篇文章
优秀的个人博客,低调大师

C++面向对象程序设计课程笔记(第三周)

第一节 this指针 1.C++程序到C程序的翻译 图1 从C++到C C++中的class在C语言中并不存在,因此可以用struct(结构体)来代替,成员变量也可以直接用域来代替,但是类中的成员函数却无法在C语言中直接表示,所以只能把SetPrice设置为全局函数。由于是全局函数,为了能让其使用结构体内的数据,故在SetPrice中增加了一个参数struct CCar *this,这样就可以在函数体中把p的值传递给结构体中的price,实现了跟成员函数一样的功能,同理,在main()中SetPrice函数执行也得把car的地址传递过去。 故,this的作用就是指向成员函数所作用的对象。 2.this指针作用 (1)非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针。 图2 this指针作用 在main()函数中,首先对对象c1执行了AddOne()函数,然后开始执行AddOne(),对c1中的real加1,然后执行对c1的Print()函数,这之后,返回一个this指针所指向对Complex对象(即c1)给c2。 对this指针再加深一个理解,如下例: class A { int i; public: void Hello() {cout<<“”Hello”<<endl;} }; int main() { A *p=NULL; p->Hello(); } 系统会报错吗?答案是否定的,并且输出Hello。原因在于,虽然我们看着这个*p指向的空,但是实际上,由于C++在转换成C语言的时候,成员函数会被转换成全局函数并增加一个this指针的参数,即变为了 void Hello(A *this){cout <<”Hello”<<endl; 主函数中的p->Hello();也变成了Hello(p); 因此就算p为空指针,在这里传递给全局函数后并没有用到p做任何输出,所以直接输出了Hello。但如果我们在这个函数的输出时用到了成员变量i,那么成员函数在变换到全局函数的时候再来执行就用到了这个this所指向的对象,而此时this指向的p为空,所以报错。 静态成员函数不能使用this指针,因为静态成员函数并不具体作用于某个对象,因此静态成员函数的真是的参数的个数,就是程序中写出的参数个数! 第二节 静态成员变量 1.静态成员基本概念 在定义前面加了static关键字的成员,称为静态成员。静态成员包括静态成员变量和静态成员函数两种。 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。 sizeof运算符在计算类的大小的时候不会计算静态成员变量。 普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。 因此静态成员不需要通过对象就能访问。 静态成员变量本质上是全局变量!!! 静态成员函数本质上是全局函数!!! 设置静态成员的机制是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一根整体,容易维护和理解。 2.如何访问静态成员 (1)类名::成员名 例如CRectangle::PrintTotal(); (2)对象名.成员名 例如CRectangle r; r.PrintTotal(); (3)指针->成员名 CRectangle *p=&r;p->PrintTotal(); (4)引用.成员名 CRectangle &ref =r; int n = ref.nTotalNumber; 必须在定义类的文件中对静态成员变量进行一次说明或初始化,否则编译能通过,链接不能通过。 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。 如下所示的写法,存在缺陷。 CRectangle::CRectangle(int w_,h_) { w = w_; h = h_; nTotalNumber++; nTotalArea += w* h; } CRectangle::~CRectangle(){ nTotalNumber–; nTotalArea -= w*h; } void CRectangle::PrintTotal(){ cout<<nTotalNumber<<“,”<<nTotalArea<<endl; } 在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象,比如:①我们调用了一个以CRectangle类对象作为参数的函数;②调用一个以CRectangle类对象作为返回值的函数。这个时候就如前面介绍复制构造函数时所说,会产生一个隐藏的临时对象(此函数没写复制构造函数,因此就算直接复制值过去,并没有执行Crectangle(int w_,int h_)),而这个临时对象在消亡的时候会调用析构函数,减少了nTotalNumber和nTotalArea的值,而它们这些对象在生成时却没有增加这两个值,由于这两个值是静态成员变量,所以实际上这两个值是减少了。 解决方案很显然就算写一个复制构造函数: CRectangle::CRectangle(CRectangle &r) { w = r.w;h=r.h; nTotalNumber ++; nTotalArea += w*h; } 第三节 成员对象和封闭类 1.基本概念 有成员对象的类交封闭(enclosing)类。 有一个类的成员是其它类的对象,被称为成员对象。 如下例程: class CTyre { private: int radius; int width; public: CTyre(int r int w):radius(r),width(w){}//初始化列表,可以为每一个成员变量提供一个初始值。 }; class CEngine{}; class CCar{//封闭类 private: int price; Ctyre tyre;//成员对象 CEngine engine;//成员对象 public: CCar(int p, int tr,int tw); }; CCar::CCar(int p,int tr,int w):price(p),tyre(tr,w)//engine使用无参构造函数构造 {}; int main() { CCar car(20000,17,225); return 0; } 在这个例子,如果CCar类不定义构造函数,则CCar car;这个语句会报错,因为编译器不明白car.tyre该如何初始化。 任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象是如何初始化的。 具体做法是:通过封闭类的构造函数的初始化列表进行。 成员对象初始化列表中的参数可以是任意复杂的表达式,可以包括函数、变量,只要表达式中的函数或变量有定义就行。 2.封闭类构造函数和析构函数的执行顺序 (1)封闭类对象生成时,先执行所有对象成员的构造函数,然后才执行封闭类的构造函数; (2)对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关; (3)当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数。次序和构造函数的调用次序相反。 3.封闭类的复制构造函数 封闭类的对象,如果是用默认复制构造函数初始化的,那么它里面包含的成员对象,也会用复制构造函数初始化。 例如: Class A { public: A(){cout<<“default”<<endl;} A(A&a){cout<<“copy”<<endl;} }; class B{A a;}; int main() { B b1,b2(b1); return 0; } 输出: default copy 说明b2.a是用类A的复制构造函数初始化的,而且调用复制构造函数的实参就是b1.a。 第四节 友元(friends) 友元分为友元函数和友元类两种。 1.友元函数 一个类的友元函数可以访问该类的私有成员(这说明友元函数不是这个类的成员函数) 可以将一个类的成员函数(包括构造、析构函数)说明为另一个类的友元。 Class B{ public: void function(); }; Class A{ friend void B::function(); }; 这就代表function()可以访问A里面的私有成员了。 2.友元类 如果A是B的友元类,那么A的成员函数可以访问B的私有成员。 Class CCar { private: int price; friend class CDriver;//声明CDriver为友元类 }; class CDriver { public: CCar myCar; void ModifyCar(){ myCar.price += 1000; //因为CDriver是CCar的友元类,故可以访问其私有成员 } }; int main(){return 0;} 友元类之间的关系不能传递,不能继承! 第三节 常量对象、常量成员函数和常引用 1.常量成员函数 如果不希望某个对象值被改变,则定义该对象的时候可以在前面加const关键词。例如: class Sample{ private: int value; public: Sample(){} void SetValue(){} }; const Sample Obj;//常量对象 Obj.SetValue();//错误。常量对象只能使用构造函数、析构函数和右const说明的函数(const方法) 在类的成员函数说明后面加const关键字,则该成员函数为常量成员函数。常量成员函数执行期间不应修改其作用的对象。因此,在常量成员函数中不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)。 如下: class Sample{ public: int value; void func(){}; Sample(){} void GetValue() const; }; void Sample::GetValue() const{ value = 0;//wrong func();//wrong } int main(){ const Sample o; o.value = 100;//err常量对象不可被修改 o.func();//常量对象上面不能执行非常量成员函数 o.GetValue();//OK常量对象可以执行常量成员函数 return 0; } 需要注意,在Dev C++中,要为Sameple类编写无参构造函数才可以,在VS中不需要。 2.常量成员函数的重载 两个成员函数,名字和参数表都一样,但是一个是const,一个不是,算重载。 3.常引用 引用前面加const称为常引用。不能通过常引用修改其引用的变量。 可以用对象的引用作为参数,如: class Sample{ }; void PrintfObj(Sample & o){ } 对象引用作为函数的参数有一定风险性,若函数中不小心修改了形参o,则实参也跟着变。为了避免这个问题,我们可以用对象的常引用作为参数,这样就能确保不会出现无意中更改o值的语句了。 class Sample{ }; void PrintfObj(const Sample & o){ }

优秀的个人博客,低调大师

在弹性应用程序设计上,eBay为什么选择MongoDB?

作为世界前十十个全球零售品牌,拥有1.7亿活跃买家和10亿在线市场,eBay无法承受系统停机带来的损失。这就是为什么公司依靠MongoDB作为其核心企业数据平台标准之一,为运行ebay.com的多个面向客户的应用程序提供支持。 在今年的MongoDB全球大会上,eBay的首席NoSQL DBA曲峰提供了弹性应用程序的实用设计模式 — 他的团队开发的一套支持企业级MongoDB部署的架构蓝图。 曲先生开始讨论多年来可用性概念的变化。过去,网站可以接受每周维护的预定停机时间。随着当前服务的全球化,用户或业务都不会接受如此频繁的停机!此外,大多数公司现在在商业硬件平台上构建其服务,而不是以前的 Sun Solaris / Sparc服务器。虽然商业硬件的成本要低得多,但是它也经常故障。 这两个因素从根本上改变了工程团队如何考虑可用性,并且引导eBay创建其“弹性设计模式”,以建立最大化平均故障时间(Mean Time To Failure,MTTF)并最大限度地减少平均恢复时间(Mean Time To Recovery,MTTR)的数据库最佳实践。 为了构建应用程序,eBay开发人员可以从五个公认的数据库标准中进行选择。 除了MongoDB,团队还可以选择使用Oracle或MySQL关系数据库和两个NoSQL数据库。 曲先生的DBA团队为适当的数据库选择提供指导,根据应用程序的数据访问模式、用户负载、数据类型等进行选择。 eBay目前运行超过3000个非关系型数据库实例,为一系列应用程序提供支持,可在其间管理数PB数据。 在过去,Oracle是“记录系统”,而非关系型数据库则处理“参与系统”中使用的临时数据。 然而,非关系型数据库环境已经成熟。通过一致的时间点备份和恢复,MongoDB现在也在eBay上服务于记录系统的用例。 虽然eBay的所有非关系数据库选择都提供了内置的故障恢复能力,但它们可以使不同的设计影响应用程序的行为。DBA团队在六个维度上评估这些差异:可用性、一致性、持久性、可恢复性、可扩展性和性能。例如,使用点对点、无主设计的NoSQL数据库具有昂贵的数据修复和重新平衡过程,必须在节点发生故障之后启动。此重新平衡过程会影响应用程序吞吐量和延迟,并可能导致连接堆叠,因为客户端等待恢复,这可能导致应用程序停机。为了减轻这些影响,eBay不得不将最初在Oracle上开发的应用级产品分层在这些无数据库之上。这种方法使DBA团队能够将更大的集群分成一系列子集群,从而将重新平衡开销与较小的一组节点隔离开来,同时只影响了一小部分查询。eBay DBA团队构建其弹性设计模式是针对这些不同类型的数据库行为。 曲先生介绍了eBay的“MongoDB弹性设计模式”,如图1所示。 图1:MongoDB恢复架构的eBay设计模式(图片由eBay的MongoDB世界大会演示提供) 在这种设计模式中,一个7节点的MongoDB副本集遍布eBay的三个美国数据中心。此模式可确保在主数据中心发生故障的情况下,数据库集群可以通过在剩余的数据中心之间建立一个仲裁来保持可用性。MongoDB的副本集成员可以被分配选举优先级,以控制哪些Slave成员被认为是在Primary成员失败时的晋升候选人。例如,如果副本集Primary成员失败,则DC1本地的节点将被优先选择。只有整个DC1遭受中断,DC2中的复制集成员才会被认为可以进行选举,根据哪个节点已经执行最近的写操作选择新的Primary成员。 可以通过使用MongoDB的 majority write concern来扩展这种设计模式,以使得能够跨数据中心持久的写入。 标准MongoDB设计模式被用作eBay的“阅读强化/高可用读取模式”的基础,该演示文稿用于为eBay产品目录提供支持。对于目录负载,MongoDB副本集可以扩展到50个成员,为大并发量的数据分发提供了读取的可扩展性和恢复能力。 对于更多的写入密集型负载,eBay开发出了“极高读/写模式”,该模式在其美国数据中心部署了一个分布式的MongoDB集群。 图2:MongoDB极高读/写模式的eBay设计模式(图片由eBay的MongoDB世界演示提供) 其次,eBay开发人员可以使用特定的MongoDB写入和读取配置来设计模式,以调整最佳满足不同应用需求的持久性和一致性级别。 曲先生指出,随着近期的产品功能增多,MongoDB正在越来越满足更广泛的应用需求: 对MongoDB 3.4添加区域分片使得eBay能够为需要跨多个数据中心提供分布式、永久写入可用性的应用程序提供服务。 针对即将发布的MongoDB 3.6版本的可重写的写入将允许eBay减少应用程序异常处理代码。 原文发布时间为:2017-10-27 本文作者:上海小胖 本文来自云栖社区合作伙伴“51CTO”,了解相关信息可以关注。

优秀的个人博客,低调大师

《OpenACC并行程序设计:性能优化实践指南》一 2.6 小结

2.6 小结 OpenACC是一种描述型并行编程模型。在本章中,通过一个测试函数的应用,使用了OpenACC的多种特性来描述并行度和数据操控,并针对特定平台对代码进行了优化。尽管使用的是PGI编译器和PGProf性能调试器,但类似的优化流程也是适用于任何支持OpenACC工具包的应用的。1.获得应用程序的性能分析结果,辨识和挖掘代码中的可并行之处。2.逐步向编译器描述代码中可挖掘出的并行性。如果主机端和设备端使用各自的存储器,这一步骤后获得的代码很可能会减速。3.描述应用程序的数据移动。编译器通常关注于数据移动等细节并确保正确性,但开发者具有更广的视野并真正了解哪些数据是在多个包含OpenACC区域的子函数中共享的。数据和数据移动的描述完毕后,在分离式存储架构的加速器上会获得极大的性能提升。4.最后,利用读者对应用程序和目标加速器架

优秀的个人博客,低调大师

《Android程序设计》一3.6 Android应用的运行时环境

3.6 Android应用的运行时环境 Android独特的应用组件架构在某种程度上是Android多处理并发的产物。为了使该环境能够适应多个供应商的多种应用,信任每个供应商只需要很少的工作,Android执行Dalvik VM的多个实例,每个任务执行一个实例。在3.7节及后续的章节中,我们将探讨组件生命周期如何促进Android提高应用堆内的垃圾收集工作,以及如何促进多个堆之间的内存回收策略。由于这种简单而又可靠的多处理方式,Android必须高效地把内存划分成多个堆。每个堆相对较小,这样内存可以支持多个应用同时运行。在每个堆中,由于有了组件生命周期而使得不使用的组件,尤其是当前不活跃的用户界面组件,在堆的空间紧张时能够执行垃圾回收,而在需要时能够重新获取。因此,由这种方式又引入了以数据库为中心的数据模型,其中大部分数据都是内在持

优秀的个人博客,低调大师

《Android程序设计》一3.4 静态应用资源和上下文

3.4 静态应用资源和上下文 应用可能需要存储大量的数据来控制其运行时的行为。其中有些数据描述了应用环境:应用名称、注册的intent和需要的许可条件等。这些数据存储在名为manifest的文件中。其他的数据也可能是要显示的图片或简单的文本字符串,以指出要使用什么样的背景颜色或字体。这些数据称为resources。所有这些信息一起构成了应用的context(上下文),在Android中对这些信息进行访问需要借助于类Context。类Activity和类Service都是对类Context的扩展,这意味着所有的activity和service都可以通过该指针访问Context类型的数据。在后续的章节中,还将描述如何使用Context对象在运行时访问应用的资源。 3.4.1 应用的清单文件 Android要求应用在XML文件AndroidM

优秀的个人博客,低调大师

《Android程序设计》一1.1 Android SDK的安装和系统需求

1.1 Android SDK的安装和系统需求 要安装Android SDK,需要两个系统软件,它们不是Android SDK的一部分:即Java开发工具包(JDK)和Eclipse集成开发环境(IDE)。这两个系统没有作为Android SDK的一部分进行提供是考虑到你可能已在非Android软件的开发中使用它们,或者你的系统中可能已经安装了这两个系统软件,而在一个系统上安装这两个软件的不同版本可能会导致版本冲突。Android SDK和最近发布的几个版本的JDK和Eclipse IDE都是兼容的。但最好安装这些工具的最新版本。其具体的要求在Android开发者网站的系统需求页面有介绍。在Android软件开发中,除了Eclipse之外,还可以使用几款其他IDE。在Android文档中给出了可以使用的其他IDE的信息。之所以在本书

优秀的个人博客,低调大师

《Android程序设计》一第2章-2.0 Android开发之Java

第2章-2.0Android开发之Java必备基础本书并不是要教授Java编程,因此本章的内容只是帮助你理解在Android开发中Java的特殊使用方式。以下人士应当仔细阅读本章的内容:已经学习了Java但还没有切身经历过实际的编程困境的学生;在其他移动平台上一直使用其他版本的Java进行移动开发的程序员,需要重新学习在Android平台上进行开发时所要用到的开发语言的某些特性;对Android平台上的特定规范和需求还不了解的普通Java程序员。

优秀的个人博客,低调大师

《Android程序设计》一2.1 Android正在重塑客户端Java

2.1 Android正在重塑客户端Java Android目前已经是最广泛的使用Java语言创建交互式客户端的方式。虽然Java也提供了一些其他的用户接口类库,例如,AWT、SWT、Swing和J2ME Canvas等,但它们的影响都没有达到Android这样的程度。任何Java编程人员,都有必要学习Android UI,借此可以了解今后的Java UI大概会是什么样子。Android工具包并非刻意去改变Java的使用方式,只是因为移动环境不同。在移动环境中,显示器的大小和形状更多样化;没有鼠标(虽然可能有触摸屏);文本输入可能是triple-tap,等等。在移动环境下,还可能有很多外围设备,例如,移动传感器、GPS、摄像机等;还有一直备受关注的续航能力问题。虽然摩尔定律对处理器和内存有深刻影响(大约每两年其性能会翻一番),但该定

优秀的个人博客,低调大师

《Kotlin 程序设计》第十四章 使用Kotlin开发Android程序

第十四章 使用Kotlin开发Android程序 正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial 京东JD:https://item.jd.com/12181725.html 天猫Tmall:https://detail.tmall.com/item.htm?id=558540170670 Kotlin for android https://github.com/EasyKotlin/Kotlin-for-Android-Developers 展示一个实现登录注册的demo 下面就我们就开始一个入门级别的demo吧,现在谷歌已经推出了android studio3.0已经支持了Kotlin这门语言,下载地址:https://developer.android.google.cn/studio/preview/index.html ,只需要在这里新建一个工程,然后在是否要加入kotlin的选项上面勾一下就可以了。 下面看一下登录注册的代码: class MainActivity : AppCompatActivity() { var userName: EditText? = null var userPwd: EditText? = null var register: Button? = null var login: Button? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) userName = findViewById(R.id.user_name) as EditText userPwd = findViewById(R.id.user_pwd) as EditText register = findViewById(R.id.register) as Button login = findViewById(R.id.login) as Button login!!.setOnClickListener { if (userName!!.text.toString() == "123456" && userPwd!!.text.toString() == "abc") { Toast.makeText(this, "login succeed1", Toast.LENGTH_SHORT).show() val intent = Intent(this,HomeActivity::class.java) startActivity(intent) } } register!!.setOnClickListener { Toast.makeText(this, "the function has not open ...", Toast.LENGTH_SHORT).show() } } } 当然实现的代码就非常简单啦,只是可能我们在刚开始接触这门语言的时候有一些的不理解。大家可以看一下上面的代码,要是有什么不理解的地方欢迎issue。 源码地址:https://github.com/linsir6/Kotlin https://github.com/EasyKotlin/Bandhook-Kotlin Kotlin生态库 项目模式 Kotlin MVP Dagger2 Rxjava DataBinding Retrofit Okhttp3 DeepLinkDispatch Gson Glide ByeBurger Kotlin 让你的代码量大大减少,函数式编程让你爽到飞上天!如果你想学习Kotlin,本项目应该会给你不少帮助。 MVP 通过契约类Contract管理View Model Presenter接口。 Model -- 主要处理业务,用于数据的获取(如网络、本地缓存)。 View -- 用于把数据展示,并且提供交互。 Presenter -- View和Model交互的桥梁,二者通过Presenter建立联系。 主要流程如下: 用户与View交互,View得知用户需要加载数据,告知Presenter,Presenter则告知Model,Model拿到数据反交于Prsenter,Presenter将数据交给View进行展示。 Dagger2 项目中,主要进行presenter、model、retrofit Api等类的注入操作。 ApiComponent 主Component、用于注入AppComponent、便于提供子Component依赖。 依赖于: 1.ApiModule(提供okhttpClient、Retrofit、Api等) 2.AppModule(提供context对象(okhttp拦截器所需)) FuckGoodsComponent 父Component为ApiComponent 用于注入FuckGoodsPresenter 依赖于: FuckGoodsModule(提供FuckGoodsView) RandomComponent 父Component为ApiComponent 用于注入RandomPresenter 依赖于 : RandomModule(提供RandomView) Rxjava + Retrofit + okhttp3 主要用于网络访问。 DeepLinkDispatch 基于路由进行页面转发。 GankClientUri 定义一些路由规则、URI等 GankRouter 统一由此进行路由操作 GSON 用于json的解析操作。 Glide 用于图片的加载。 ByeBurGer 用于导航栏以及悬浮按钮滑动隐藏。 参考资料 1.http://git.bookislife.com/post/2016/dev-android-using-scala/ 2.https://github.com/saturday06/gradle-android-scala-plugin 3.https://github.com/pocorall/scaloid Kotlin 示例教程 kotlin中文官网 kotlin官网 kotlin官网翻译 kotlin书籍 kotlin demo

优秀的个人博客,低调大师

K&R《C语言程序设计》代码慢录一

昨天,在一品漫城打第三届4VS4室内篮球赛。 我带的队,打三场,输三场,成功淘汰出局~~~:) 哎,到最后,好像打球氛围不太好,我们老了,只为练练身体,友谊第一。 但,好像有些队,只认输赢一样, 一个哥们居然去威胁裁判。。。 晚上回来吃得少,半夜饿啦,小孩子又跟我们睡觉, 我就起来找食吃,顺便看会K&R的书,尽管在DOUBAN上我给了它差评, 但一路PYTHON看下来,我觉得和这书对照,应该理解得更深入些。 今早突发想学布置JAVA和HADOOP的事。到时再写BLOG。 先上刚才写的书上的样例代码和运行效果吧。 代码: 1 #include <stdio.h> 2 main() 3 { 4 /* list transfer program. 5 print list*/ 6 float fahr, celsius; 7 int lower, upper, step; 8 9 lower = 0; 10 upper = 300; 11 step = 20; 12 13 fahr = lower; 14 while (fahr <= upper) { 15 celsius = (5.0/9.0) * (fahr-32); 16 printf("%3.0f %6.1f\n", fahr, celsius); 17 fahr = fahr + step; 18 } 19 } 运行截图:

优秀的个人博客,低调大师

《Android程序设计》一3.1 Android平台和传统编程模型的对比

3.1 Android平台和传统编程模型的对比 传统编程中,操作系统启动应用时使用单一入口点,通常是main函数,在这个函数中可能会首先解析用户在命令行中提供的输入参数,然后获取输入数据,在处理之后生成输出数据。操作系统负责把程序的代码加载到进程中,然后开始执行它。从概念上讲,这个过程看起来如图3-1所示。 使用Java编写程序,这个过程会变得稍微复杂一些:Java虚拟机(VM)负责将二进制代码加载到内存中来实例化Java类。这个过程如图3-2所示。如果使用的是富图形化用户界面系统,如Swing,则可能会启动一个UI系统,在UI系统中通常需要编写回调函数来响应各种操作事件。 相比而言,Android则更进一步,它支持多个应用入口点,引入了更丰富的机制。在Android系统中假定的前提是,系统会在不同的地方启动它们,这取决于用户当前正在哪

优秀的个人博客,低调大师

《JavaScript 高级程序设计》第四章:变量、作用域和内存问题

目录 变量的引用 执行环境及作用域 作用域链延长 块级作用域 垃圾回收机制 变量的引用 当一个变量保存了基本数据类型时,此时对于变量的操作(赋值,运算)就是操作这个基本数据的本身,就算是赋值操作,赋值时拷贝后的值与之前的值也是相互独立互不影响的。 var a = 1; var b = a b++; console.log(a); //1 console.log(b); //2复制代码复制代码 这非常好理解,但是如果一个变量保存的是一个引用类型的数据,例如对象,那么情况将会不同,这是因为变量保存的并不是对象本身,而是其在内存中的地址(指针),所以当对引用类型进行赋值时,虽然也会进行拷贝,但是这个拷贝后的值只是一个指针,它们两个最终指向的都是对同一个对象的引用,因此便会存在相互影响的问题。 var obj = new Object(); var copyObj = obj; obj.name = 'test'; console.log(obj2.name); //test复制代码复制代码 用图表示就是如下关系: 通过具体的事例再来感受这两者的不同: function PersonnelInfo(age, info) { age = 10; info.name = "cheng"; } var info = {}; var age = 0; PersonnelInfo(age, info); console.log(age); console.log(info);复制代码复制代码 由此我们可以得出变量的访问有两种,一种是“按值访问”,另一种则是“按引用访问”,按值访问操作变量操作的就是值的本身,在进行赋值的时候也是相互独立互不影响的,而按引用访问,再进行赋值的时候,实际上多个变量访问的对象依然是同一个。 一般来说我们会将固定大小的值(例如基本数据类型)保存到栈内存中,将不能固定大小的值(例如对象,数组等)保存到堆内存中,这样的区分也是更好的利用内存空间,提高执行效率。 执行环境及作用域 变量的访问有两种,“按值访问”以及“按引用访问”,而执行环境(Execution Context) 则形成了作用域,作用域又确定了变量或函数是否有权访问其它环境中的数据。也就是说执行环境确定了某些标识符是否能被访问。 每个执行环境都会有个与之对应的变量对象(Variable Object),变量对象用于管理和保存当前环境中的变量以及函数(标识符)。当从一个执行环境进入到另一个执行环境时,首先便会创建变量对象,然后该执行环境会被加入到当前的执行栈中进行执行,如果执行完毕则会从执行栈中弹出,并且该环境中的代码、函数以及变量也都会被销毁。 在JavaScript中执行环境主要的有两种:全局执行环境,函数执行环境。全局执行环境绑定在 WEB浏览器顶层宿主对象 window上,也就是说我们在全局执行环境中声明的变量或者函数都会将作为 window对象的属性或者是方法,也因此只有在退出浏览器或关闭WEB页面才会销毁全局执行环境。 函数的执行环境也是一种局部执行环境,变量对象会比较特殊,我们更多的将其称之为“活动对象(Active Object)”,它默认保存的一个标识符就是arguments,而arguments中保存的便是该函数的参数。 当执行环境被加入到执行栈中进行执行的时候,JS引擎会根据变量对象来解析标识符,首先它会查找当前执行环境中的标识符是否在变量对象中有定义,如果有则取得标识符的值进行下一步操作,如果没有,则向上进入到上一级执行环境,访问其变量对象,依次类推,像这样对不同的环境不同的变量对象进行访问的路径,我们可以称之为作用域链(scope chain)。 因此,所谓的标识符解析实际上就是沿着作用域链进行标识符的查找。 作用域链的访问只能由前向后,由下向上,而不能反方向访问,具体可见事例代码: var x = 1; function method(){ var y = 2; console.log(x); } method(); console.log(y); //Uncaught ReferenceError: y is not defined复制代码复制代码 也可见下图: 作用域链延长 在 JavaScript中有的语句可以在当前的作用域链前端增加一个变量对象,从而延长作用域链。 对于with语句它会将指定的对象作为变量对象添加至作用域链的前端。 function buildUrl(){ var search = '?debug=true'; with(location){ var url = href + search; #注意with并没有作用域。 } return url; }复制代码复制代码 而对于catch语句而言则会创建一个新的对象,然后添加至当前作用域链的前端,在这个变量对象中保存的主要是错误对象Error的相关信息,例如 name,message等。 块级作用域 JavaScript (ES5) 中并不存在块级作用域,ES5支持的作用域跟执行环境相同,主要有函数(局部)作用域、全局作用域。 声明变量时,如果使用var关键字,则所声明的变量添加至当前执行环境中的变量对象上,如果没有使用var关键字,则默认添加至全局执行环境的的变量对象上。 不论是全局作用域还是局部作用域,声明变量时正确的操作都是使用var关键字去声明。 垃圾回收机制 概述 JavaScript支持自动的垃圾回收机制,而不像C,C++那样需要手动的跟踪内存的使用情况,而所谓的自动垃圾回收机制,其本质原理非常简单,那就是每隔一段时间,周期性的检查程序的执行情况,将不在使用的标识符其所占据的内存释放,或者自动分配程序执行期间所需要的内存空间,这样开发人员只需关注业务功能代码,无需过多关心内存的使用情况。 当我们明白垃圾回收机制的大致原理时,那么如何确定一个标识符,其生命周期是否已经结束,就时垃圾自动回收的功能核心。 标记清除 主流浏览器厂商,基本都时采用 “标记清除(mark and sweep)”的方式来标识那些变量可以被回收,那些变量还具有引用关系不能被回收。 其大致思路时当一个变量进入执行环境时,会为它添加一个标志位,用于说明该变量进入了该环境,原则上永远不能释放进入环境中的变量,因为执行流程进入到相应的环境就有可能会用得到。而当变量离开环境时,则再将其标志置为离开状态。 这种标志位的记录方式有很多种,你可以通过翻转某一个位来记录一个变量何时进入环境,何时离开环境,也可以使用 map表的方式来分别记录进入与离开时的状态信息。 当JS的垃圾回收机制运行的时候,它会给存储在内存中的所有变量都加上标记(可以使用任何方式)然后它会去掉全局环境中的以及执行环境中具有引用关系的变量标记,而在此之后在被添加标记(可以认为是离开标记)都被视为准备删除的变量,原因是这些变量已经不需要再被访问了。 简单的来概括,那就时当变量进入环境时,其标记为1,离开时置为0,然后JS的垃圾回收机制每隔一段时间来扫描,将标记为0的变量进行释放。 用代码来表示如下: var status = 1 //进入环境 status = null //离开环境,或者为Null的时候,马上被垃圾回收机制回收。复制代码复制代码 引用计数 “引用计数 (reference counting)”。引用计数实际上就是对值的一种计数标记,当我们定义一个变量并为它赋值一个引用类型时,这个引用类型的值其引用次数就默认为1,当这个值还被其它的变量所引用,则引用次数加1。相反当引用了这个值的变量引用了别的值,则其引用次数减1。当这个值的引用次数为0时,便说明这个值已经以及没有被其它变量引用了,此时便可以将其所占据的内存释放出来。 引用计数的方式有一个非常严重的问题,那就是“循环引用”,当A的值有对B值的引用,而B值中也有对A值的引用时就会发生循环引用。 function problem(){ var ObjectA = new Object(); var ObjectB = new Object(); ObjectA.A = ObjectB; ObjectB.B = ObjectA; }复制代码复制代码 在这个事例中变量 ObjectA 与 ObjectB的值分别被引用了两次,第一次是声明变量并赋值的时候,第二次则是它们各自的属性进行了交叉引用。所以此时这两个对象的值引用次数就时 2,如果在标记清除的策略中并没用什么问题,但是在引用计数的方式下,ObjectA与ObjectB将在函数执行完毕后还会存在,因为它们的引用次数永远不会为0。假如这个函数被重复执行多次,那么就会导致更多的内存空间得不到回收。 采用“引用计数”方式的浏览器都非常古老了,主要是 Netspace Navigator 3.0 以及之前,所以不需要太担心,但是了解下还是非常有必要的,这是因为在IE9之前,对于JavaScript中原生对象采用的是标记清除方式,但是对于非原生对象,例如BOM,DOM等垃圾回收机制依然还是引用计数策略,所以如果需要兼容IE9以下版本的浏览器,在操作非原生对象时,就有可能会出现循环引用的问题。 事例代码: var element = document.getElementById('element'); var myObject = new Object(); myObject.element = element; element.hostObject = myObject;复制代码复制代码 对于这种情况,我们最好在书写代码的时候就要尽量避免,如果难以避免,则在程序执行完成以后也要记得手动释放。 myObject.element = null; element.hostObject = null;复制代码复制代码 性能问题 我们知道垃圾回收机制是周期性的进行运行的,因此确定垃圾收集的时间间隔是一个非常重要的问题。 在IE7之前,IE的回收机制都是根据内存的分配量进行的,具体一点就是256个变量,4096个对象(或数组)字面量和数组元素(slot)或者64KB的字符串,达到上述的任何一个临界值,垃圾收集器就会运行。这种实现方式的问题在于如果一个脚本具有非常多的变量,那么脚本很可能会在其生命周期中一直保有那么多的变量。这样一来,垃圾收集器就不得不频繁的执行,从而影响了正常的程序执行。 到了IE7后,微软重写了IE浏览器的垃圾回收机制,触发垃圾收集的变量分配、字面量和(或)数组元素的临界值被调整为动态修正,其各项临界值在初始时与IE6及之前的版本相同,如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和(或)数组元素的临界值就会加倍,如果例程回收了85%的内存分配量,则再将各临界值重置为默认值。 在日常编码时还有另一种方式可以很好的提升执行的性能,那就是为不再使用到的变量赋值null来进行手动的释放。一般来说这种方式常用于全局变量,因为局部变量会由垃圾回收机制自行清理。 function doSomething() { var obj = new Object(); return obj.name = 'csutom'; } var global_var = doSomething(); //... global_var = null; //当不用的时候最好记得手动释放 原文发布时间为:2018年07月03日原文作者:掘金本文来源:掘金如需转载请联系原作者

优秀的个人博客,低调大师

《Android程序设计》一1.2 小试牛刀:确认安装是否能够正常工作

1.2 小试牛刀:确认安装是否能够正常工作 如果遵循本章前面给出的步骤, Android SDK安装就完成了。但为了确保安装能够正常工作,创建一个简单的Android应用进行验证。 1.2.1 创建Android项目 创建简单的Android应用的第一步是创建Android项目(Android Project)。Eclipse会把工作项组织成项目,当指定某项目为Android项目后,Eclipse就会自动关联该项目所需要使用的ADT插件和其他Android工具。注意: 创建Android项目所需的参考信息和详细的在线说明可以在这里找到。通过File→New→Android Project菜单命令启动新项目。在New Project对话框中找到Android Project选项(它应该是在Android菜单栏中)。单击Next按钮,

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册