03-面向对象OOP

面向对象OOP

引言

计算机语言发展的主线

随着计算机深入人们的生活,所要解决的问题越来越复杂,同时计算机运行速度越来越快,问题的解决更大程度上指的是问题本身而不是解决问题的效率,为了适应这种需求,计算机语言越来越向方便人类思考问题的方向发展。

最初的计算机语言只有基本变量(类似我们学习的基本数据类型),用来保持数据。

但是数据多了怎么办?成千上万的数据怎么处理?于是有了数组的概念,通过数组将这同类型的数组进行组织。

后来,数据不仅多了而且复杂了怎么办?数组只能存放同类型的数据,于是产生了结构体(c/c++中的struct),可以将不同类型的数据包括在一个数据结构。

后来,数据不仅多了,复杂了,而且对数据的操作(指的就是方法)也多了复杂了,怎么办?结构体只包含了数据,没有包含对数据操作的方法。即,数据和方法是分离的,虽然他们联系紧密但是各自为政。于是,类和对象产生了。说白了,对象也是一种数据结构而已。包含了:不同的数据类型(属性field)和相关的操作处理(方法method)。

面向过程:数据和方法是分离的。
面向对象:数据和方法集成到一起,便于扩展。

事务处理的主线

我们常说高级语言分为:面向过程和面向对象。面向对象和面向过程首先存在思想上的区别和联系。

对于小而简单的问题,为了快速,为了方便,我自己会动手从头到尾处理;对于庞大且复杂的问题,我一个人,已经不够用了,时间不够,精力不够,学识也不够,所以我会找其他人来帮忙。而且个个都是专业的。

例如:让你搬一块砖从小店到迎泽,很简单,弯腰捡起砖头,扛在肩上,大步朝前走就行,到达目的地放下即可。但是如果现在要让你从小店修一条路到迎泽,这个…

再例如:原来开一间10平米的小杂货铺,一个人足够负责铺子里的每一样事物。现在要开一家五层的百货商场,如果只有你自己,想想都头疼…

作为整个大局的规划者(程序的设计者),我需要从宏观上把握、从整体上合理分析,此时我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,还是需要面向过程的思路去处理

总结

  • 都是解决问题的思维方式,都是代码组织的方式。
  • 解决简单问题可以使用面向过程
  • 解决复杂问题:宏观上使用面向对象把握,微观处理上仍然是面向过程。

面向对象思考方式:遇到复杂问题,先从问题中找名词,然后确立这些名词哪些可以作为类,再根据问题需求确定的类的属性和方法,确定类之间的关系。

对象和类的概念

认识事物的过程

首先,我们需要考虑一个问题“为什么叫做面向对象,而不是面向类?”。计算机语言越到高级越接近人的思维方式,这是语言发展的一个基本规律。我们人认识世界,其实就是面向对象的。大家眼里都是一个个对象,要不怎么老说搞对象搞对象啊。

当我们认识一个新事物的时候,都会有一个抽象的过程,比如“龙”这个神兽,现实中没有吧,但是我们现在是能够分辨出来的,那是因为我们在电视上、书上都见过很多龙的身影了。在我们脑子里已经将之前看到过的这些龙的特征抽象出来了。

对象:是具体的实物
:是对对象的抽象
类可以看做是一个模版,或者图纸,系统根据类的定义来造出对象。

类和对象的关系

对象和类的关系是特殊到一般,具体到抽象。
类:我们叫做 class 。
对象:我们叫做 Object , instance (实例)。以后我们说某个类的对象,某个类的实例。是一样的意思。

类的定义方式

定义

语法:

class 类名{
   
 
}

class是定义类的关键字
类名需要满足命名规则和规范,类的命名应该使用大驼峰命名原则。

示例:

class Phone{
   
 
}

上面的类定义好后,没有任何的其他信息,就跟我们拿到一张张图纸,但是纸上没有任何信息,这是一个空类,没有任何实际意义。所以,我们需要定义类的具体信息。对于一个类来说,一般有三种常见的成员:属性 field 、方法 method 、构造器 constructor 。这三种成员都可以定义零个或多个。

类的属性

属性用于定义该类或该类对象包含的数据或者说静态特征。

属性作用范围是整个类体。

属性定义格式:在类中,所有方法和代码块之外。

[修饰符]  属性类型  属性名 [= 默认值] ;

类的方法

方法则用于定义该类或该类的实例的行为特征和功能实现。方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成;面向对象中,整个程序的基本单位是类,方法是从属于对象

方法定义格式和之前讲的方法相同,其实就是一个东西

[修饰符]  方法返回值类型  方法名(形参列表) {
   
方法体;
}

类的方法的调用:如果调用的是自己方法,直接调用 ; 如果调用的是别人(别的类)的方法,需要加前缀(引用,类名)。

对象的创建和使用

必须使用 new 关键字创建对象。
Person person= new Person ();
使用对象(引用) . 成员变量来引用对象的成员变量。
person.age;
使用对象(引用) . 方法名(参数列表)来调用对象的方法。
person. setAge(23);
同一类的每个对象有不同的成员变量存储空间。
同一类的每个对象共享该类的方法。

构造器(constructor)

构造器用于构造该类的实例

Java通过new关键字来调用构造器,从而返回该类的实例。

构造器是一种特殊的方法:
格式如下

[修饰符] 类名(形参列表){
   
	//n条语句
}

注意

  • 通过new关键字调用。
  • 构造器虽然有返回值,但是不能定义返回类型(返回值的类型肯定是本类),不能在构造器里使用带数据的return语句。
  • 如果我们没有定义构造器,则编译代码时(java–>class)会自动定义一个无参的构造函数。如果已定义则编译器不会添加!
  • 构造器的方法名必须和类名一致!

构造函数不是没有返回值吗?为什么不能用void?

规定。事实上,构造函数是有返回值的就是构造的对象。如此写法只是针对构造函数的特殊规定。

内存分析

  1. 每个线程私有,不能实现线程间的共享!
  2. 局部变量放置于栈中。
  3. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!

  1. 放置new出来的对象!
  2. 堆是一个不连续的内存空间,分配灵活,速度慢!

方法区

  1. 被所有线程共享!
  2. 用来存放程序中永远是不变或唯一的内容。(类代码信息、静态变量、字符串常量

this关键字

基本含义:当前对象

普通方法中,this总是指向调用该方法的对象。

构造方法中,this总是指向正要初始化的对象。

this最常的用法

  • 让类中的一个方法,访问该类的另一个方法(this.方法名())或属性(this.属性名)。访问属性更常用,用来区分同名的形参和属性。
  • 使用this关键字调用重载构造方法。避免写相同的初始化代码,只能在构造方法中用,并且必须位于构造方法的第一句。

static 关键字

static属性: 属性被所有对象共享; 这个属性先于对象存在的

static 方法:这个方法先于对象存在

static 表示静态的, 所有对象共用的(所有对象都看到一份,而且只要其中任何一个对象对其进行修改,其他所有对象都会看到这个变化),所有的静态内容都是跟随类存在,在对象还没有的时候就已经存在。

在类中,用static声明的成员变量为静态成员变量

  • 它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化
  • 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享
  • 可以使用” 对象.类属性 ”来调用。不过,一般都是用“ 类名.类属性 ()”。

用static声明的方法为静态方法

  • 不需要对象,就可以调用( 类名.方法名() )
  • 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。也不可以出现this关键字

可以通过对象引用或类名(不需要实例化)访问静态成员。

静态初始化块

经常用来初始化类,加载类信息时执行!

如果希望加载后,对整个类进行某些初始化操作,可以使用static初始化块。

  • 是在类初始化时执行,不是在创建对象时执行。
  • 静态初始化块中不能访问非static成员。

执行顺序:上溯到Object类,先执行Object的静态初始化块,再向下执行子类的静态初始化块,直到我们的类的静态初始化块为止。(到继承再看)

package

为什么需要package?
为了解决类之间的重名问题。

为了便于管理类:合适的类位于合适的包!

package怎么用?
通常是类的第一句非注释性语句。
包名:域名倒着写即可,再加上模块名,并与内部管理类。

其实内部实现就是靠目录结构来做到的。

特别注意:写项目时都要加包,不要使用默认包

JDK中的主要包

java.lang -包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。

java.net -包含执行与网络相关的操作的类。

java.io -包含能提供多种输入/输出功能的类。

java.util -包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

import

为什么需要import?

如果不适用import,我们如果用到其他包的类时,只能这么写:java.util.Date,代码量太大,不利于编写和维护。通过import可以导入其他包下面的类,从而可以在本类中直接通过类名来调用。

import怎么使用?

import java.util.Date;
import java.util.*; //导入该包下所有的类。会降低编译速度,但不会降低运行速度。

注意要点

  • java会默认导入 java.lang 包下所有的类,因此这些类我们可以直接使用。
  • 如果导入两个同名的类,只能用包名+类名来显示调用相关类:
    java.util.Date date = new java.util.Date();

静态导入(了解)

static import 静态导入(JDK 1.5后增加):

静态导入的作用:用于导入指定类的静态属性

如何使用:

import static java.lang.Math.*; //导入Math类的所有静态属性
import static java.lang.Math.PI; //导入Math类的PI属性

然后,我们可以在程序中直接使用: System.out.println(PI);

上面两种导入方式都是为了便于编写代码,提高可维护性。

封装(encapsulation)

封装的作用

我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要碰碰显像管吗?

我要开车,….
制造厂家为了方便我们使用电视,方便我们开车,把复杂的内部细节全部封装起来,只给我们暴露简单的接口,比如:电源开关、比如:油门。具体怎么内部实现的,我们不需要操心。

需要让用户知道的暴露出来,不需要让用户了解的全部隐藏起来。这就是封装。

白话:该露的露,该藏的藏
专业:我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。

编程中封装的具体意义

便于调用者调用。

良好的封装,便于修改内部代码,提高可维护性。

良好的封装,可进行数据完整性检测,保证数据的有效性。

访问控制符

关键字 同一个类 同一个包中 子类 所有类
private
default
protected
public
  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值