00:00
我们现在已经知道怎么样用scla去写代码了,而且通过hello word这个最简单的事例,我们也已经知道了scla里面的一些语法细节,那么大家会发现skyla整体来讲跟其他一些编程语言语法是很接近的,那么如果要跟Java做一个类比的话,最大的区别就应该是。比Java里边啊,少了一些关键字啊,大家看这个public和static都被删掉了,我们这个定义的过程显得简洁了很多,另外还有就是定义的时候。名称和类型跟Java刚好反过来,Java里边我们是先有类型,后边是方法名称、参数名称或者变量名称,而在skyla里边呢,是先定义名称,后边跟着的才是类型,中间用冒号做一个分割啊,大家一开始接触的时候可能会不太适应啊,这个其实熟悉之后也没有什么难的,这就是一个规则的定义而已。那这一部分代码里面,可能大家会觉得有所困惑的还是前边的这个object。
01:06
这里我们说它是一个单立对象,全局只有一份的对象,但是这个对象呢,大家会发现直接一个关键字就把它声明出来了,这跟Java里面的对象声明不一样啊,大家熟悉的对象定义的方式,其实应该是应该是先有一个类,我们先把一个class定义出来,然后接下来呢,去new这个class的对象实例啊,然后再接下来才是通过这个对象访问它的属性,调用它的方法,这是我们所谓的面对对象编程的一整套思路,一整一整套流程。那现在。Cala里边没有这样一个过程,直接上来就创建了一个对象,它到底是哪个类的对象呢?哎,所以这一部分跟Java是有所不同的啊,而且前面我们也说到了这个单立对象,其实在skyla的概念里面,底层应该把它叫做半生对象,它是跟另外一个类相伴相生的,这个概念可能稍微有一点复杂,所以这里面呢,我们再把这一部分展开一点,给大家做一个扩展,深入了解一下什么是scla里面的伴生对象。
02:15
那么前面其实我们在做反编译分析的时候也已经涉及到了这个概念啊,呃,在idea里边大家会发现其实我们也能找到对应的这个编译之后自节码文件啊,只要前面我们做过编译运行执行啊,那么在target classes目录下边就可以找到对应的这个对象,然后呢,我们右键,然后opening explorer,大家看到这就可以看到,果然生成的还是两个点class自建码文件,一个叫做hellowood,另外一个叫做hello word Dollar啊,那如果说我们还是用这个反编译工具。看一下里边的内容的话,会发现跟之前我们那个分析是一样的,Hello word这个大家知道,反编译其实是把它又翻译回了Java。
03:04
对应的那个语言对吧,所以看到的就应该是每一个点class文件都应该是一个Java类嘛,嗯,所以接下来我们其实看到的是两个Java类,那么一个类是叫做hello word,这个类就是整个代码执行的入口类。那么对应着我们看到跟。码里边GALA代码里边定义的这个object的名称其实是一样的,都叫hello word啊,那所以我们说这个hello word,它本身是一个伴生对象嘛,那么它到底跟谁相伴相生呢?其实就跟它同名的这个a word类,他俩彼此相伴相生。啊,所以只要它们名称相同啊,这个时候我们就把这个对象叫做一个类的生对象,而把这个类呢,叫做我们那个对象的生类啊,所以这个hello word是一个半生类,也是我们程序执行的入口类,那另外还有一个类就是hello word Dollar,这个我们也已经知道了啊,它在里边呢,是构造方法私有化,然后要去定义一个静态的对象啊,定义这个对象呢,是要在静态代码块里边拗一个对象实例全局只此一份,那就相当于实现了一个单立设计模式嘛,所以我们发现了所谓的我们在这里定义的这个单利对象啊,Object,真正这个对象其实是是谁呢?
04:27
就是就是hello沃的Dollar里边的Mo Dollar哎,那么当前的这个model Dollar又是哪个类的一个实例呢?啊,其实大家看其实就是hello Dollar的一个实例,对吧?我们本来就是拗了一个当前啊,直接拗了一个对象啊,然后把这个this直接付给了modu Dollar嘛,所以整体来讲,我们就把这两个类,如果从Java的角度上去理解的话,那就相当于一个是当前的入口执程序执行的入口类,或者叫做当前。
05:00
伴生对象啊,当前我们对应的定义的这个对象的伴生类,那么另外一个hello Dollar,这就是当前伴生对象的所属类啊,这就是我们之前给大家的一个解释,那这里如果要只是这么空洞的解释的话,大家可能还是不太理解,所以我们还是给大家呃讲一个具体的例子吧,因为这里边主要是涉及到了对于Java里边static关键字的一个省略,大家看到在这个Java代码里面,其实根本没必要这样去定义,呃,就是绕一圈,然后实现这样一个单立设计模式,因为我们有static关键字啊,你只要有static关键字,那其实你想要实现的所谓的这个单立对象文局只有一份的这个东西,那我不是直接可以在这个先用static把它定义出修饰出来,不就可以了吗?啊,所以我们先回忆一下啊,画里边怎样实现这样类似的这个功能啊,那我们这里边在Java目录下边。
06:00
新建一个Java class,我们举一个最经典的例子啊,就是学生这个类,Student类。大家知道student里边可以有各种各样的属性,比方说我们每个属性都定义成私有的啊,我们定义一个string类型的name,学生的名字啊,然后我们再定义一个新体制类型,整数类型的age生的年龄啊,这些大家知道每一个学生。都是有关的,我们在创建一个学生实力的时候,肯定要付给他不同的名称和,呃,名字和年龄,这个肯定是因人而异,每一个对象都不相同,而另外有一些属性呢,有可能他们就是完全相同的,那比如说大家会想到在同一个项目里边,我们要处理的数据可能都来自于同一个学校的学生。啊,那这种情况下,我们就根本没有必要单独去定义嘛,但是在有些地方呢,我要又要用到这样的一个,比方说学校啊,School这样一个字段,那这个时候我感觉又应该把它定义在class,呃,Student这个class里边,那当前这个到底该怎么定义呢?Java里边非常简单,我是不是直接把它用static关键字做一个修饰,定义成静态的,那接下来这个school不就相当于变成全局的一个属性了,所有的学生上来之后,他的school都是一样的,那再比方说我们这里边给一个at特硅谷,所有的学生不来自于硅谷。
07:31
那我们就定义好了,接下来我们在创建这个构造方法的时候,我不需要传入school的信息,只要传入name和age,哎,赋给当前的这个属性就可以了,对吧?哎,这就是当前这个定义的过程啊,那当然前面我们这个属性都是private私有的,要想在外部访问的到,那还必须得有public的方法,我们在这里干脆就直接定义一个打印所有信息的一个方法吧,我把它叫做print info,不需要有任何参数啊,然后直接打印啊,S out啊,Print line把它打印出来,那这里我要的是当前的name,然后空一格,再加上当前的H。
08:15
空定格,最后再加上当前的school,但是大家会发现现在如果我要是this.school去调用的话,不是应该就有问题啊,对吧,因为这里面正常来讲,我们对应的这个school属性其实已经不属于。就我们在调用的时候啊,已经不是直接用当前的这个对象去做调用了,我们这里边this其实指代的是当前这个对象实例嘛,我们在调用这个school它静态属性的时候,应该直接用当前的类名去做调用啊,这才是静态属性和方法调用的这个,呃,标准的方式啊,标准形式啊,所以有了这个之后,接下来我们可以直接做一个测试,我们就直接在下面去建一个这个main方法吧,面测试啊,单独创建这个不是的类了啊,我们可以直接用一个student,一个他的名字,比方说第一个我们叫做Alice,年龄是20,我把这个student Alice创建出来,另外我们在拟一个二个学生,我们叫做宝,同样把这个学生创建出来,那接下来当然就是可以直接。
09:34
打印他们的信息。接下来我们可以直接做一个运行。大家可以看到运行的结果,那就是爱丽丝和Bob,他们的名字和年龄各不相同,但是学校当然都是at特硅谷,哎,这是完全没有问题的,这是Java里面的实现,大家看这个我们非常熟悉,也非常的简洁,但是呢。
10:04
它其实有问题的,有什么问题呢?诶本身逻辑上没有任何的问题啊,但是从这个语言的设计上,它有一点点问题,就是我们本来说Java式一门面对对象的语言,所以后边你做任何的这个行为啊,我们说都应该是对象的一个方法调用,所有的这个属性也都应该是一个对象的属性去做访问,那大家会发现这里边,诶,我们这里边的这个打印,当然都是一个对象的方法调用啊,但是这里边的这个school这个属性,它调用的时候是不是就是没有通过对象去做调用去做访问啊,而是直接用了类名去做访问。哎,所以这种方式你就不足够面对对象啊,哎,当前我们这个还只是一个静态的属性,大家可能看的还不是很明显,那如果说我们要是在单独定义这样一个静态的方法的话,那就会看的更加明显了,对吧?如果我们在外面把这个print iner定义成一个static的方法的话,在外面去做调用的时候,你就不应该是Alice去调他的这个方法,而应该直接调student.print iner,那这还能叫面对对象吗?他的行为都已经不是一个对象的行为了。
11:16
诶,所以马丁奥德斯基也是考虑到了这一点,所以接下来在盖拉里边,他干脆就大笔一挥,直接把study关键字删掉了,所以我们看到在skyla代码里边,这里边并没有static关键字,那问题就来了,呃,你这个一删,删的是简单,那如果说是现在我就要实现Java里边这样的一个功能,又该怎么样去实现呢?那就比方说我现在就是啊,有一个student类里边有两个属性,这是我构造方法啊,要传参,要指定的每一个对象可能都不一样,然后呢,有一个school这样一个属性呢,它是全局的,所有的student来了之后,这个school属性都一样。那这个时候我又应该怎么样去调用呢?而且我要求还不能直接用这个类名去做全局的调用,对吧?必须要基于一个对象去调用。
12:07
啊,那为了解决这个问题,那么在scla的语法设计里边就增加了一个关键字叫做object,所以大家会看到啊,所谓的单利对象或者半生对象,它其实就是为了解决删除掉静态static关键字之后,而且我们又要去实现对应的这个静态功能,为了解决这样的需求而设计出来的。啊,那当然了,既然设计它就是一个对象,我们基于它去做调用,所有的东西当然也就都变成面对对象的了,对吧?啊,那接下来我们就来看一看这个student这样一个类在LA代码里边又该怎么样去实现,接下来我们chapter one下边去创建一个scla class,那现在就不是object了啊,因为当前我们还是。Student类嘛,所以我们创建一个scla的类叫做student scale的代码里边,它比这个Java代码就会简洁很多啊,因为Java代码里边我们是先去声明属性,然后呢,呃,再去定义这样的一个构造方法,把这个对应的字段传进去啊,付给属性,那在SC里边呢,不用那么麻烦,他直接把这个所有属性啊,想要去定义的属性放在。
13:25
内名后边跟一个括号互项方法的参数一样,传进去就可以了,那比方说这里边我直接给一个name,对,是一个一个属性叫做name,对吧,类型是string,然后age int Ella里边的整形和int,不是in啊,就是int,所以大家会看到它,这就相当于是直接把属性定义出来,而且连构造方法都定义好了,大家看这不就很像构造方法的这种声明方式吗?啊,这就是scalela的这个语法简洁的地方啊,那所以接下来我们构造方法都不用写了啊,那最终就是实现一个print infer这个方法就可以了,在scale里边还还记得我们的这个语法结构吧,EF一个方法的声明,然后接下来是point in后边是一个括号,没有参数冒号跟上它的返回值,没有返回值冒的嘛,那就是unit了,接下来是它的函数体,函数题里边直接打印起来,打印就可以了,里边要写的内容大家会想到是不是跟我们这里边其实差不多啊,也是把当前的name和age还有school要做一个。
14:36
要做一个实现对吧,要要这样做一个出,哎,当然这里面我可以用this.name也可以不写,因为大家看这我就把这个name作为一个参数进来不就完了吗?就有点像里边所有的这一个方法啊,就相当于是我我外边的这一个函数题里边的一部分内容,对吧?所以都可以访问得到,哎,这里边我把这个this删掉也是可以的。
15:01
但是最后这个school就比较麻烦了,首先你不能把它删掉,直接删掉的话,那这个school我当然不知道是什么嘛,这语法上肯定是找不到的,那如果说要不删的话,目前这个student我能直接点school去定义吗?当然也不能啊,因为当前这个student本身我在这里边就不能基于class去做这样的一个定义,对吧,就不能在这个SC里边,你既然是要完全面对对象吧,所以你基于类名就不能直接点什么去调用它的属性或者方法,那这里面问题就来了,我既然还要去基于一个对象去想要做调用,那这个对象又从哪儿来呢?这就要引入一个诞生对象,所以我们的伴生对象其实就是这么样啊去产生的,那当前这个伴生对象呢,那就是跟当前的student类相伴相生,他们的名字必须完全一样而已,Object作为关键字,后面还是student,那么这样一个伴生对象,它跟前面的这个student类呢,它俩相伴相生,里边的所他们里边的所有的私有成员都是可以互相访问的。
16:18
哎,所以这样的话就可以解决我们那个S之前我们想要的那个study关键字的问题了,也就是说之前你不是说想让他全局只有一份吗?啊,就是相当于是所有的这个对象啊,Student对应的那个对象来了之后都能够访问到吗?我把全局只有一份的这个属性直接放在全局只有一份的这个半生对象里边,这不就完了吗?那当然这个属性也只有一份,对不对?你想要用的时候,是不是直接基于这个伴生对象去做一个访问就可以了呀?哎,所以大家看我把这个student办成对象声明出来之后,Student这里的这个定义已经不爆红了,只不过后面我还没有声明school这个属性,所以说这个我还需要做一个定义,接下来我就啊,School灯明成,String类型灯明成。
17:11
对项student里边的一个属性at硅谷,你看这样就解决了这个问题。啊呃,就是我们所说的这个,呃,伴生对象和伴生类啊,就是当前的这个类student,它有一个伴生对象。这个对象就是它的伴生对象啊,那么那这个类呢,Student类呢,又可以叫做这个对象的伴生类,他们彼此相伴相生,互相之间都可以访问彼此对方的私有对私有成员啊,那我们也可以在这里边做一个测试,大家会发现你这个class是没法没法测试的,因为我们在class里边没有static关键字,那你当然不能像Java里边public static voin,对吧,那就没有没方法去执行了,那怎么办呢?就只能,哎,有同学可能想,那我在这儿直接去声明一个没方法可以吗?
18:01
大家看到你即使声明出来之后,这儿也那没有箭头,对吧,不能去执行,那怎么样才能执行呢?就必须把这个没方法定义在object里面看,只要在这一声明前面是不是就都有这个箭头了,甚至前边class这里也有箭头了,为什么呢?诶,因为我们说它是可以访问诞生对象里边的所有成员和方法的嘛,诶那。Student办成对象的may方法,当然这里边student类也可以访问啊,所以这里边你要执行的时候,其实还是让的是下边这个student,它对应的这一个main方法对吧?哎,所以这是我们当前定义的这样的一个过程,这里边我们做测试的时候,跟之前的过程其实就非常的类似了啊,我还是直接去new一个student,给一个ALICE20,我们把它定义出来,这个叫做爱ice,看到里边我可以直接不给对应的类型,编译器其实会给我们自动的把它判断出来啊,当前类型当然就是student了,只要编译器,编译器能够识别出来,我们就可以省略,可以不写BOB23,哎,同样把这个Bob定义出来。
19:18
然后你是Alice print INF print in。运行一下。看到这样的话,同样得到了一样的结果。ALICE20对应的name和AGE2个属性都是自己独有的,每个对象独有的,而at特硅谷学校这个属性呢,是大家共有的,这个属性是在半生对象里边全局实现的啊,那大家如果要想看的更加清楚一点的话,我们可以看到对应的这个student啊,我们在target里边找到它编译之后。生成的class文件。
20:02
然后接下来哦,这个编译工具,我们可能需要重新的开启一下。好,我们把这个类拽进来,然后接下来看一下对应的结果,在这个结果里边,我们可以很清晰的看到student class,这之前不就是我们的那个入口类。呃,是相当于是我们之前的那个要程序执行的那个入口类,对吧?哎,所以大家会发现现在他同样还是入口类,还是public static voin放在这儿了,对吧,但是同样呢,它这里边还有我们之前。是不是在这个本生对象里边登明出来独一无二全局只有一份的那些属性也在这儿啊,大家看到下面是不是同样也有一个public static string school你了这样一个东西对不对?哎,那只不过这里边static定义出来的呢,这是一个方法,它真正意义上这个方法里边调用的时候还是调到了哪里呢?诶最后大家看到还是return了student Dollar这个里边这个是我们说这是真正意义上啊,最终我们。
21:20
定义的那个单利对象,全局只有一份的对象是放在这里的吧,所以大家看到这个对象里边的Mo daughter,哎,这里边还定义了一个final string school是在这儿实现的,这就是我们整个这个原理啊,当前的这个真正全局只有一份的这个对象是在student Dollar这里边声明出来,而student本身这个类呢,它是一个入口类。啊,那那另外大家会发现就是当前它的这个构造方法啊,我们这里边定义的这个name和age在这里边也都是有的,这里的属性同样还都是在这里面出现的,所以我们会发现它其实就是一个入口类加当前的伴生类,如果说我们把当前的伴生对象和伴生类同样都实现出来的话,要注意啊,他俩他俩要实现的一个前提就是。
22:13
名称必须一样,而且必须放在同一个文件里边,然后这样的话,它编译之后呢,编译之后得到的结果大家看到还是两个点class文件对吧?哎,那么当前的半生类所有的东西都会放在student啊,就是对应的这个我们之前说的应的那个半生类入口类。这个类里边这个点class文件里边,而对应的object,我们的诞生对象相关的东西呢,都会放在student Dollar对应的这一个类里面,就是之前我们讲的一个是半生类,一个是半生对象的所属类,这样的话,大家可能对这一部分内容就会理解的更加深刻一些。
我来说两句