本帖最后由 扬州城 于 2018-12-18 19:11 编辑
基础班的学习已结束,半个多月的时间里,Java基础部分就已学习完毕。不得不说时间过得真快,感觉仿佛又回到了学生时代,每日与周围一帮志同道合的同学一起奋斗的感觉真不错,连饭量都增加了不少,不过扫地时看到地上最多的东西是头发让我心慌不已… 在来到黑马学习前,我对Java可以说一无所知,而各类语言中我也仅仅是在大学时学过一点点C 语言,算是0基础吧,不过既然下定决心踏入计算机这一行业,那就坚定地走下去吧~ 基础班的内容说多不多,不过细究下来,个人认为有两个点还是需要深入了解一下,一个是堆与栈还有方法区中存储内容的区别,另外一个则是抽象类与接口的区别。 首先来看第一个:堆、栈、方法区,而寄存器和本地方法区与我们开发无直接关系,不提。 先看栈(Stack):栈存储的都是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,也就是说只有方法存在局部变量才能存在,这样就可以理解为什么局部变量有自己的作用域。栈内存的更新速度很快,因此局部变量的生命周期都很短。栈内存遵循“先进后出,后进先出”。 堆(Heap):用于存储对象及数组的地方,其实数组也是对象。每当我们创建一个新的对象时,JVM就会在堆内存中为对象开辟一个空间,用于存储该对象的成员变量,和成员方法的地址值。每一个对象都有自己的地址值,当使用对象的时候,其实是将对象的地址值作为参数在传递。 在此举个例子谈谈基本数据类型和引用数据类型的区别(简写): main(){int a= 1; int b = 1; a = 2;} 在以上程序中,我们首先创建了一个int类型数据a,将其值赋值为1;编译器的动作为:首先查找栈中有没有为“1”的一个值,没有,创建“1”,将a指向字面为“1”的地址(注意此处不是对象的引用);接下来我们创建b,编译器动作:查找“1”这样一个值,同样将b指向“1”的地址,这里体现的是栈的数据共享特点;最后我们将a赋值为2,那么b的值会改变吗?答案是不会的,此时编译器的动作:首先在栈中查找有没有“2”这样的一个值,有的话就将“2”的地址给b,没有,创建“3”,再将“2”的地址给b,而a的值或者说其指向“1”的地址不会发生改变,因为二者的值“1”和“2”不同。那为什么不会把“1”变成“2”之后再赋值给b呢,因为:常量固定不变。 接下来谈谈对象的引用,限于篇幅就简写了: main(){ Studentstu = new Student; stu.name = “马冬梅”; Studentstu1 = stu; (1) Stu1.name= “马什么梅”; (2) } 在以上程序中,我们首先创建一个对象在堆内存中创建一个对象stu,JVM为其开辟一个空间,同事将空间的地址值赋值给stu,此时再将成员变量name赋值为“马冬梅”;接下来(1)中,我们创建对象stu1,然后将stu的值,也就是地址值,赋值给stu1,其实这两个对象都是指向同一个空间,在这同一个宇宙下只有一个叫“马冬梅”的成员变量name,所以此时不管是stu1还是stu,他俩的name都是“马冬梅”;之后出现了一位老大爷,非要把name变成“马什么梅”,那么我们能看到的就是stu1的name变成了“马什么梅”,同理,stu与stu1其实是同一个空间,那么同一个宇宙下只有一个成语变量name被老大爷变成了“马什么梅”,因此stu的name也就成了“马什么梅”。这就是对象的引用,在引用数据发生改变时,指向该数据的所有变量的值就都会被改变。 最后再谈谈方法区(Method Area):用于存储.class文件的地方,来谈谈其中一个比较特别的地方:静态区。当我们在类中利用static关键字定义了静态成员变量或者方法时,该变量或者方法就将存储在静态区,那么这些内容将不会随着新对象的创建而发生初始化,我们通常将一些对象共性的内容定义为静态。在此我以课堂中第八天的内容为例说明,该案例中需要为每一位学员分配学号,为此定义了两个相关的成员变量:id 和idCounter,那为什么需要两个而不是一个呢?为什么需要一个非静态一个静态呢?各自轮换用static修饰又会怎样呢?以下图片是我的分析过程,由于视频上并未讲解两个变量在新对象创建过程中各自的变化,所以当时理解花了些时间,后来源哥在课堂上又提及,具体分析请看图片(注:所有的学号都在所有对象创建完成之后再打印,如果每创建一次打印一次,结果会与我图片分析的不一样,不过原理相同)(再注:原来这玩意儿不能直接放图片,只能放在附件了...)
接下来谈谈抽象类与接口的区别,视频中只是讲了一些它们在语法上的区别,但是个人认为还是需要深入去理解才能知道今后如何使用。 抽象类:通过abstract关键字修饰的类成为抽象类,在抽象类中不一定要有抽象方法,可以有成员变量、成员方法、构造方法、静态方法、私有方法等等,而抽象方法所在的类必须是抽象类,抽象类不能直接创建对象,必须通过子类来创建。其实抽象类与普通类的区别主要在于是否有抽象方法和能否直接创建对象,记忆时记住这两个点。 接口:通过interface修饰。接口中只能有几种存在:常量、抽象方法、默认方法、静态方法、私有方法。在接口中定义成员变量必须使用final关键字,其值不可更改,也就变成了常量。接口同样不能直接创建对象,必须通过实现类来实现。与抽象类不同的是,抽象类只能单继承,而接口可以多继承或实现。 以上是抽象类与接口在语法上的区别,而在设计理念上才是它们的本质区别。 抽象类的存在,是因为该类的实例中某些成员方法都存在,但各自的行为体现却不一样,为了满足这种需求,需要在抽象类中定义抽象方法,但没有方法体,具体方法体交由子类重写。这其实是一种“由下至上”的设计理念,由于实现类有需求,因此在抽象类中将该需要抽象出来,为实例服务。 接口则相反,接口是事先定义抽象方法,而其实现类必须完成重写这些抽象方法,这是一种“由上至下”的设计理念,是一种类似于“契约”关系,如果你要采用我这个接口,那么你必须遵守我的协议,正如接口的定义:所以实现类提供一个共同的规范契合。举个例子:PCI接口。请勿认为接口就是主机板上的插槽,其实它是指主机板的那个插槽遵守了PCI规范,而插槽本身则是PCI接口的实例。对于不同型号的主板,它们各自的PCI接口插槽都遵守了PCI协议,因此同一个PCI接口设备可以在不同的主机板上通用。 以上两个大点就是个人认为在基础阶段需要深入了解的点,以上分析参考了CSDN论坛和《Java疯狂讲义》的观点,因为个人能力有限,因此可能部分观点有些偏颇,如有不同的见解还请在评论区指出,共同学习,共同进步。 最后借用一句话与JavaEE14班的同学么共勉:天降大任,必先苦其心志,劳其筋骨,空乏其身,行拂乱其所为,所以动心忍性,增益其所不能。
|