面向对象程序设计(简称OOP)是当今主流的程序设计范型,它已经取代了20世纪70年代的“结构化”过程化程序设计开发技术。Java是完全面向对象的,必须熟悉OOP才能够编写Java程序。面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。
~
本篇主要记录内容包括:面向对象程序设计概述、静态域与静态方法、构造器、内部类。
- 上一篇内容:Java基础:Java流程控制
- 下一篇内容:Java基础:Java面向对象
- 更多知识学习:全网最全的 Java 技术栈内容梳理(持续更新中)
文章目录
- 一、面向对象程序设计概述
- 1、类
- 2、对象
- 3、类之间的关系
- 二、静态域与静态方法
- 1、关键字static
- 2、关键字final
- 3、静态域与静态方法
- 三、构造器
- 1、构造方法的特点
- 2、 构造方法的重载
- 3、子父类中的构造方法
- 4、注意事项
- 四、内部类
- 1、内部类概念
- 2、内部类的分类
一、面向对象程序设计概述
面向对象程序设计(简称OOP)是当今主流的程序设计范型,它已经取代了20世纪70年代的“结构化”过程化程序设计开发技术。Java是完全面向对象的,必须熟悉OOP才能够编写Java程序。面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。
1、类
类(class)是构造对象的模板或蓝图。我们可以将类想象成制作小甜饼的切割机,将对象想象为小甜饼。由类构造(construct)对象的过程称为创建类的实例(instance)。
用 Java 编写的所有代码都位于某个类的内部。标准的 Java 库提供了几千个类,可以用于用户界面设计、日期、日历和网络程序设计。尽管如此,还是需要在 Java 程序中创建一些自己的类,以便描述应用程序所对应的问题域中的对象。
2、对象
要想使用 OOP,一定要清楚对象的三个主要特性:
- 对象的行为——可以对对象施加哪些操作,或可以对对象施加哪些方法?
- 对象的状态——当施加那些方法时,对象如何响应?
- 对象的标识——如何辨别具有相同行为与状态的不同对象?
同一个类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是用可调用的方法定义的。
此外,每个对象都保存着描述当前特征的信息。这就是对象的状态。对象的状态可能会随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现(如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏)。
但是,对象的状态并不能完全描述一个对象。每个对象都有一个唯一的身份(identity)。例如,在一个订单处理系统中,任何两个订单都存在着不同之处,即使所订购的货物完全相同也是如此。需要注意,作为一个类的实例,每个对象的标识永远是不同的,状态常常也存在着差异。
对象的这些关键特性在彼此之间相互影响着。例如,对象的状态影响它的行为(如果一个订单 “已送货” 或 “已付款”,就应该拒绝调用具有增删订单中条目的方法。反过来,如果订单是 “空的”,即还没有加入预订的物品,这个订单就不应该进入“已送货”状态)。
3、类之间的关系
在类之间,最常见的关系有:依赖(uses-a)、聚合(has-a)、继承(is-a)
-
依赖(dependence),即 “uses-a” 关系,是一种最明显的、最常见的关系。例如,Order类使用Account类是因为Order对象需要访问Account对象查看信用状态。但是Item类不依赖于Account类,这是因为Item对象与客户账户无关。因此,如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
应该尽可能地将相互依赖的类减至最少。如果类A不知道B的存在,它就不会关心B的任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来说,就是让类之间的耦合度最小。
-
聚合(aggregation),即 “has-a” 关系,是一种具体且易于理解的关系。例如,一个 Order 对象包含一些 Item 对象。聚合关系意味着类 A 的对象包含类B的对象。
-
继承(inheritance),即 “is-a” 关系,是一种用于表示特殊与一般关系的。例如,Rush Order 类由 Order 类继承而来。在具有特殊性的 RushOrder 类中包含了一些用于优先处理的特殊方法,以及一个计算运费的不同方法;而其他的方法,如添加商品、生成账单等都是从 Order 类继承来的。一般而言,如果类 A 扩展类 B,类 A 不但包含从类 B 继承的方法,还会拥有一些额外的功能。
二、静态域与静态方法
1、关键字static
static
关键字的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!
static
关键字的另一个比较关键的作用就是用来形成静态代码块以优化程序性能。static
块可以置于类中的任何地方,类中可以有多个static
块。在类初次被加载的时候,会按照static
块的顺序来执行每个static
块,并且只会执行一次。
static 注意事项:
- 静态内容是优先于对象存在的,只能访问静态 。静态修饰的内容存于内存的静态区;
main
方法为静态方法,仅仅为程序执行入口,它不属于任何一个对象,可以定义在任意类中;- 静态上下文中,不能引用非静态的成员变量或成员方法;
- 在静态上下文中,无法使用
this/super
关键字, 因为this/super
指代的是对象
静态变量和成员变量的区别:
-
所属不同:静态变量属于类,所以也称为为类变量,成员变量属于对象,所以也称为实例变量(对象变量);
-
内存中位置不同:静态变量存储于方法区的静态区,成员变量存储于堆内存;
-
内存出现时间不同:静态变量随着类的加载而加载,随着类的消失而消失,成员变量随着对象的创建而存在,随着对象的消失而消失;
-
调用不同:静态变量可以通过类名调用,也可以通过对象调用成员变量只能通过对象调用
2、关键字final
继承的出现提高了代码的复用性,并方便开发。但随之也有问题,有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写。可是当子类继承了这些特殊类之后,就可以对其中的方法进行重写,那怎么解决呢?
要解决上述的这些问题,需要使用到一个关键字 final
, final
的意思为最终,不可变。 final
是个修饰符,它可以用来修饰 类,类的成员,以及局部变量。
final 特点
final
修饰类不可以被继承,但是可以继承其他类;final
修饰的方法不可以被覆盖,但父类中没有被final
修饰方法,子类覆盖后可以加final
;final
修饰的变量称为常量,这些变量只能赋值一次;final
修饰的引用类型的变量值为对象地址值,地址值不能更改,但是地址内的对象属性值可以修改;final
修饰成员变量,必须在创建对象前赋值,或在多个构造方法中进行赋值,否则报错。
3、静态域与静态方法
如果将域定义为static,每个类中只有一个这样的域。而每一个对象对于所有的实例域却都有自己的一份拷贝。
Ps:在绝大多数的面向对象程序设计语言中,静态域被称为类域。术语 “static” 只是沿用了 C++ 的叫法,并无实际意义。
静态变量使用得比较少,但静态常量却使用得比较多。例如,在 Math 类中定义了一个静态常量:PI。在程序中,可以采用 Math.PI 的形式获得这个常量。如果关键字 static 被省略,PI 就变成了 Math 类的一个实例域。需要通过 Math 类的对象访问 PI,并且每一个 Math 对象都有它自己的一份 PI 拷贝。
静态方法是一种不能向对象实施操作的方法。
三、构造器
构造器也被称为构造方法,是一种特殊的方法,调用构造方法可以创建新对象。构造方法可以执行任何操作,实际应用中,构造方法一般用于初始化操作,例如初始化对象的数据域。
构造方法定义:修饰符 构造方法名 (参数列表){}
1、构造方法的特点
- 构造方法没有返回类型,包括没有
void
。,也不需要写返回值。因为它是为构建对象的,对象创建完,方法就执行结束; - 构造方法名必须和类名保持一致;
- 只有在创建对象的时候自动调用执行,而且只执行一次
2、 构造方法的重载
一个类中可以有多个构造方法,多个构造方法是以重载的形式存在的;
意义在于:可以根据不同的需求,定义不同的构造方法,灵活地初始化对象的成员变量;
构造方法是可以被 private
修饰,作用是:其他程序无法创建该类的对象
3、子父类中的构造方法
在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();
语句,它是用来访问父类中的空参数构造方法,进行父类成员的初始化操作
this()
是调用本类的构造方法,super()
是调用父类的构造方法, 且两条语句不能同时存在
4、注意事项
- 每一
class
类都必须有一个构造方法,如果自己不写,编译的时候,系统会给出默认构造方法; - 构造方法也是可以重载的;
- 在创建对象时,会调用与参数列表对应的构造方法;
- 子类的所有构造方法,直接或间接必须调用到父类构造方法; 子类的构造方法什么都不写,默认的构造方法第一行
super()
四、内部类
1、内部类概念
将类写在其他类的内部,可以写在其他类的成员位置和局部位置,这时写在其他类内部的类就称为内部类。其他类也称为外部类。在描述事物时,若一个事物内部还包含其他可能包含的事物,比如在描述汽车时,汽车中还包含这发动机,这时发动机就可以使用内部类来描述。
class 汽车 { //外部类class 发动机 { //内部类}
}
内部类的特点:①内部类提供了更好的封装,只有外部类能访问内部类;②内部类可以独立继承一个接口,不受外部类是否继承接口影响;③内部类可以直接访问外部类的成员,包括私有 private
;④健外部类要访问内部类的成员,必须创建对象;⑤在外部类中,即使内部类中用 private
修饰的成员,也可以在外部类中以 内部类 对象.成员
的方式访问;⑥private
修饰内部类,则外部类以外不能访问,只能在外部类访问。
2、内部类的分类
内部类分为 成员内部类 与 局部内部类其次还有 匿名内部类、静态内部类:
- 成员内部类:定义在外部类中的成员位置,与类中的成员变量相似,可通过
外部类.对象
进行访问,访问方式:外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
。 - 局部内部类:定义在外部类方法中的局部位置。与访问方法中的局部变量相似,可通过调用方法进行访问,访问方式: 在外部类方法中,创建内部类对象,进行访问。Ps:①局部内部类,只能在方法体中使用;②局部类不能加访问修饰符,因为它们不是类成员;③局部类可以直接访问外部类成员;④JDK8或者更高版本,从语法上讲,不要求被局部内部类所访问的局部变量,一定要加
final
,但是,如果在代码中,没有final
,只要局部内部类访问局部变量,编译器会自动给局部变量加final
。 - 匿名内部类:就是一个没有名字的局部内部类,匿名内部类是创建某个类型子类对象的快捷方式,没有名字,意味着,类不能通过名字来复用。不能复用,并不意味着不能使用,它还是可以被使用的,但是只能被使用一次(在类定义的时候使用一次)。Ps:①匿名内部类是没有访问修饰符;②匿名内部类必须继承一个类(可以是 具体类也可以是抽象类) 或者实现一个接口;③匿名内部类中不能存在任何静态成员或方法;④匿名内部类是没有构造方法,因为它没有类名;⑤匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效;⑥匿名内部类不能是抽象的,所以,它必须要实现继承的类或者实现的接口的所有抽象方法
- 静态内部类:使用
static
修饰的成员内部类我们称之为静态内部类,静态内部类的创建是不需要依赖于外部类,可以直接创建,访问特征:①对于静态内部类而言,它不能访问外部类中非静态的成员变量和成员方法;②在外部类中访问,静态内部类,和访问普通成员内部类没有任何区别;③在外部类的外部访问静态内部类,由于静态内部类,不依赖于外部类对象 :new 外部类类名.内部类类名()