不知道是ESET的问题,还是开发商的问题,我在千千静听官网下载的播放器、百度下载的百度影音和优酷下载的iKu软件,结果
都被ESET报潜在威胁,这软件编写的让人蛋疼,不知道杀软和应用软件什么时候才能正常。
前面几天因为公司的事,忙的不行,也就没有及时更新文字,今天小休班,因此来园子了逛逛, 继续我的Java之旅,前面大体
描述了一些Java的基础点,今天我们来讨论Java中的OOP。
【OOP】
OOP? 什么是OOP,说实话,我也不明白,我估计也没有一个完整的非常严格的定义,OOP这个概念需要描述,不是简单的定义
就能说明白的。
OOP:面向对象编程, 这里强调的是“对象”这个概念, 那什么是对象呢?如果您对Unix中,文件的概念比较熟悉的话,应该了解
这么一个事实:在UNIX中一切皆文件。 在这里,我们可以提升一个类似的概念: 在OOP的世界里,一切皆对象。就是说任何一个东西
、任何一件事都可以抽象为一个对象,这里有点辩证哲学的意味,有点方法论的调调;编程人员没有必要死死的抓这个概念,编程人员需要
理解的事OOP的各种特征: 封装、继承和多态。
【封装】
封装的目的就是为了躲猫猫,为了不让你任意的访问类中的实例域和方法。
封装: 封装是OOP的一个重要特点,有点像躲猫猫,也有点“金屋藏娇”的意思,这个“娇娃”也和时下炒作的沸沸扬扬的二奶一样,会给
你找麻烦。封装的目的就是不让你了解内部的具体实现。
封装从形式上看就是将:数据和操作行为耦合在一起,同时不向对象的使用者公开内部的具体实现和结构,而是提供给使用者一套接口,
使用者只要知道接口规范,就能正确无误的使用对象。
封装后对象的数据称为实例域,而操作数据的过程(有时候可能是函数)称为方法。
封装的要点就是:不能让对象的方法直接访问其他的类实例域。
【继承】
继承的目的是为了提高代码的复用性能。
继承这个概念或者说这个理论不知道和生物学有没有关系,看了很多资料都没有提及到这个问题,我一直很迷惑,因为大自然存在的很多
事情都是人类科技模仿的对象,也许这个也有关系。
继承和基因的遗传比较类似; 假令类A为父类(或者说是基类),类B为子类(或者说是扩展类),这样类B就具有类A所有的特性,这个
就与基因的遗传一样了,儿子继承了父亲的基因;而通常我们在设计子类的时候,不会完全与父类相同,这个就与基因的变异相似了;而如果
类B还继承了类C,这个就和儿子继承了来自母亲的基因类似了,但是很不幸的事,Java中不允许多重继承(悲剧了,C++中允许多重继承,Java
中的子类注定是个单亲家庭的孩子);如果要实现多重继承需要其他的机制,貌似接口机制可以实现。
【多态】
多态的目的是什么呢?多态的目的是为了提高接口的适用度。
多态性怎么说呢? 没有比较合适的比喻, 不过倒有一个场景适合说明这个问题:C语言中求两个数值最大值或者最小值的函数。
Exp:
int imax(int iValueA,int iValueB) { return iValueA>iValueB?iValueA:iValueB; }
这里我们可以看到,由于类型的限制,我么不能利用这个函数求实数的最大值,为了求实数的最大值我们必须写一个功能类似的函数
并且我们还必须为实数的函数设计一个新的名字,问题就来了,我们在使用的过程中,希望是一个函数名,既可以用来求int类型的最值,
同时也可以用来求实数的最值,这样使用者不必当心函数名是否正确,我们只需要使用一个统一调用格式即可。
这里求最值的函数我们希望是这样的: the_max_value=max(valueA,valueB); 这个调用格式既可以满足int类型,也可以满足
float类型,我们不必关心传入的参数的数据类型。 这在C语言中,是不太现实的,而OOP则可以非常容易的实现这个要求。在C++中通过
函数重载很容易实现;这就是说我们可以这样定义:
max(int ValueA,int ValueB); //method 1
max(double ValueA,double ValueB); //method 2
而我们调用的时候,采用: the_max_value=max(valueA,valueB); 即可,运行时会根据传入的参数类型,自动选择method 1 或者
method 2.
多态在Java中与C++的多态还有很多的不一样,例如在C++中可以实现运算符的重载,而在Java中不能进行运算符重载(前面说过的字符
串连接运算符 + 不是运算符重载的结果,虽然两者看起来非常相似)。
【OOP小结】
上面讨论的都是方法论范畴的东西,并没有涉及到具体的实现,这个需要注意,思想决定思路。
【类和对象】
大家应该见过塑瓷菩萨,手艺匠师有一个塑料的模子,然后会有已经搅拌好的石膏粉,当要塑造瓷菩萨的时候,匠师
将模子将石膏粉弄成菩萨的模样后,将模子取下来就是一个菩萨。
这里类就是模子,对象就是塑成的菩萨,而石膏粉就是内存空间了。
【对象】
要使用一个东西,这个东西必须存在;否则就是镜花水月了。
对象也一样,要使用对象,必须先存着对象,那么在Java中对象是如何来的呢?
在OOP中,要用构造器来构造对象;接触过C++的人,应该知道,在C++中,构造器就是类的构造函数。而在Java中也一样必须有
构造器来构造对象。
Java中构造器是类的一个公有的方法(public method);构造器必须与类名一致;构造器用来实例化一个对象,同时设定对象的初始状态。
构造器方法可以有参数,也可以没有参数。
在用构造器方法实例化对象的时候,需要向系统申请内存空间,这个申请空间的过程由new操作符来完成。例如在Java内置库中有一个Date类,
如果我们需要构造一个Date对象,如下所示:
new Date();
这里我们确实构造了一个Date对象,但是如果这样的话,我们以后将没有办法使用这个Date对象
当然如果对象仅需要使用一次,那么我们可以这样做:
String dateStr=new Date().toString;
这里我们使用了这个对象的方法toString。
如要我们需要在构造一个对象后,多次使用这个对象,那么就需要定义一个对象变量。通过对象变量来引用构造出来的对象。如下
所示:
Date birthday; //定义了一个Date类的对象变量,这个对象变量分配了内存空间,但是这个内存空间不是Date对象需要的内存空间。
birthday=new Date(); //将birthday与新构造出来的Date对象关联起来,同时new 操作符向系统申请了一块空间来表示Date对象。
这里我们需要分辨一下birthday对象变量和Date对象。他们的关系如下图所示:
这里与C++中的引用有点类似,但是需要分辨引用与对象变量之间的区别。在C++中,没有空引用,同时在C++中引用不能多次赋值;
就是说在C++中引用在设定好后,就不能被改变,而在Java中对象变量是可以改变指向的,这一点需要注意。
要点:
对象变量不是对象本身,并且只有当用对象初始化对象变量后才能使用对象变量。
Date birthday; String str=birthday.toString(); //编译时错误
这里错误是因为对象变量只有被对象初始化后才能引用对象。初始化对象变量有两种方法,如下所示。
Exp:
Date birthday=new Date(); Date deadline; deadline=birthday;
birthday和deadline之间的关系如下图所示:
要点:
【空对象】
在Java中有一个预定义的对象null——空对象。
可以显示的将一个对象变量设置为null, 设置为null的对象变量表示没有引用任何对象。如果调用设置为null的对象变量的方法,就相当于引用一个空对象,
引用空对象的方法将产生一个运行时错误。
Exp:
Date birthday=null; System.out.println(birthday.toString()); //将产生一个运行时错误
【对象的存储空间】
这里暂时不讨论这个问题,等我们将OOP这个主题讨论完后,我们再来讨论一下对象空间分配的相关内容。
【更改器方法和访问器方法】
我们知道类中的实例域保存的对象的信息,而方法是用来对实例域进行操作的;这里我们一般将读取实例域信息的方法叫做访问器方法;
而将修改实例域的方法叫做更改器方法。
设计更改器方法和访问器方法的目的是支持对象(或者说类)的封装特性。
要修改或者获取一个类的实例域,通常建议用更改器方法或访问器方法,这样可以保证实例域访问的有效性。
虽然我们可以定义public的实例域,但是不建议这么做,为了封装性,建议用更改器方法和访问器方法。
【设计一个雇员类】
雇员类应该包括什么信息呢?
1、name
2、gender
3、phone number(telphone number)
4、salary
前面说了要实例化一个对象,必须有构造器,因此雇员类还必须至少有一个构造器方法。
1、employee();
为了获取雇员的信息和修改雇员的信息,我们还必须有更改器方法和访问器方法。
1、getName;
2、getGender
3、getPhoneNumber
4、getSalary
5、setName
6、setGender
7、setPhoneNumber
8、setSalay
我们获取信息后,有时需要打印出来查看,这就需打印相关的方法
1、printName
2、printGender
3、printPhoneNumber
4、printSalary
【代码风格】
在设计类的时候,代码的顺序一般不影响程序的运行,但是在实际操作的时候,不同的人会有不同的风格,
例如有的人喜欢这样设计:
class className
{
field1;
field2;
.....
construct method1;
construct method2;
.....
method1;
method2;
.......
}
而有的人则喜欢这样设计:
class className
{
construct method1;
construct method2;
.....
field1;
field2;
.....
method1;
method2;
.....
}
还有的人喜欢这样设计:
class className
{
construct method1;
construct method2;
.....
method1;
method2;
.....
field1;
field2;
.....
}
我个人认为,究竟使用哪种风格并不重要,重要的是要在代码编辑的过程中,保持一致,这样才不至于给后期的代码维护和升级带来
太多的麻烦。
不过我现在看的这本书的作者则喜欢第三种风格;作者是这样的认为的:
使用这种风格会促使类的设计者在,在没有编辑代码的时候,首先设计好类,然后才决定编写代码,这样不会在代码编辑的过程中出现写到
一半的时候突然想起需要增加一个实例域或者突然想起要增加一个方法的情况,这样时间长了有利于提高程序人员的设计类的实践能力。
【代码】
下面是设计的代码,因为时间的原因,没有写完了。
/* 设计雇员类 */ class employee { public employee(String inName,boolean inGender,String inPhoneNumber,double inSalary) { if(!setName(inName)) { } setGender(inGender); setPhoneNumber(inPhoneNumber); setSalary(inSalary); } public String getName() { return Name; } public boolean getGender() { return Gender; } public String getPhoneNumber() { return PhoneNumber; } public double getSalary() { return Salary; } public boolean setName(String inName) { if(inName.equals("")) { System.out.println("you haven't enter you name"); retrun false; } Name=inName; } public boolean setGender(boolean inGender) { } public boolean setPhoneNumber(String inPhoneNumber) { } public boolean setSalary(double inSalary,boolean raise) { } public void printName() { } public void printGender() { } public void printPhoneNumber() { } public void printSalary() { } private String Name; private boolean Gender; private String PhoneNumber; private double Salary; }
呵呵,下次有时间将代码不全,同时这个地方还有点内容需要在讨论一下。