为了账号安全,请及时绑定邮箱和手机立即绑定
4.4 省略参数的小括号

当我们写的 Lambda 表达式只需要一个参数时,参数的小括号就可以省略,改写上面实例的代码:// 省略小括号前代码Consumer<String> consumer3 = (s) -> { System.out.println(s);};consumer3.accept("你好,世界!");// 省略小括号后代码Consumer<String> consumer4 = s -> { System.out.println(s);};consumer3.accept("你好,世界!");观察实例代码,之前的 (s) -> 可以改写成 s ->,这样写也是合法的。

4.5 省略 return 和大括号

当 Lambda 表达式体只有一条语句时,如果有返回,则 return 和大括号都可以省略,实例代码如下:1210运行结果:0-1

4.3 省略数据类型

什么叫省略数据类型呢?我们依旧采用上面的实例,使用 Lambda 表达式可以省略掉括号中的类型,实例代码如下:// 省略类型前代码Consumer<String> consumer2 = (String s) -> { System.out.println(s);};consumer2.accept("你好,世界!");// 省略类型后代码Consumer<String> consumer3 = (s) -> { System.out.println(s);};consumer3.accept("你好,世界!");Tips:之所以能够省略括号中的数据类型,是因为我们在 Comsumer<String> 处已经指定了泛型,编译器可以推断出类型,后面就不用指定具体类型了。称为类型推断。

4.2 圆括号

在讲除法运算之前,一定要先讲一下这个圆括号 () ,圆括号和数学运算中一样,可以来控制运算顺序,这个我们从小就学过,在 Sass 运算中你同样可以使用它来控制运算顺序。另外就是如果你直使用除法运算符, Sass 会把这当成一个分隔符来处理,但如果你是写在圆括号内就可以被当作除法操作处理了,这也是圆括号在 Sass 中的另外一个作用!

10.1 判断括号是否匹配

判断一个数学式子的括号匹配是否合法,如 (1 + 2) * (3 + 4)) ,这个式子就是不合法的。校验括号合法不单单要看左括号和右括号的数量是否相等,还要看括号的顺序, ))(( 这样的括号顺序一定是错误的。利用 JavaScript 数组的特性,可以很容易的实现。// 空数组var stack = [];// 一个式子var equation = '(1 + (2 - 3) * 4) / (1 - 3)';var i, len;for (i = 0, len = equation.length; i < len; i++) { if (equation[i] === '(') { // 如果碰到左括号 // 往数组里放个1 stack.push(1); } else if (equation[i] === ')') { // 如果碰到右括号 if (!stack.length) { // 判断数组长度,如果是0,则肯定是出错的,数组长度0的时候说明没有左括号,没有左括号是不可能出现右括号的 // 随便放一个1 stack.push(1); break; } // 如果数组不是空的 就从数组末尾拿一个走。 stack.pop(); }}// 判断数组长度if (!stack.length) { // 如果数组已经空了,说明括号都一一对应,式子里的括号没问题。 console.log('括号合法');} else { console.log('括号不合法');}使用数组实现的具体思路就是,碰到左括号就往数组里放一个成员,碰到一个右括号就拿掉一个成员。这样如果最后有剩下,说明括号没有一一成对。(1+2*(3+4))*1 如这样一个式子:初始化操作: 定义数组 arr为空从式子第一个字符开始循环 第一次循环: 数组的值为 [] 得到字符"(" 判断是左括号,往数组里放一个1,表示碰到了左括号 第二次循环 数组的值为 [1] 得到字符"+" 既不是左括号,又不是右括号,进行下一轮循环,不做操作 第三次循环 第四次循环 第五次循环 与第二次循环基本一致 第六次循环 数组的值为 [1] 得到字符"(" 是左括号 往数组里再放一个1,表示碰到了左括号 第七次循环 数组值为 [1, 1] 得到字符"3" 不是左括号,也不是右括号,进行下一轮循环 第八次循环 第九次循环 与第七次一致 第十次循环 数组的值为 [1, 1] 得到字符")" 是右括号,从数组末尾拿掉一项 第十一次循环 数组的值为 [1] 得到字符")" 是右括号,从数组末尾拿掉一项 第十二次循环 第十三次循环 数组值为 [] 都不是括号,不做操作循环结束判断数组值,如果是空的,说明括号匹配完了,显然 (1+2*(3+4))*1 是合法的当然这种判断有局限性,假如碰到 ((1+)2)-3 这种非括号造成不合法的式子,就判断不出来了。其实这里用到了栈这种数据结构,这个问题在栈的应用上很经典,是算法入门常见面试题之一。

3.3 返回值是对象

如果函数体返回对象字面量表达式,可以省略大括号,使用圆括号的形式包裹对象。var getimooc = () => ({a: 1, b: 2});getimooc() // {a: 1, b: 2}

3.2 有返回值

当函数体内有返回值时,ES6 的箭头函数可以省略大括号:var sum = (num1, num2) => num1 + num2;当传递的参数只有一个时,圆括号也可以省略:var sum = num => num + 10;下面看个使用 map 求和的例子:// ES5[1,2,3].map(function (x) { return x * x;});// 等同于ES6[1,2,3].map(x => x * x);对比 ES5 可以看出箭头函数的简洁表达,更加准确明了。

1.4 元组的简写

当元组作在赋值操作符 = 的右边时,可以省略括号,示例如下:>>> t = 123, 456>>> t(123, 456)>>> x = 123,>>> x(123, )在第 1 行,创建了元组 (123, 456)在第 4 行,创建了元组 (123,)

2.2 双引号

定义:双引号内存放文字的字符串对象。使用场景:推荐用来定义复杂的字符串(包括转义符或者表达式插值操作)。实例:# 输出一段文字puts "Hello Ruby!"# ---- 输出结果 ----Hello Ruby!当使用双引号创建字符串对象时,首先他会查找以反斜杠\开头的字符,进行转义操作,其中最常见转义符为\n,它叫做换行符,当输出包含换行符的字符串的时候,\n会被强制转换为换行。实例:# 输出带有换行符的字符串puts "Goodnight,\nAlice"# ---- 输出结果 ----Goodnight,Alice其次,双引号字符串做的第二件事是表达式插值,在字符串中,#{表达式}会被表达式的结果替换。实例:# 表达式插值name = 'Alice' #定义一个局部变量name,这里的字符串单引号双引号均可puts "Goodnight, #{name}"# ---- 输出结果 ----Goodnight, Alice表达式也可以是数学运算。实例:x, y, z = 12, 36, 72puts "x 的值为 #{ x }"puts "x + y 的值为 #{ x + y }"puts "x + y + z 的平均值为 #{ (x + y + z)/3 }"# ---- 输出结果 ----x 的值为 12x + y 的值为 48x + y + z 的平均值为 40如果表达式只是全局变量$,类变量@@或实例变量@,则可以省略花括号。变量类型将在之后章节给大家普及。实例:puts "This is line #$."# ---- 输出结果 ----This is line 1经验:除了#{}这种表达式插值的形式,使用+也可以进行字符串拼接操作,但是要求进行拼接的两个变量的类型一定是字符串,否则会抛出异常,Ruby 会将#{}表达式中的结果强制转化为字符串,我们不需要关心变量的类型,只需要关心拼接的操作。所以,最好不使用+来拼接字符串。对比下面两种情况:x = 12puts "x 的值为 #{x}"# ---- 输出结果 ----x 的值为 12x = 12puts "x 的值为 " + x# ---- 输出结果 ----Traceback (most recent call last): 1: from ruby.rb:2:in `<main>'ruby.rb:2:in `+': no implicit conversion of Integer into String (TypeError)而这样就不会抛出异常:x = 12puts "x 的值为 " + x.to_s # 将12从数字转化成字符串# ---- 输出结果 ----x 的值为 12

1. 实现策略模式

接下来我们就以电子地图为例,讲解如何用策略模式实现。不过先别着急,上一节我们学习了工厂模式,看起来电子地图也可以用工厂模式来实现。所以我们先来看看用工厂模式如何实现。下面的例子为了方便展示,接口入参只有出行方式,省略了出发地和目的地。计算结果是预估时长。

2.2 信号

信号(Signal)是 Unix 系统中就已有的 IPC 方式,继承于 Unix 的 Linux 系统和 MacOS 系统也具有相同的通信方式。信号的工作原理是向某个进程发送特定的消息,目标进程在收到消息之后,就知道特定事件已经发生,此时进程可以忽略消息即不做处理,或者是处理消息调用固定的函数。以 MacOS 为例,在 shell 终端输入 kill -l 可以列出支出的全部信号名称:HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP。MacOS 支持的信号列表

2.1 一个参数的时候

让我们来改进一下这个方法,可以传递一个名为name的参数。实例:def sayGoodnight(name) result = "Goodnight, " + name return resultend# 该睡觉了~puts sayGoodnight("John-Boy")# ---- 输出结果 ----Goodnight, John-Boy解释: 我们在上个例子调整了sayGoodnight方法,使他可以传递一个参数name并打印出来,调用sayGoodnight这个方法的同时传递了一个字符串参数"John-Boy"。最后打印出来内容为:Goodnight,John-Boy。注意事项: 在第 6 行 ,puts sayGoodnight("John-Boy")包含两个方法调用,一个是sayGoodnight,另一个是puts 。 为什么一个方法调用在参数用括号括起来,而另一个没有使用括号?这种情况,纯粹是个人习惯问题。如果您过多省略括号,由于优先级的问题会让您很难知道哪个参数与哪个方法调用一起使用,因此,除了最简单的情况外,我们建议在所有情况下都使用括号。以下几行都是等效的。实例:puts sayGoodnight "John-Boy" puts sayGoodnight("John-Boy") # 最推荐的写法puts(sayGoodnight "John-Boy") puts(sayGoodnight("John-Boy"))

3.1 SINGLE_TABLE 策略

SINGLE_TABLE 策略: 数据库中使用一张表结构描述 OOP 中的继承关系。学生数据、老师数据以及其它工作人员的信息都放在一张表中。可想而知,这种映射的实用价值并不是很大,因为没有较好地遵循数据库设计范式。留一个问题给大家思考:数据库设计范式有哪些?既然大家都挤在一张表里,一想想,就觉得闷得慌。天呀,都在一起,怎么区分这张表中的数据谁是谁?添加一个鉴别器字段!所谓鉴别器字段,就是在表中添加了一个字段区分彼此之间的身份,这个字段充当的就是鉴别器(discriminator)的功能。表中的数据可能是这样子:不敢直视,有点像住混合宿舍,大通铺的那种。对于这种策略,建议用于数据关系不是很复杂的应用场景下。贴上关键的注解映射代码:Peson 类:@Entity@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)@DiscriminatorValue("person")public class Person implements Serializable { //标识 private Integer id; //姓名 private String name; //性别 private String sex; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Integer getId() { return id; } //省略其它……}细究一下上面用到的 2 个注解:@Inheritance: 继承映射注解,此注解有一个很重要的 strategy 属性,strategy 属性是一个枚举类型,有 3 个可选值,也就是 3 种继承映射 策略:InheritanceType.SINGLE_TABLE InheritanceType.TABLE_PER_CLASSInheritanceType.JOINED@DiscriminatorColumn:@DiscriminatorColumn(name = "discriminator",discriminatorType=DiscriminatorType.STRING)此注解的作用就是添加一个冗余的识别字段,用来区分表中彼此的身份。@DiscriminatorValue("person")对于 Persono 类的信息区分关键字是 person。你可以指定任意的你觉得有意思的名字。学生类中只需要出现仅属于自己的属性,再标注自己的身份说明标签:@Entity@DiscriminatorValue("student")public class Student extends Person implements Serializable { //最喜欢的课程 private String loveCourse; //其它代码……}老师类:@Entity@DiscriminatorValue("teacher")public class Teacher extends Person{ //工作年限 private Integer serviceYear; //其它代码……}修改主配置文件中的信息:<property name="hbm2ddl.auto">create</property><mapping class="com.mk.po.inheritance.Person" /><mapping class="com.mk.po.inheritance.Student" /><mapping class="com.mk.po.inheritance.Teacher" />测试下面的实例,仅仅只是为了创建新表,不用添加任何具体的操作代码。HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>(); hibernateTemplate.template(new Notify<Student>() { @Override public Student action(Session session) { return null; } });进入 MySql,查看表生成情况:有且仅有一张表。大功告成,这种映射策略不再细究,如果有兴趣,添加、查询数据等操作自己去玩。

3.1 使用箭头函数

在定义匿名函数时最好使用箭头函数的形式,更加简洁。// badconst foo = function(){}(function() { console.log('100') })()// goodconst foo = () => {}(() => { console.log('100') })()// best[1, 2, 3].map(x => x * x);当函数只有一个参数,并且返回值是一个表达式时,可以将参数外的括号和表达式外的大括号都省略。// bad[1, 2, 3].map((x) => { return x * x;});// good[1, 2, 3].map(x => x * x);使用箭头函数的另一个好处是,在箭头函数内部是不绑定 this 的,这样在调用函数时 this 的指向是不会变的。var title = "全局标题";// badvar imooc = { title: "慕课网 ES6 Wiki", getTitle : function(){ console.log(this.title); }};imooc.getTitle(); // 慕课网 ES6 Wikivar bar = imooc.getTitle;bar(); // 全局标题// goodvar imooc = { title: "慕课网 ES6 Wiki", getTitle : () => { console.log(this.title); }};imooc.getTitle(); // 全局标题var bar = imooc.getTitle;bar(); // 全局标题

5. 元组

元组是一个有序的序列,元组中所有的元素放在 () 中间,并用逗号分开,例如:(1, 2, 3),一个包含 3 个整数的元组(‘a’, ‘b’, ‘c’),一个包含 3 个字符串的元组元组中的元素是顺序排列的,可以通过索引访问元组的元素,例如:>>> tuple = (1, 2, 3)>>> tuple[0]1>>> tuple[1]2>>> tuple[2]3在第 1 行,创建了一个元组。在第 2 行,通过 tuple[0],访问元组的第 0 个元素,元组的下标从 0 开始。在第 4 行,通过 tuple[1],访问元组的第 1 个元素。在第 6 行,通过 tuple[2],访问元组的第 2 个元素。元组与列表的区别在于:列表创建后可以修改,元组创建后不可以修改。下面的程序首先创建列表 [1, 2, 3],然后修改的第 0 项元素,程序输出表明修改成功了。>>> list = [1, 2, 3]>>> list[0] = 11>>> list[11, 2, 3]下面的程序首先创建元组 (1, 2, 3),然后修改的第 0 项元素,程序输出表明修改失败了。在第 6 行打印输出 tuple,发现 tuple 没有发送变化。>>> tuple = (1, 2, 3)>>> tuple[0] = 11Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: 'tuple' object does not support item assignment>>> tuple(1, 2, 3)

3. 符号

在 ES6 之前,有三种符号。g 全局匹配,找到所有匹配,而不是在第一个匹配后停止var regexp1 = /a/g;var regexp2 = /a/;var str = 'abcdeabcde';console.log(str.match(regexp1)); // 匹配到两个 aconsole.log(str.match(regexp2)); // 只匹配到一个,并返回相应信息可以看到,regexp1 能匹配到两个 a。i 忽略大小写var regexp1 = /apple/i;var regexp2 = /apple/;var str = 'AN APPLE A DAY KEEPS THE DOCTOR AWAY.';console.log(str.match(regexp1)); // 可以找到一个console.log(str.match(regexp2)); // 找不到 输出:nullregexp2没有忽略大小写,所以是无法匹配到 apple 的。m 多行匹配多行匹配模式下,开头和末尾就不是整个字符串的开头和末尾了,而是一行的开头和末尾。目前 ES6 提供了三种新的描述符,分别为 u(Unicode 模式),y(粘连模式),s(dotAll 模式)。

策略模式

大家一定都使用过电子地图。在地图中输入出发地和目的地,然后再选取你的出行方式,就可以计算出最优线路以及预估的时长。出行方式有驾车、公交、步行、骑行等。出行方式不同,计算的线路和时间当然也不同。其实出行方式换个词就是出行策略。而策略模式就是针对此类问题的设计模式。生活中这种例子太多了,比如购物促销打折的策略、计算税费的策略等等。相应的策略模式也是一种常用的设计模式。本节我们会以电子地图为例,比较工厂模式和策略模式,讲解策略模式的原理。最后结合工厂模式改造策略模式的代码实现,以达到更高的设计目标。

3. 语法

.demo{ text-overflow: clip|ellipsis|string;}属性值说明值说明clip超出内容后裁剪ellipsis文字溢出后使用在最后的结尾使用省略号string使用给定的字符串来代表被修剪的文本

1. 声明和调用Ruby方法

在 Ruby 中,我们使用def来声明定义方法,def后面接加方法名,end作为方法的结尾。另外,我们使用方法名()的形式来调用方法,在大多数情况下,我们还可以省略这个括号。让我们编写一个简单的返回字符串的方法,然后调用这个方法。实例:def sayGoodnight result = "Goodnight" return resultend# 该睡觉了~puts sayGoodnight() # puts sayGoodnight 和此方法等效# ---- 输出结果 ----Goodnight解释: 我们在上述代码定义了一个sayGoodnight的方法,这个方法会返回一个字符串名叫“Goodnight”,sayGoodnight()调用了这个方法,然后我们又调用了puts方法,它会将结果打印出来,最后显示的结果为GoodNight。Ruby 的方法默认将最后一行作为返回值,所以我们甚至可以省略return。实例:def sayGoodnight "Goodnight"endputs sayGoodnight# ---- 输出结果 ----Goodnight解释:sayGoodnight 方法里面的最后一行字符串作为此方法的返回值输出出来。

5. 实例

文字超出后裁剪内容<div class="demo"> 慕课网css3属性教学 text-overflow。</div>.demo{ height: 30px; width: 100px; overflow: hidden; white-space: nowrap; text-overflow:clip ;}效果图文字超出后裁剪内容效果图文字超出元素后使用省略号。<div class="demo"> 慕课网css3属性教学 text-overflow。</div>.demo{ height: 30px; width: 100px; overflow: hidden; white-space: nowrap; text-overflow:ellipsis ;}效果图文字超出元素后使用省略号效果图文字超出后使用 !。<div class="demo"> 慕课网css3属性教学 text-overflow。</div>.demo{ height: 30px; width: 100px; overflow: hidden; white-space: nowrap; text-overflow:"!" ;}效果图文字超出后使用 `!`效果图说明:只在火狐浏览器兼容。

1.1 普通用法

在 Go 语言中,for 循环之后一样可以跟三个语句,单次表达式;条件表达式;末尾循环体,但是它不需要使用()来包裹这三个表达式,写法上更加的简洁。同时它也和其它语言一样,可以任意省略这三个表达式。代码示例:package mainimport "fmt"func main() { for a := 0; a < 10; a++ { fmt.Println(a) }}省略单次表达式代码示例:package mainimport "fmt"func main() { a := 0 for ; a < 10; a++ {//表达式可以省略,但是;不能省略 fmt.Println(a) }}执行结果:

3.3 JOINED 策略

JOINED: 将父类、子类分别存放在不同的表中,并且建立相应的外键,以确定相互之间的关系。将来的数据应该和下面一样:第三种策略的映射代码和第二种策略唯一不同的地方,就在 person 中的策略改成了:@Inheritance(strategy=InheritanceType.JOINED)好吧,跑一下测试实例:HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>(); hibernateTemplate.template(new Notify<Student>() { @Override public Student action(Session session) { return null; } });进入 MySql 查看生成的表结构:这种策略从表内容来讲,会把学生和老师共同的字段信息保存到一张表中,两个子表只分别保存属于自己的信息。JOINED 策略从使用角度上讲增加了查询时间,对学生、老师信息进行保存和查询操作时需要连接 person 表,显然增加了操作时间。并且,表中的数据不完善,有点残缺不全的感觉。相信各自还是有自己的优缺点:SINGLE_TABLE: 除了速度杠杆的,但不分你我,数据挤在一起,只怕数据多了,迟早会出现异常;TABLE_PER_CLASS: 类结构符合 OOP 标准,表结构符合关系型数据库范式。数据之间分界线清晰,操作速度也还可以;JOINED: 和 SINGLE_TABLE 有点类似,原来是全部挤在一起。为了缓解空间,一部分数据挤在一起,另一部分放在自己的表中,速度不会提升,数据表完整性得不到保存。客观上对 3 种策略进行纵横比较,最后选择使用哪一种策略,还是由项目需求决定吧。存在,就有合理性。

2. 策略模式

策略模式是软件运行时,根据实际情况改变软件的算法行为。常见的策略模式就是文件压缩软件,通常一个压缩软件可以支持多种压缩算法如 zip 、gzip、rar 等,通过策略模式可以让压缩软件根据我们具体的操作来实现不同的压缩算法。我们来看一个压缩数据的策略模式的例子://定义压缩策略接口 public interface CompressionStrategy{ public OutputStream compress(OutputStream data) throws IOException; } //gzip压缩策略 public class GzipStrategy implements CompressionStrategy{ @Override public OutputStream compress(OutputStream data) throws IOException { return new GZIPOutputStream(data); } } //zip压缩策略 public class ZipStrategy implements CompressionStrategy{ @Override public OutputStream compress(OutputStream data) throws IOException { return new ZipOutputStream(data); } } ​ //在构造类时提供压缩策略 public class Compressor{ private final CompressionStrategy strategy; public Compressor(CompressionStrategy strategy){ this.strategy = strategy; } public void compress(Path inFiles, File outputFile) throws IOException{ try(OutputStream outputStream = new FileOutputStream(outputFile)){ Files.copy(inFiles,strategy.compress(outputStream)); } } } //使用具体的策略初始化压缩策略 //gzip策略 Compressor gzipCompressor = new Compressor(new GzipStrategy()); //zip策略 Compressor zipCompressor = new Compressor(new ZipStrategy());以上就是一个完整的 zip 和 gzip 的压缩策略。现在我们用 Lambda 表达式来优化初始化压缩策略//使用构造器引用优化初始化压缩策略 //gzip策略 Compressor gzipCompressor = new Compressor(GzipStrategy::new); //zip策略 Compressor zipCompressor = new Compressor(ZipStrategy::new);

2.4 跳过某项值使用逗号隔开

在解构数组时,可以忽略不需要解构的值,可以使用逗号对解构的数组进行忽略操作,这样就不需要声明更多的变量去存值了:var [a, , , b] = [10, 20, 30, 40];console.log(a); // 10console.log(b); // 40上面的例子中,在 a、b 中间用逗号隔开了两个值,这里怎么判断间隔几个值呢,可以看出逗号之间组成了多少间隔,就是间隔了多少个值。如果取值很少的情况下可以使用下标索引的方式来获取值。

1.2 代替 while 的用法

在其它大部分语言中 for 循环中省略单次表达式和末尾循环体其实就和其它语句中的 while 用法一致了。所以在 Go 语言中,直接使用省去单次表达式和末尾循环体的 for 循环语句来代替 while 的用法,为了简便代码书写,Go 语言中 for 循环语句在省去单次表达式和末尾循环体时,可以不写分号。代码示例:package mainimport "fmt"func main() { a := 0 for a < 10 { //和其它语言中的while(a<10)一致 fmt.Println(a) a++ }}执行结果:

5. 创建复合数据类型

Python 中的复合数据类型包括:列表提供了内置函数 list() 创建列表元组提供了内置函数 tuple() 创建元组字典提供了内置函数 dict() 创建字典集合提供了内置函数 set() 创建集合

1.8 title

title 属性用于指定元素的备注信息。这些信息通常是指,鼠标移动到元素上并且停留一段时间时,浏览器的提示框内的文本。935上面的代码实现的功能是:当段落文字超出段落宽度时,显示省略号,并且鼠标移上去可显示全部内容:

5. 次版本号与主版本号

学前疑问:学习者可能会有疑问,为什么标题说的是次版本号与主版本号,次版本号在前,而主版本号在后呢?先次后主,是不是读起来感觉有点别扭呢?疑问解答:特别强调下,对于Class 文件结构,第一部分为 u4 的魔数,魔数后边紧跟的就是 u2 的次版本号,次版本号后边才是 u2 的主版本号,此处需要特别注意,从结构上来说,次版本号在前,主版本号在后。定义:次版本号与主版本号共同标识了我们所使用的的 JDK 版本,如 JDK 1.8.0 版本的次版本号为 u2 大小,用字节码表示为 00 00,主版本号也是 u2 大小,用字节码表示为 00 34。次版本号:JDK 版本的小版本号;主版本号:JDK 版本的大版本号。Tips:如果 Class 文件的开头 8 个字节分别为 CA FE BA BE 00 00 00 34,那么我们可以确定,这是一个 JVM 可识别的 Class 文件,且使用的 JDK 1.8.0的版本进行的编译,因为前4个字节魔数为 CA FE BA BE 符合标准,后4 个字节 00 00 00 34 为 JDK 1.8.0的版本。无符号数结构示意图:前文提到,次版本号与主版本号也是无符号数类型的数据。我们接下来看下魔数的示意图:Tips:至此我们了解了先次后主,了解了次版本号与主版本号分别占用 2 个字节,无符号数表示为 u2。同时我们从整体上了解了,魔数后边为次版本号,次版本号后边为主版本号。主版本号后边紧跟的是什么?不要着急,我们继续学习。版本号对照表:开篇的前言部分已经说过,对照表部分为了解内容,这里简单举出几个版本的对照表,了解一下即可。JDK 版本16进制字节码1.8.000 00 00 341.7.000 00 00 331.6.000 00 00 321.5.000 00 00 31

3.4 局部变量

它们的名称始终以小写字母(a-z)或下划线(_)开头。实例:loopcounter = 10_LoopCounter = 20注意事项:在Ruby中我们调用方法(详情请查看:Ruby的方法)可以省略括号(),这就会导致变量名和方法名可能重名的问题。实例:some_thing = 'I am a variable' # 现在我是一个变量# 定义了一个some_thing的方法def some_thing puts 'I am a method'endputs some_thing# ---- 输出结果 ----I am a variable解释:当变量名和方法名称一致的时候,优先使用变量名。如果我们也要调用方法的话,要在变量名后面增加一个括号()。实例:puts some_thing()# ---- 输出结果 ----I am a method当局部变量没有定义时被调用会抛出异常。puts undefined_variable# ---- 输出结果 ----ruby.rb:1:in `<main>': undefined local variable or method `undefined_variable' for main:Object (NameError)局部变量在声明它们的代码结构中是局部的,例如,在方法或循环内声明的局部变量无法在该循环或方法外访问。(在作用域章节中会详细介绍)loopcounter = 10def a_method puts loopcounterenda_method# ---- 输出结果 ----ruby.rb:3:in `a_method': undefined local variable or method `loopcounter' for main:Object (NameError) from ruby.rb:5:in `<main>'解释:因为在a_method方法的作用域中没有找到loopcounter这个局部变量,所以抛出了异常。

1. 结构体类型

想要模拟面向对象就首先要了解一下 Go 语言中的结构体类型。当你需要两个以上的基本数据类型或自定义类型来声明定义函数的时候,你就可以使用结构体。结构体变量使用struct{...}的形式来定义。代码示例:package mainimport ( "fmt" "reflect")func main() { var student1 struct { Name string Age int } student1.Name = "Codey" student1.Age = 18 fmt.Println("student1数据类型:", reflect.TypeOf(student1)) fmt.Println("student1的值:", reflect.ValueOf(student1)) student2 := struct { Name string Age int }{ Name: "Codey", Age: 18, //这个逗号千万不能忘记,若是和大括号同行,这个逗号才可以省略 } fmt.Println("student2数据类型:", reflect.TypeOf(student2)) fmt.Println("student2的值:", reflect.ValueOf(student2))}第 9~12 行:声明一个结构体变量 student1,其属性为 string 类型的 Name 和 int 类型的 Age。第 13 行:给结构体变量的 Name 属性赋值。第 14 行:给结构体变量的 Age 属性赋值。第 19~25 行:定义一个结构体变量 student2,其属性为 string 类型的 Name 和 int 类型的 Age,并赋初值。执行结果:

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号