JAVA面向对象
1. 什么是面向过程?什么又是面向对象?
面向过程——步骤化
面向过程就是分析出实现需求所需要的步骤,通过函数(方法)一步一步实现这些步骤,接着依次调用即可
面向对象——行为化(概念相对抽象,可结合下面的例子理解)
面向对象是把整个需求按照特点、功能划分,将这些存在共性的部分封装成类(类实例化后才是对象),创建了对象不是为了完成某一个步骤,而是描述某个事物在解决问题的步骤中的行为
举个例来了解一下
例如我们设计一个桌球游戏(略过开球,只考虑中间过程)
A:面向过程方式思考:
把下述的步骤通过函数一步一步实现,这个需求就完成了。(只为演示概念,不细究逻辑问题)。
① palyer1 击球 —— ② 实现画面击球效果 —— ③ 判断是否进球及有效 —— ④ palyer2击球
⑤ 实现画面击球效果 —— ⑥ 判断是否进球及有效 —— ⑦ 返回步骤 1—— ⑧ 输出游戏结果
B:面向对象方式思考:
经过观察我们可以看到,其实在上面的流程中存在很多共性的地方,所以我们将这些共性部分全集中起来,做成一个通用的结构
玩家系统:包括 palyer1 和 palyer2
击球效果系统:负责展示给用户游戏时的画面
规则系统:判断是否犯规,输赢等
总结:
我们将繁琐的步骤,通过行为、功能,模块化,这就是面向对象,我们甚至可以利用该程序,分别快速实现8球和斯诺克的不同游戏(只需要修改规则、地图和球色即可,玩家系统,击球效果系统都是一致的)
面向过程和面向对象的优缺点
A:面向过程
优点:性能上它是优于面向对象的,因为类在调用的时候需要实例化,开销过大。
缺点:不易维护、复用、扩展
用途:单片机、嵌入式开发、Linux/Unix等对性能要求较高的地方
B:面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:一般来说性能比面向过程低
低耦合:简单的理解就是说,模块与模块之间尽可能的独立,两者之间的关系尽可能简单,尽量使其独立的完成成一些子功能,
这避免了牵一发而动全身的问题。这一部分我们会在面向对象学习结束后进行系统的整理和总结。
总结:只通过教科书后的例题是无法体会到面向过程所存在的问题的,在一些小例程中,面向过程感觉反而会更加的简单,
但是一旦面临较大的项目,我们需要编写N个功能相似的函数,函数越来越多,代码量越来越多,你就知道这是一场噩梦了。
说明:关于性能的问题,这里只是在笼统意义上来说,具体性能优劣,需要结合具体程序,环境等进行比对
1.1 对象的产生格式:
类名称 对象名 = new 类名称();
2. 说一说类、对象、成员变量和成员方法的关系和理解
类:一组相关的属性和行为的集合,是一个抽象的概念。
对象:该类事物的具体表现形式,具体存在的个体。
成员变量:事物的属性
成员方法:事物的行为
3. 访问权限修饰符 public、private、protected, 以及不写(默认)时的区别
- public:公共的,可以被项目中所有的类访问。
- protected:受保护的,可以被这个类本身访问;被同一个包中的类访问;被它的子类(同一个包以及不同包中的子类)访问。
- default:默认的,可以被这个类本身访问;被同一个包中的类访问。
- private:私有的,只能被这个类本身访问。
4. static 关键字修饰的作用?
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。 —— 《Java编程思想》P86
可以知道,被 static 关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。也就是说,即使没有创建对象也可以进行调用(方法/变量)
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
4.1 什么是静态方法
*static 修饰的方法一般叫做静态方法,静态方法不依赖于对象访问,因此没有 this 的概念(this 代表所在类的对象引用),正因如此静态方法能够访问的成员变量和成员方法也都必须是静态的
- 例如在静态方法 A 中 调用了非静态成员 B,如果通过 类名.A 访问静态方法 A,此时对象还不存在,非静态成员 B
自然也根本不存在,所以就会有问题。调用非静态方法 C 也是如此,你不清楚这个方法 C 中是否调用了费静态变量*
4.2 什么是静态变量
static 修饰的变量也称作静态变量,静态变量属于类,所以也称为类变量,存储于方法区中的静态区,随着类的加载而加载,消失而消失,可以通过类名调用,也可以通过对象调用。
4.3 什么是 静态代码块
静态代码块是在类中(方法中不行)使用static关键字和{} 声明的代码块
static {
... 内容
}
执行: 静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。
作用: 一般情况下,如果有些代码需要在项目启动的时候就执行,这时候 就需要静态代码块。比如一个项目启动需要加载的 很多配置文件等资源,我们就可以都放入静态代码块中。
4.3.1构造代码块(补充)
概念:在java类中使用{}声明的代码块(和静态代码块的区别是少了static关键字)
执行: 构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行。
作用 :和构造函数的作用类似,都能对对象进行初始化,并且只创建一个对象,构造代码块都会执行一次。但是反过来,构造函数则不一定每个对象建立时都执行(多个构造函数情况下,建立对象时传入的参数不同则初始化使用对应的构造函数)。
因为每个构造方法执行前, 首先执行构造代码块,所以可以把多个构造方法中相同的代码可以放到这里,
5. 面向对象的三大特性:
1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
2、继承
提高代码复用性;继承是多态的前提。
3、多态
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
6、匿名对象
一个没有名字的对象, 创建了一个对象出来,没有赋给一个变量;
特点:
- *对方法或字段只进行一次调用时;
- 可作为实际参数进行传递;
- 只在堆里面开辟存储区域,
- 只能使用一次, 使用完就被销毁了;
- 何时使用?只拿来用一次!!
- new Person();表示匿名对象,没有名字的对象
- new Person().age = 17;//使用一次之后就被销毁了*
7、this关键字
特点:this表示当前对象。
当前对象 ←→ 当前正在调用实例成员的对象
换言之:谁调用了方法,谁就是当前对象。
什么时候使用this关键字呢?
方法间的相互调用;
this.字段;
构造器中相互调用,但是此时this([参数])必须写在构造方法第一行。
this不能用在static修饰的方法里和static修饰的代码块里;
构造方法中的this.name = name;
五大基本原则
单一职责原则SRP(Single Responsibility Principle)
是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
开放封闭原则OCP(Open-Close Principle)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,
那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。
替换原则(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,
也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。
依赖原则(the Dependency Inversion Principle DIP)
具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,
B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,
B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B
定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成
循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。
接口分离原则(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来