---------------------------------------------------------------------------------------------------------------------
面向对象思想:
对象的定义:
a. 广义的对象的定义:对象是世界中的物体在人脑中的映象。 它概括了世界上的物体的一些基本属性和特有
特性;比如说到猪这种动物,那么人们大脑当中立刻会产生猪的一些基本:四条腿,长鼻子,大耳朵,肥硕,
有尾巴;此外还会想起猪的一些特有特性:肉好吃。
b. 在java领域下的对象定义:把数据及对数据的操作方法放在一起,作为一个相互依存的整体,这就是对象;
相应的做法就是:
谁持有数据,就将操作数据的方法定义在谁身上;这样一个由数据和操作数据的方法构成的整体
就是一个对象--------也就是类这种用来描述事物属性和行为的代码!
从上图中我们知道了在java中对象其实就是类,当然此外还有枚举、接口等;
只不过类是对象的最常见的表现形式;
下面我们着重来讲一下类;通常我们通过定义一个类从而定义一个对象:
类---------------------------对象
类中的变量-------------对象的特有属性
类中的成员方法-----------对象的特有行为
比如我们定义一个类来描述一只公鸡:
公鸡有哪些特有属性呢? 大红冠子,花外衣!
公鸡又有哪些特有的行为呢? 公鸡会打鸣!
于是我们可以通过java代码的形式将公鸡这个对象描述出来:
class Cock{
Clothes clothes = colorfulClothes; //特有属性:花外衣;
Hat hat =BigRedHat; //特有属性:大红冠子;
public void tweet(){ //特有方法:打鸣;
System.out.println(“喔喔喔!”);
}
}--------------------------------------------(伪代码!)
面向对象编程是一种开发过程中使用的思想,他与面向过程编程的区别,我用下图表示:
从上图可以看出:面向对象编程的思想框架比较类似于西欧古代的层级分封制度,主函数就相当于是皇帝;
而一级对象就是公爵,他直接向主函数负责,而他下面又有二级对象这些伯爵,直接效命于他;而二级对象
下面还有三级对象这些子爵……,由这一级一级的对象组成了一个java程序的框架;同时为了提高皇帝的权利
范围,皇帝还可以直接命令二级,三级等这些对象(如图中紫色虚线所示),这样使得程序的灵活性更高!
这也是java的面向对象编程思维框架与西欧古代的层级分封制度不同之处:
西欧古代的层级分封制度中原则是:附庸的附庸不是我的附庸!
而java面向对象编程在它的基础上变成了:如果皇帝想,任何附庸还是皇帝的附庸!
而面向过程编程的框架图如下:
从上图我们可以看出:所有的事情都需要皇帝,也就是主函数调用者亲力亲为;实在是个苦命皇帝啊!
这样一来程序员需要同时统筹安排的事情就太多了,开发起来就比较痛苦!同时一旦任何一个过程出现了
问题,查找起来也更费力!
java面向对象编程就是规划安排对象:
a. 开发的过程就是找对象使用的过程,如果没有对象就创建一个对象,也就是自己定义一个类,
然后将这个类实例化;
b. 开发需要找对象,建立对象,使用对象并维护对象之间的关系。
---------------------------------------------------------------------------------------------------------------------------------------------
类的结构组成:
一个类主要包括变量和方法,有时候还有构造代码块以及静态代码块。
|----静态代码块|---格式:static{ 静态代码快中的执行语句;}
| |---特点:随着类的加载而执行,只执行一次,优于主函数执行
|----构造代码块|---格式:{ 给对象进行统一初始化的代码;}
| |---作用:给对象进行初始化,对象一建立就运行,而且优于构造执行,可以被执行多次!
类 | |-----局部变量:作用于函数或者语句中,存在于栈内存中;
|-----变量 |-----普通成员变量:作用于整个类中;存在于堆内存中;
| |----静态成员变量:被所有对象共享,存在于方法区中;
|-----方法|----构造方法:用于建立建立对象,给对象进行初始化;
|----普通函数:通过对象调用,存在于方法区的非静态区中;
|----静态函数:可以通过类名直接调用,存在于方法区的静态区中;
当一个类中没有定义构造函数时,系统会默认给该类添加一个空参数的构造函数,
如果该类中自定义了构造函数,那么默认的构造函数就没有了!
---------------------------------------------------------------------------------------------------------------------
面向对象的三个特征:封装,继承,多态;
面向对象的特征一-----------《封装》
何谓封装:就是指隐藏对象的属性和实现细节,仅仅对外提供公共访问的方式;就类似于给你一台式电脑,
你不需要知道其内部 构造以及内部元器件的工作原理,你只需要通过通过USB连上鼠标,键盘便
可以访问和使用他了!-----在这里主机箱将 cpu,显卡,内存条,主板封装了起来,仅仅提供了
USB接口作为公共访问方式!
封装的好处:将变化隔离;便于使用;提高重用;提高安全性;
封装的原则:将不需要对外提供的内容隐藏起来;把属性隐藏起来,提供公共方式对其访问。
前面我打过比喻:调用者是主子,而被调用者是臣子;俗话说:君让臣死,臣不得不死;但是这一套在公正
民主的今天已近不适用了,君主有道理的命令,臣子应该执行,但是君主无理的命令,,臣子有权利拒绝:
class Courtiers{
private money;
//定义了臣子要上交税金,此时还是变量,需要皇帝指定;
public void setMoney(int a){
//设置臣子应该上交多少税金;
if(money>0 && money<10000){
//对皇帝的要求进行一个判断,合理才执行!
this.money = a;
}else{ //如果皇帝的要求太过分了;
System.out.println(
“陛下,下官交不起啊!请收回成名!”);
}
}
public void handinMoney(){
System.out.println(“臣子上缴的税赋为:”+money)
}
}
这样一来皇帝就不能对手下的臣子乱摊派了!国家也就更稳定了!
对应到java程序代码上面代码也就更加健壮了!
通常最常用的封装形式是通过private修饰符,将类中的成员封装起来,然后通过被public修饰的getXxx( )和setXxx( )方法,
将来操作和访问这些被封装起来的成员。但是不能说封装就是private,只要无法直接访问,要通过人家提供的
公共方法才可以访问,那么对于调用者来说,他所访问的成员都是被封装了的!
―――――――――――――――――――――――――――――――――――――――
面向对象的特点二--------------《继承》
我们知道现实世界中事物之间是有关系的,他们都是被系统划分了的:比如老虎、豹子、猫等一类的
动物被划分为猫科动物;苹果、梨、葡萄、西瓜等被划分为水果;各省市自治区的人按照户籍分为了广东人,
广西人,山东人,东北人……这样好处是:便于政府的管理。在java中为了更好的管理那么多的类,也通过
“继承”建立了一个“户籍制度表”,方便我们管理这些对象!
继承使得对象的分工更加明确:在最初原始社会所有人同耕同住,干的事情是一样的,但是慢慢的发现有
些人更适合种田,而有的人更适合打猎,于是在继承先辈的基础上,有些人发展成为伐木工,有的人发展成为
采矿工,有的人发展成为猎人;他们都在保持了先辈特性的基础上,增加了自己特有的能力;对应到java里面,
比如最初有一个类叫做Exception(异常),他表示程序出现了一些问题,但是具体是哪一方面的就不知道了,
排查起来就比较慢了,于是通过继承将他进一步细分为:数组角标越界异常,空指针异常,格式转换异常……
这些异常除了具备Exception的特性外,还有了自己的特性,这时候一旦发生了某个具体异常,
查找起来就更加方便快捷了!
继承的关键字——extends
比如有两个类class A 和 class B,如果向要B继承A,只需要:
class B extends A{ B中的特有成员; }
这样一来B除了拥有B中的特有成员以外还具备了A的所有的成员;所以我们可以看相互继承的出现---提高了
代码的复用性;此外还让A和B之间产生了关系---为多态奠定了基础!
在这里A被称为父类(或者超类),而B被称为子类。
继承的原则:
1. 不能单单为了获得某一个类的功能或者属性而去胡乱继承另一个类,必须是类与类之间有从属关系才可以
去继承!如 果被继承的类中有的东西在继承类中是不应该出现的那么就千万不可以去继承!
2. 如果一个类已经继承过其他的类了,那么他就没有资格再去继承其他类了!否则会有可能发生安全隐患!
比如:两个父类中有同名一个方法,那么子类就不知道到底是去执行哪一个方法了!----也就是说:
java不支持多继承!
但是java支持多层继承:
也就是说A继承了B,同时B还继承了C;A是孙子,B是儿子,而C是爷爷!
如何使用一个继承体系的功能呢?
想要使用体系,先查阅体系中父类的描述,因为父类中定义了体系中的共性功能,通过了解共性功能,就知道
了该体系的基本功能;那么这个体系已经基本可以使用了;在调用时,通常是创建最子类的对象:
(1)因为有可能父类并不可以创建对象;
(2)创建子类对象可以使用更多的功能,包括基本功能也包括子类特有功能!
简单一句话:查阅父类功能,创建子类对象来使用功能!
抽象类:被abstract关键字修饰的类!
抽象类的特点:
1. 抽象类中有抽象方法(可以不定义抽象方法,这样是为了不让该类创建对象);
2. 抽象方法和抽象类都被abstract关键字所修饰;
3. 抽象类无法用于new对象,因为调用抽象方法无意义;
4. 抽象方法要被使用,必须由子类复写其所有的抽象方法之后,创建子类对象调用;
接口----interface:
初期的理解是:一种特殊的抽象类;它里面的方法全都是抽象的;
在形式上只是将类的class标识换成了interface;
在接口中的成员都有特定的格式:-----------少了系统会帮你自动加上!
常量被:public static final 所修饰;
方法被:public abstract 所修饰;
子类与父类之间的关系是继承---extends,并且只能单继承;
类与接口之间的关系是实现----implements,并且是可以多实现的。
并且类的继承和实现是不矛盾的,可以在集成的同时实现某个或多个接口!
接口与接口之间是可以多继承的!
接口也是不可以创建对象的,因为它里面的方法全部是抽象方法,需要在被子类全部复写之后才可以创建
子类的对象来使用里面方法,有任何一个抽象方法没有被复写,那么子类就是一个抽象类!
接口的特点:
1. 借口是对外暴露的规则;
2. 接口是程序的功能扩展;
3. 借口可以用来多实现;
4. 类与接口之间是实现关系,而且类可以集成一个类的同时实现多个接口;
5. 接口与接口之间有继承关系。
在继承这一块有一个很重要的知识点-----复写(也叫覆盖):
当子类集成父类,沿袭了父类的功能到子类中但子类中虽然具备了此功能,可是功能的内容与父类不一致,
这时候没有必要定义新的功能,而是使用覆盖的特性,保留父类的功能定义,并重写功能的内容,也就是说将
继承过来的函数的函数体部分(也就是被大括号括起来的部分)进行了改造,而函数的其他部分与父类完全
一致,这就是复写!从外表上看上去字符类中方法外貌完全一样,但是内在却是不同的。
注意事项:
1.子类覆盖父类,必须保证子类的权限大于等于父类,否则编译失败;
2.静态只能覆盖静态;
3.重载只看同名函数的参数列表,而重写要求子父类函数一模一样,包括返回值类型;
4.当父类的函数被private修饰,那么子类是无法复写此函数的。
子父类中构造函数的特点:
在对子类对象进行初始化时,父类的构造函数也会运行,因为子类中构造函数的第一行
有一条隐式的语句: super( );而他会访问父类中空参数的构造方法,而且子类中所有的构造函数第一行都是
super( );当然子类中的构造函数第一行也可以用this语句访问本类中某一个访问父类中构造函数的构造函数;
当父类中没有空参数的构造函数时,必须用super(x)手动设置访问动作,否则编译器会报错!
―――――――――――――――――――――――――――――――――――――――---------------------
面向对象的特点三-----《多态》
多态就是事物存在的多种形态!打个比喻:到宠物店里买宠物,我让店家给我一只宠物,于是人家给我了
一条宠物狗,或者给我了一只宠物猫,又或者给我了一直宠物猪……在这个例子中,我所要求的宠物就具有了
多种形态,可能是狗,可能是猫,还可能是猪……可以看出宠物相对于宠物猫、宠物狗、宠物猪……是父类,
而宠物猫、宠物狗、宠物猪是在继承了宠物后,对宠物的细分。
多态在代码中的体系:父类或者接口的引用指向的子类实际对象具有多样性,但是代价就是父类或者接口
的引用指向的子类实际对象具有不确定性!
pet x =new petcat( ); //父类宠物x指向了子类的一个具体对象宠物猫。
对态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容;
例如:class DuoTaiDemo{
public static void main(String[ ] args){
function(new Cat);
function(new Dog);
}
//下面函数的参数列表用多态,既可以接受Cat,又可以接收Dog;
//简化了代码,提高了代码的扩展性!
public static void function(Animal a){
a.eat( );
}
}--------------------------(伪代码,仅供解释说明使用!)
多态的弊端:
前期定义的内容不能调用后期子类的特有内容;这是因为通过多态父类引用指向的子类实际对象具有不确定性,
有可能指向宠物猫,有可能指向宠物狗,还有可能指向宠物猪,这是万一父类的引用指向一只宠物狗,而你却
调用了宠物猫“喵喵叫”的功能,这就会出现错误,所以为了避免有这种安全隐患,java中就直接要求说:父类
的引用指向的子类对象虽然有自己的特有功能,但是父类的引用不可以去调用这些特用功能!
此外,我们还可以这样理解:调用者只是要求给他一只宠物,却不知道具体是哪种宠物,那么他就不可能
知道给他的宠物的具体的特有方法!那么他也不会去调用这种特有方法,如果调用者调用了的话,也就违背了
逻辑事实,编译器就会报错!当然,java还是很开明的,如果调用者实在是想使用子类的特有方法,那么只要
你证明了子类对象确实有这个方法,并完成一个类型转换,编译器在检查通过后,你就可以使用了!
如何证明:
class DuoTaiDemo{
public static void main(String[ ] args){
function(new Cat);
function(new Dog);
}
public static void function(Animal a){
a.eat( );
if(a instanceof Cat){ //向编译器证明子类对象确实是一只猫!
Cat c = (Cat)a;
c.catchMouse( );
}else if(a instanceof Dog){ //证明子类对象是一只狗!
Dog d = (Dog)a;
d.kanJia( );
}
}
}
多态使用的前提:类与类之间必须存在关系,要么是继承,要么是实现,另外存在复写!
多态中非静态成员的特点:
在编译时期:参阅引用类型所属的类中是否有调用的方法,如果有的话,则编译通过,否则编译失败;
在运行时期:参阅对象所属的类中是否有调用方法,如果有的话,则编译通过,否则编译失败;
简单的讲就是:编译看左边,而运行看右边;
多态中静态成员的特点:无论编译还是运行都参照左边;