深入浅出关键字---base和this
- 格式:docx
- 大小:37.91 KB
- 文档页数:4
this的四种⽤法及注意事项1.代表成员变量我们如何区分开:同名的成员变量和在构造⽅法中的局部变量呢?---⽤this。
package com.dh.oop;public class ThisDemo {public String name;public ThisDemo(String name){//将构造⽅法的参数值赋值给成员变量 = name;}}在构造⽅法中,this代表的就是成员变量。
2.代表当前对象的引⽤我们知道,在实例化对象时,会利⽤构造⽅法进⾏初始化成员变量,所以每调⽤⼀次构造⽅法,初始化的都是正在实例化的这个对象的成员变量,即this,所以在构造⽅法中输出this,结果为当前对象的哈希码值。
对象是引⽤数据类型,直接输出,输出的就是其地址。
package com.dh.oop;public class ThisDemo {public String name;public ThisDemo(){//在构造⽅法中输出this,为当前调⽤构造⽅法实例化对象的哈希码值System.out.println(this);}public static void main(String[] args) {ThisDemo tom = new ThisDemo();ThisDemo jerry = new ThisDemo();}}3.在构造⽅法中使⽤this调⽤其它构造⽅法package com.dh.oop;public class ThisDemo {public String name;public int age;//第⼀个构造⽅法public ThisDemo(String name){//调⽤第⼆个构造⽅法this(name,18);}//第⼆个构造⽅法public ThisDemo(String name,int age) { = name;this.age = age;}public static void main(String[] args) {//调⽤第⼀个构造⽅法ThisDemo tom = new ThisDemo("tom");System.out.println(+"\t"+tom.age);}}分析结果,虽然在main⽅法中调⽤的是第⼀个构造⽅法,但由于在第⼀个构造⽅法中调⽤了第⼆个构造⽅法,所以输出了tom 18。
探讨一下构造函数中base和this的用法与区别(C#版)探讨一下构造函数中base和this的用法与区别(C#版)这篇文章主要介绍一下在构造函数中base和this的用法和区别的。
接下来的文章会陆续介绍一下静态变量和静态构造函数。
希望大家能够将意见反馈给我。
代码最具有说服性了,看下面代码吧://代码段一public class ConstructorProgram1{private string name;public ConstructorProgram1(){Console.WriteLine("No Info Left");}public ConstructorProgram1(string name){ = name;Console.WriteLine("name=" + );}}这里我重载了另外一个构造函数,里面的this作为一个指针指示了一个类的引用。
即是ConstructorProgram1类的引用。
这个很简单,但不是重点。
这篇文章最重点要说一下:this和base在构造函数中扮演的角色。
看下面的代码:public class ConstructorProgram{private string name;private int age;public ConstructorProgram():this("bell"){//Console.WriteLine("No Info Left.");}public ConstructorProgram(string name):this("Simple Programmer",20){ = name;Console.WriteLine("name=" + );}public ConstructorProgram(string name, int age){ = name;this.age = age;Console.WriteLine("name=" + );Console.WriteLine("age=" + this.age);}public static void Main(){ConstructorProgram cp1= new ConstructorProgram("goal");ConstructorProgram cp2 = new ConstructorProgram();}}运行结果:name=Simple Programmerage=20name=goalname=Simple Programmerage=20name=bell在上面的代码当中,可以看出来这里红色字体的this用来调用ConstructorProgram类的自身的构造函数。
[深入浅出]深入浅出、深入深出、浅入浅出、浅入深出[深入浅出]深入浅出、深入深出、浅入浅出、浅入深出篇一 : 深入浅出、深入深出、浅入浅出、浅入深出在网上读到这样一段话:世界上有四种老师,第一种是讲课能深入浅出,很深奥的道理,他能讲得浅显易懂,很受学生的欢迎,这是最好的老师;第二种是深入深出,这样的老师很有学问,但缺乏好的教学方法,不能把深奥的学问讲得浅显易懂,学生学起来就费劲,这也算是好老师;第三种是浅入浅出,这样的老师本身学问不深,但却实事求是,把自己懂的东西讲出来,这也能基本保证质量,也算是个好老师;最糟糕的是第四种老师,浅入深出,本身并无多大学问,却装腔作势,把本来很浅近的道理讲得玄而又玄,让人听不懂。
对比一下,我大概属于第三种。
一般我搞不懂的东西,我会避开不讲,只讲自己弄懂的东西;弄懂多少就讲多少。
学生问我问题,我会结合自己的切身经历告诉他自己碰到同样的问题会怎么做,甚至恨不得亲自示范给他/她看。
我知道有一种老师,他们总是能站在更高的地方给学生方法论方面的指导;我也见过另一种老师,他们对学生提出的问题总不正面回答,而是大谈一番似是而非不着边际的话题。
譬如学生问:老师,我想去云南自助游,应该怎么走,我会告诉他,我去过丽江,当年我是怎么走的。
但学生也许想去的是卢沽湖,我会说那里我没去过,但你可以先到丽江再打听怎样去卢沽湖,或者参照我当年的方法去寻找路线;另一种老师会这样回答:你可以到某某网站或某本书上去了解去那里的路线,并告诉他如何找到那个网站或那本书和出行的注意事项;还有一种老师会说:我写过一篇《自助游的兴起、演变、未来趋势和宏观管理战略》的文章,反响很大,你去找来看看吧,看完就知道怎么去了。
呵呵!篇二 : 深入浅出WinDbg——利用快速定位错误Sharepoint代码的某方法LoadLines中使用了SPSecurity.RunWithElevatedPrivileges此方法两次调用了Common.GetLookupValue,并且问题可能出在这里。
VBS数组深⼊浅出vbs教程《数组使⽤》rem 定义dim arr(5)rem 赋值arr(0) = 20arr(1) = 2arr(2) = 5arr(3) = 3arr(4) = 1arr(5) = 100rem 访问msgbox(arr(2))rem 遍历for each v in arrmsgbox(v)nextVBS数组在应⽤中没有像其他语句那么⼴泛,VBS数组存在不少功能上的局限性(如⼆维数组的定义、赋值),在使⽤上也没有java等语⾔那么便捷。
下⾯来具体讲解下⼏个数组函数的使⽤⽅式:Array 函数返回包含数组的 Variant。
Array(arglist)arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(⽤逗号分隔)。
如果没有指定此参数,则将会创建零长度的数组。
说明⽤于引⽤数组元素的表⽰符,由跟随有括号的变量名组成,括号中包含指⽰所需元素的索引号。
在下⾯的⽰例中,第⼀条语句创建名为 A 的变量。
第⼆条语句将⼀个数组赋值给变量 A。
最后⼀条语句将包含在第⼆个数组元素中的值赋值给另⼀个变量。
arr = array("t1","t2")MsgBox arr(0)MsgBox arr(1)注意未作为数组声明的变量仍可以包含数组。
虽然包含数组的 Variant 变量与包含 Variant 元素的数组变量有概念上的不同,但访问数组元素的⽅法是相同的。
IsArray 函数返回 Boolean 值指明某变量是否为数组。
IsArray(varname)varname 参数可以是任意变量。
说明如果变量是数组,IsArray 函数返回 True;否则,函数返回 False。
当变量中包含有数组时,使⽤ IsArray 函数很有效。
下⾯的⽰例利⽤ IsArray 函数验证 MyVariable 是否为⼀数组:Dim MyVariableDim MyArray(3)MyArray(0) = "Sunday"MyArray(1) = "Monday"MyArray(2) = "Tuesday"MyVariable = IsArray(MyArray) ' MyVariable 包含 "True"。
深⼊浅出CDP(ChromeDevToolsProtocol)深⼊浅出 CDP (Chrome DevTools Protocol)14 Jan 2020Table of Contents背景⾃从 Chrome 59 发布⽀持 –headless 启动参数以后 (Windows 上是 60 版本), 轻量级浏览器内核就不再是 webdriver ⼀家独⼤, 甚⾄ phantomjs 作者也发⽂表⽰不再维护该项⽬, 国外也有越来越多的⽂章推荐使⽤ headless Chrome 代替过去 selenium + webdriver 的⽅式进⾏ Web 测试或者爬⾍相关⼯作. ⽬前国内实际上使⽤ headless Chrome 的并不少, 只不过⽬前⼤量营销号的存在, 导致为了点击量频繁刷⽂, 进⽽把早年间 selenium ⽤作爬⾍的旧⽂章重新翻到读者眼前, 所以遇到各种稀奇古怪的问题, 初学者使⽤体验较差. selenium 作为⽼牌 Web 测试⼿段闻名已久, 在⾼级功能 API 层⾯⾮常成熟, 后来也加强了对 Chrome headless 模式下 CDP 的⽀持, ⽬前依然拥有⼤量⽤户在使⽤.这⾥, 简单提⼀下 selenium + webdriver ⽅式的⼀些不⾜:1. 默认参数启动时很容易被服务端发现2. 性能与 Chrome headless 相⽐, 较差3. 存在了⽆数年的内存泄漏问题4. 不像 Chrome 有⼤⼚在背后⽀撑, 上千 issues 解决不完5. ⽆法作为完整浏览器使⽤和调试简⽽⾔之, 都 2020 年了, 不要再抱着 selenium 不放了概述CDP交流⽅式通过 HTTP, WebSocket 两种⽅式, 对添加了远程调试接⼝参数( --remote-debugging-port=9222 )的浏览器进⾏远程调试, ⼤部分功能其实与浏览器⼿机打开的 devtools ⼀致1. HTTP 负责总览当前 Tabs 信息2. 每个 Tab 的对话使⽤ WebSocket 建⽴连接, 并接收已开启功能 (enabled domain) 的事件消息.Headless Browser俗称的⽆头浏览器, 实际上就是没有图形界⾯的浏览器, 因为省去了视觉渲染的⼯作, 性能和开销有较⼤优化, 粗略估计, 原本只能启动⼗个浏览器的内存, 使⽤ Headless 模式可以⾄少启动三倍的数量常见⽤途1. 主要还是 Web 测试2. 少数情况会⽤来做爬⾍, 所见即所得的调试体验⾮常容易上⼿3. 有⼀些 Web ⾃动化的⼯作, 可以替代⾃⼰写扩展或者 tampermonkey JS 脚本, 毕竟权限更⾼更全⾯, GUI 模式调试完以后, ⽆⼈参与操作的多数情况, 则可以⽆痛改成 –Headless 模式来提⾼性能常见问题1. Chrome 浏览器有⼀个并发连接数的限制. 即对同⼀个⽹站, 只允许建⽴最多 6 个连接(纯静态情况下, 可以看作是 6 个同 domain 的 Tabs). 如果真的遇到超过 6 个连接的需求, 可以通过新开⼀个浏览器实例来解决.2. 对于 Linux 来说, ⼦进程处理不正确会导致出现僵⼫进程/孤⼉进程, 导致⽩⽩浪费资源, 时间长了整台服务器的内存都会垮掉. 常见解决⽅案有 3 种1. 将 Chrome 守护进程 (Daemon) 与业务代码隔离, 随需要启动对应数量的 Chrome 实例2. 就 Python subprocess 这个内置模块来说, 确定每次关闭的时候执⾏正确的姿势1. 调⽤ Browser.close 功能 gracefully 地关闭浏览器2. 然后 terminate ⼦进程后, 记得 wait ⼀下消息3. 最后保险起见可以再加个 kill, 虽然实际没什么⽤3. 最简单的其实是找到 chrome 实例的进程 ID 来杀, 毕竟杀死以后, subprocess 那边⽴刻就结束了3. 神奇的是, 除了 chrome 实例有僵⼫进程, 连 tab 也会存在⼀些看不见 ( /json ⾥那些⾮ “page” 类型的就是了)或关不掉(僵⼫标签页)的 tab 页1. ⽬前这种 tab 不确定会不会⾃⼰关闭, 访问 B 站遇到过2. 以前我处理这种 tab 的⽅式是给每个 tab 设定⼀个 lifespan, 异步⼀个循环, 扫描并关闭那些⾮ page 类型或者寿命超时了的 tab3. 然⽽ tab 数量多了以后, 反⽽会出现很多⽆法关闭的僵⼫ tab, 通过 /json/close 或者发送 Page.close 事件都⽆效, 暂时只好重启 chrome 实例来清理4. 拿来做爬⾍还有⼏个问题没解决1. chronium 开发团队本着 “你并不是真的特别需要” 原则, 没有动态挂代理的开发意向, 毕竟⼈家也不太希望⼈们拿它来做爬⾍, 只能指望不同代理 IP 启动多个 chrome 实例来解决2. 在 “⾮ headless” 情况下, 可以通过代理扩展, 或者 pac ⽂件, 来搞定动态代理的问题3. 在 headless 的模式, 那就只好从 upstream ⾓度搞了, 甚⾄挂上 mitmproxy 也⾏吧4. ⾄于动态修改 UA, 暂时可以⽤扩展来搞, 不过如果喜欢钻研, 可以发现 CDP ⾥⽀持动态修改 Request 的各项属性, 在这⾥改 headers 是有效的⽂档常⽤功能Chrome DevTools Protocol ⽂档的使⽤, 主要还是使⽤⾥⾯的检索功能, 不过最常⽤的还是以下⼏个领域1. Page1. 简单地理解, 可以把⼀个 Page 看成⼀个 Page 类型的 Tab2. 对 Tab 的刷新, 跳转, 停⽌, 激活, 截图等功能都可以找到3. 也会有很多有⽤的事件需要 enable Page 以后才能监听到, ⽐如 loadEventFired4. 多个⽹站的任务, 可以在同⼀个浏览器⾥打开多个 Tab 进⾏操作, 通过不同的 Websocket 地址进⾏连接, 相对隔离, 并且托异步模型的福, Chrome 多个标签操作的抗压能⼒还不错5. 然⽽并发操作多个 Tab 的时候, 可能会出现⼀点⼩问题需要注意: 同⼀个浏览器实例, 对⼀个域名只能建⽴ 6 个连接, 这个不太好改; 过快⽣成⼤量 Tab, 可能会导致有的 Tab ⽆法正常关闭(zombie tabs)2. Network1. 和产⽣⽹络流量有关系的⼤都在这个 Domain2. ⽐如 setExtraHTTPHeaders / setUserAgentOverride 对当前标签页的所有请求修改原是参数3. ⽐如对 cookie 的各种操作4. 通过 responseReceived + getResponseBody 来监听流量, 只⽤前者就能嗅探到 mp4 这种特殊类型的 url 了, ⽽后者可以把流量⾥已经 base64 化的数据进⾏其他操作, ⽐如验证码图⽚的处理3. 其他功能也基本和 devtools ⼀致常规姿势1. 和某个 Tab 建⽴连接2. 通过 send 发送你想使⽤的 methods3. 通过 recv 监听你发送 methods 产⽣的事件, 或者其他 enable 的事件, 并执⾏对应回调实践准备⼯作1. 安装 chrome 浏览器2. 安装 Python3.7pip install ichrome -Uichrome 库是可选的, 主要是为了演⽰通过 HTTP / Websocket client 与 chrome 实例实现通信ichrome 库除了协程实现, 也有⼀个同步实现, 观察它的源码⽐协程版本的更直观⼀点, 也易于学习启动调试模式下的 chromefrom ichrome import ChromeDaemondef launch_chrome():with ChromeDaemon(host="127.0.0.1", port=9222, max_deaths=1) as chromed:chromed.run_forever()if __name__ == "__main__":launch_chrome()以上代码负责启动 chrome 调试模式的守护进程, 具体参数如下:1. **chrome_path: **表⽰ chrome 的可执⾏路径 / 命令, 默认为 None 的时候, 会⾃动根据操作系统去尝试找寻 chrome 路径, 如 linux 下的 google-chrome 和 google-chrome-stable, macOS 下的 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome, 或者Windows 下的1. C:/Program Files (x86)/Google/Chrome/Application/chrome.exe2. C:/Program Files/Google/Chrome/Application/chrome.exe3. “%s\AppData\Local\Google\Chrome\Application\chrome.exe” % os.getenv(“USERPROFILE”)2. **host: ** 默认为 127.0.0.1, 之所以不⽤ localhost, 是因为很多 Windows / macOS 的 etc/hosts ⽂件⾥被强制绑定到了 ipv6 地址上3. **port: ** 默认为 92224. **headless: ** 常见参数 –headless, –hide-scrollbars, 放在初始化参数⾥了5. **user_agent: ** 常见参数 –user-agent6. **proxy: ** 常见参数 –proxy-server7. **user_data_dir: ** 避免 chrome 到处乱放 user data, 所以默认会放到 user ⽬录下的 ichrome_user_data ⽂件夹下, 命名按端⼝号chrome_92228. **disable_image: ** 常⽤参数 –blink-settings=imagesEnabled=false, 从 blink 层⾯禁⽤, ⽐其他禁⽌图⽚加载的⽅式要靠谱9. **max_deaths: ** ⽤来⾃动重启, max_deaths=2 表⽰快速杀死 chrome 实例 2 次才能避免再次⾃动重启, 所以默认为 110. **extra_config: ** 就是添加其他更多 chrome 启动的参数, 参数类型为 list启动带图形界⾯的 chrome 之后, 可以⼿动尝试下通过 http 请求和 chrome 实例通信了1. 访问 , 会拿到⼀个列出当前 tabs 信息的 json2. 其他操作参考 (HTTP Endpoints 部分)[{"description": "","devtoolsFrontendUrl": "/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/E6826ED4A0365605F3234B2A441B1D03","id": "E6826ED4A0365605F3234B2A441B1D03","title": "about:blank","type": "page","url": "about:blank","webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/E6826ED4A0365605F3234B2A441B1D03"}]操作 Tab1. 建⽴到 webSocketDebuggerUrl 的 Websocket 连接, 然后监听事件2. ⼤部分功能 ichrome 已经打包好了from ichrome import AsyncChromeimport asyncioasync def async_operate_tab():chrome = AsyncChrome(host='127.0.0.1', port=9222)if not await chrome.connect():raise RuntimeErrortab = (await chrome.tabs)[0]async with tab():# 跳转到 httpbin, 3 秒 loading 超时的话则 stop loadingawait tab.set_url('', timeout=3)# 注⼊ js, 并查看返回结果result = await tab.js("document.title")title = result['result']['result']['value']# 打印 titleprint(title)# # 通过 js 修改 titleawait tab.js("document.title = 'New Title'")# click ⼀个 css 选择器的位置, 跳转到了 Githubawait tab.click('body > a:first-child')# 等待加载完成await tab.wait_loading(3)async def callback_function(request):if request:# 监听到经过过滤的流量, 等待它加载⼀会⽐较保险for _ in range(3):result = await tab.get_response(request)if result.get('error'):await tab.wait_loading(1)continue# 拿到整个 htmlbody = result['result']['body']print(body)def filter_func(r):url = r['params']['response']['url']print('received:', url)return url == 'https:///'# 监听流量, 需要异步处理, 则使⽤ asyncio.ensure_future 即可# 监听 10 秒task = asyncio.ensure_future(tab.wait_response(filter_function=filter_func,callback_function=callback_function,timeout=10),loop=tab.loop)# 点击⼀下左上⾓的⼩章鱼则会触发流量await tab.click('[href="https:///"]')# 等待监听流量await taskif __name__ == "__main__":asyncio.run(async_operate_tab())总结CDP 单单⼊门的话, 其实没想象中那么复杂, chrome 59 刚出的时候, puppeteer 都没的⽤, 更别说 pyppeteer 之类的包装, 看了⼏个早期项⽬的源码, 发现简单使⽤的话, 其实主要就是:1. HTTP2. Websocket3. Javascript4. Protocolpyppeteer 诞⽣之初曾体验了⼀下, 第⼀步就因为⼀些不可抗⼒导致下载 chromium 失败, 所以之后只能阅读⼀下⾥⾯⼀些有意思的源码, 主要看了下如何从 puppeteer 原⽣事件驱动转为 Python ⾓度的事件, pyee 的使⽤也让⼈眼前⼀亮之后⾃⼰摸索过程中也碰到了各种各样问题, 除了上⾯提到的, 其实还遇到 Websocket 粘包(粘包本⾝就是个因为理解不⾜导致的伪命题), Chrome Headless 阉割掉了很多基础功能也使开发过程中总是⽆理由地调试失败, 甚⾄关闭 user-dir 使⽤匿名模式导致⼀系列不知名故障也是费⼼费⼒, 不过总体来说收获颇⼤⽤ Python 来操作 chrome 能做的事情挺多, 尤其是各路签到爬⾍, 或者索取微信公众平台⼤概 20 ⼩时有效期的 cookie / token 给后台爬⾍使⽤, 采集视频, ⾃动化测试时候截图, 启动 Headless 模式以后节省了很多⼿动操作的时间, 甚⾄可以丢到⽆ GUI 的 linux server 上去. 要知道以前指望的还是 tampermonkey 或者⼿写扩展, 很多 Python 的功能只能转 js 再⽤, 劳⼼劳⼒.。
this 关键字的作用this 关键字的作用this 关键字的用法1.this 是指当前对象自己。
当在一个类中要明确指出使用对象自己的的变量或函数时就应该加上this 引用。
如下面这个例子中: 矚慫润厲钐瘗睞枥庑赖賃軔朧。
public class Hello {String s =public Hello(String s){System.out.println(System.out.println(this.s = s;System.out.println(}public static void main(String[] args) {Hello x=}}运行结果:s = HelloWorld!1 -> this.s = Hello2 -> this.s = HelloWorld!在这个例子中, 构造函数Hello 中,参数s 与类Hello 的变量s 同名, 这时如果直接对s 进行操作则是对参数s 进行操作。
若要对类Hello 的成员变量s 进行操作就应该用this 进行引用。
运行结果的第一行就是直接对构造函数中传递过来的参数s 进行打印结果; 第二行是对成员变量s 的打印; 第三行是先对成员变量s 赋传过来的参数s 值后再打印,所以结果是HelloWorld! 聞創沟燴鐺險爱氇谴净祸測樅。
2.把this 作为参数传递当你要把自己作为参数传递给别的对象时,也可以用this 。
如: public class A {public A() {new B(this).print();}public void print() {System.out.println(}}public class B {A a;public B(A a) {this.a = a;}public void print() {a.print();System.out.println(}}运行结果:Hello from A!Hello from B!在这个例子中,对象 A 的构造函数中, 用new B(this) 把对象 A 自己作为参数传递给了对象 B 的构造函数。
PHP常用的关键字PHP常用的关键字PHP可编译成具有与许多数据库相连接的函数。
将自己编写外围的函数去间接存取数据库。
通过这样的途径当更换使用的数据库时,可以轻松地修改编码以适应这样的变化。
下文yjbys店铺为大家分享的是PHP常用关键字,一起来看看吧!final:在PHP中final关键字充当锁的作用,当定义类的时候该类不能被继承,当用来定义方法的时候该方法不能被重载self:用来访问当前类中内容的关键字,类似于$this关键字,但$this需要类实例化后才能使用,$this不能够访问类中的静态成员,self可以直接访问当前类中的`内部成员,包括静态成员。
$this关键字类实例化后可以使用,也可以在类的内容访问非静态化成员static:单独占据内存,只初始化一次,访问静态成员要用::,类中的静态成员和方法可以直接访问,不需要实例化const:用来定义类中的常量,类似PHP外部定义的常量的关键字define();CONSET只能修饰类当中的成员属性!常量建议都大写,不使用$关键字是不需要加$的。
在类中访问常量也是用self关键字举例:/** Created on 2012-2-12** To change the template for this generated file go to* Window - Preferences - PHPeclipse - PHP - Code Templates */abstract class cl1{static $ss='我的电脑';//静态成员变量public $aa='你的电脑';abstract function fun1();abstract function fun2();abstract function fun3();function ok(){echo self::$ss;//在类的内部访问static成员也要用的self关键字echo $this->aa;}}class cl2 extends cl1{function fun1(){}function fun2(){}function fun3(){return 1;}}$instance=new cl2();echo $instance->fun3().$instance->ok();echo cl1::$ss;//无需实例化也可以访问到变量ss?>【PHP常用的关键字】。
C++关键词asmautobad_castbad_typeidboolbreakcasecatchcharclassconstconst_castcontinuedefaultdeletedodoubledynamic_cast elseenumexcept explicit externfalsefinallyfloatforfriendgotoifinlineintlongmutable namespaceoperator private protected publicregister reinterpret_cast returnshortsignedsizeofstaticstatic_caststructswitch templatethistruetrytype_infotypedeftypeid typename unionunsignedusingvirtualvoidvolatilewchar_t whileasm已经被__asm替代了,用于汇编语言嵌入在C/C++程序里编程,从而在某些方面优化代码.虽然用asm关键词编译时编译器不会报错,但是asm模块的代码是没有意义的.(2)auto这个这个关键词用于声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。
这个关键词不怎么多写,因为所有的变量默认就是auto的。
(3)bad_cast,const_cast,dynamic_cast,reinterpret_cast,static_cast关于异常处理的,还不是太了解..(4)bad_typeid也是用于异常处理的,当typeid操作符的操作数typeid为Null指针时抛出.(5)bool不用多说了吧,声明布尔类型的变量或函数.(6)break跳出当前循环.The break statement terminates the execution of the nearest enclosing loop or conditional statement in which it appears.(7)caseswitch语句分支.Labels that appear after the case keyword cannot also appear outside a switch statement.(8)catch,throw,try都是异常处理的语句,The try, throw, and catch statements implement exception handling.(9)char声明字符型变量或函数.(10)class声明或定义类或者类的对象.The class keyword declares a class type or defines an object of a class type.(11)const被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
1第一部分2访问关键字:base,this3base访问基类的成员。
用于从派生类中访问基类的成员,1.调用基类上已经被重写的方法。
2.指定创建派生类实例时应调用的基类构造函数。
**对基类的访问只能在派生类的构造函数实例的方法实例的属性访问器中。
属性访问器:get,set函数。
注意:!!!!!!!!!不能在静态方法中使用base关键字。
例:在子类的方法中写base.GetInfo();调用基类的方法。
基类中的构造函数重载了,Mybase()和Mybase(int i);在子类的构造函数中public MyDerived():base(int i)public MyDerived(int i):base()this:引用当前对象。
用于引用为其调用方法的当前实例。
静态成员函数没有this指针。
可以用于从构造函数,实例方法,实例访问器中访问成员。
this的一般用途:1.限定被相似的名子隐藏的成员public void A(int a, int b ){this.a=a;this.b=b;}2.将对象作为参数传递到函数中public void ShowInstance(){print(this);console.writeline("lalalalllalalala");}3.声明索引器public int this[int param]{get{ return array[param]; }set{ array[param]=value; }}注意!!!!!!静态方法,静态属性访问器或字段声明中不能用this。
二.转换关键字:explicit, implicit, operator1explicit:用于声明用户定义的显式类型转换运算符。
例:class MyType{public static explicit operator MyType(int i){//从int显式转换成MyType类型的代码!!!}}显式类型转换符必须通过类型转换调用。
本文将介绍以下内容:
∙面向对象基本概念
∙base关键字深入浅出
∙this关键字深入浅出
1. 引言
new关键字引起了大家的不少关注,尤其感谢Anders Liu的补充,让我感觉博客园赋予的交流平台真的无所不在。
所以,我们就有必要继续这个话题,把我认为最值得关注的关键字开展下去,本文的重点是访问关键字(Access Keywords):base和this。
虽然访问关键字不是很难理解的话题,我们还是有可以深入讨论的地方来理清思路。
还是老办法,我的问题先列出来,您是否做好了准备。
1.是否可以在静态方法中使用base和this,为什么?
2.base常用于哪些方面?this常用于哪些方面?
3.可以base访问基类的一切成员吗?
4.如果有三层或者更多继承,那么最下级派生类的base指向那一层呢?例
如.NET体系中,如果以base访问,则应该是直接父类实例呢,还是最高
层类实例呢?
5.以base和this应用于构造函数时,继承类对象实例化的执行顺序如何?
2. 基本概念
base和this在C#中被归于访问关键字,顾名思义,就是用于实现继承机制的访问操作,来满足对对象成员的访问,从而为多态机制提供更加灵活的处理方式。
2.1 base关键字
其用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中,MSDN中小结的具体功能包括:∙调用基类上已被其他方法重写的方法。
∙指定创建派生类实例时应调用的基类构造函数。
2.2 this关键字
其用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏this,MSDN
中的小结功能主要包括:
∙限定被相似的名称隐藏的成员
∙将对象作为参数传递到其他方法
∙声明索引器
3. 深入浅出
3.1 示例为上
下面以一个小示例来综合的说明,base和this在访问操作中的应用,从而对其有个概要了解,更详细的规则和深入我们接着阐述。
本示例没有完全的设计概念,主要用来阐述base和this关键字的使用要点和难点阐述,具体的如下:
base和this示例
3.2 示例说明
上面的示例基本包括了base和this使用的所有基本功能演示,具体的说明可以从注释中得到解释,下面的说明是对注释的进一步阐述和补充,来说明在应用方面的几个要点:
1.base常用于,在派生类对象初始化时和基类进行通信。
2.base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。
3.this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成
员,而且不管访问元素是任何访问级别。
因为,this仅仅局限于对象内
部,对象外部是无法看到的,这就是this的基本思想。
另外,静态成员
不是对象的一部分,因此不能在静态方法中引用this。
4.在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存
在的情况下,base将指向直接继承的父类成员的方法,例如Audi类中的ShowResult方法中,使用base访问的将是Car.ShowResult()方法,而不能访问Vehicle.ShowResult()方法;而是没有重载存在的情况下,base 可以指向任何上级父类的公有或者受保护方法,例如Audi类中,可以使
用base访问基类Vehicle.Run() 方法。
这些我们可以使用ILDasm.exe,从IL代码中得到答案。
.method public hidebysig virtual instance void
ShowResult() cil managed
{
// 代码大小 27 (0x1b)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
//base调用父类成员
IL_0002: call instance void .My_Must_net.Car::ShowResult()
IL_0007: nop
IL_0008: ldarg.0
//base调用父类成员,因为没有实现Car.Run(),所以指向更高级父类
IL_0009: call instance void .My_Must_net.Vehicle::Run()
IL_000e: nop
IL_000f: ldstr "It's audi's result."
IL_0014: call void [mscorlib]System.Console::WriteLine(string)
IL_0019: nop
IL_001a: ret
} // end of method Audi::ShowResult
3.3 深入剖析
如果有三次或者更多继承,那么最下级派生类的base指向那一层呢?例如.NET 体系中,如果以base访问,则应该是直接父类实例呢,还是最高层类实例呢?
首先我们有必要了解类创建过程中的实例化顺序,才能进一步了解base机制的详细执行过程。
一般来说,实例化过程首先要先实例化其基类,并且依此类推,一直到实例化System.Object为止。
因此,类实例化,总是从调用
System.Object.Object()开始。
因此示例中的类 Audi的实例化过程大概可以小结为以下顺序执行,详细可以参考示例代码分析。
1.执行System.Object.Object();
2.执行Vehicle.Vehicle(string name, int speed);
3.执行Car.Car();
4.执行Car.Car(string name, int speed);
5.执行Audi.Audi();
6.执行Audi.Audi(string name, int speed)。
我们在充分了解其实例化顺序的基础上就可以顺利的把握base和this在作用于构造函数时的执行情况,并进一步了解其基本功能细节。
下面更重要的分析则是,以ILDASM.exe工具为基础来分析IL反编译代码,以便更深层次的了解执行在base和this背后的应用实质,只有这样我们才能说对技术有了基本的剖析。
Main方法的执行情况为:
IL分析base和this执行
因此,对重写父类方法,最终指向了最高级父类的方法成员。
4. 通用规则
尽量少用或者不用base和this。
除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,base和this的使用容易引起不必要的结果。
∙在静态成员中使用base和this都是不允许的。
原因是,base和this访问的都是类的实例,也就是对象,而静态成员只能由类来访问,不能由对象来访问。
∙base是为了实现多态而设计的。
∙使用this或base关键字只能指定一个构造函数,也就是说不可同时将this和base作用在一个构造函数上。
∙简单的来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来公有和保护成员。
∙除了base,访问基类成员的另外一种方式是:显示的类型转换来实现。
只是该方法不能为静态方法。
5. 结论
base和this关键字,不是特别难于理解的内容,本文之所以将其作为系列的主题,除了对其应用规则做以小结之外,更重要的是在关注其执行细节的基础上,对语言背景建立更清晰的把握和分析,这些才是学习和技术应用的根本所在,也是.NET技术框架中本质诉求。
对学习者来说,只有从本质上来把握概念,才能在变化非凡的应用中,一眼找到答案。
言归正传,开篇的几个题目,不知读者是否有了各自的答案,我们不妨畅所欲言,做更深入的讨论,以便揭开其真实的面纱。
参考文献
(USA)Stanley B.Lippman, C# Primer
(USA)David Chappell, Understanding .NET
(Cnblog)Bear-Study-Hard,C#学习笔记(二):构造函数的执行序列
广而告之
[预告]
另外鉴于前几个主题的讨论中,不管是类型、关键字等都涉及到引用类型和值类型的话题,我将于近期发表相关内容的探讨,主要包括3个方面的内容,这是本系列近期动向,给自己做个广告。
祝各位愉快。
[声明]
本文的关键字指的是C#中的关键字概念,并非一般意义上的.NET CRL范畴,之所以将这个主题加入本系列,是基于在.NET体系下开发的我们,何言能逃得过基本语言的只是要点。
所以大可不必追究什么是.NET,什么是C#的话题,希望大家理清概念,有的放肆。