第4章 对象与类

概述

面向对象程序设计(OOP)是当今直流的程序设计范型。
面向对象(OO)是一种以对象为中心的编程思想.
面向过程 (OP)是一种以过程为中心的编程思想。

使用面向对象编程思想开发系统,在现代开发中会将面向对象贯穿整个过程,一般包括:
OOA/OOD/OOP:
① OOA:面向对象分析(Object-Oriented Analysis)
② OOD:面向对象设计(Object-Oriented Design)
③ OOP:面向对象编程(Object-Oriented Programming)

面向对象具有三大特征
① 封装(Encapsulation)
② 继承(Inheritance)
③ 多态(Polymorphism)

类:
构造对象的模板
由类构造对象的过程——创建类的实例(特定实例字段值的集合——对象当前的状态)

将数据(实例字段)与行为(方法)组合在一个包中,并对对象使用者隐藏具体的实现过程——封装
实现封装的关键:绝对不能让类中的方法直接访问其他类的实例字段,程序只能通过对象的方法与对象数据进行交互。

通过拓展其他类来构建新类,拓展后的类具有被扩展的类的全部属性和方法,还可以添加仅适用于新类的新方法和数据字段——继承

对象:
三大特性:行为(方法),状态(实例数据字段),标识(区别对象的唯一标识)

类之间的关系:

  • 依赖:“uses-a”:一个类的方法使用或操纵另一个类的对象
  • 聚合:“has-a”:一个类的对象包含另一个类的对象
  • 继承:“is-a”:一个类由另一个类继承而来

java 虚拟机内存管理

(by 动力节点)
java 虚拟机是如何管理它的内存
在这里插入图片描述① 程序计数器:

  1. 概念:可以看做当前线程所执行的字节码的行号指示器。
  2. 特点:线程私有的内存

② java 虚拟机栈(重点):

  1. 概念:描述的是 java 方法执行的内存模型。(每个方法在执行的时候会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至完成的过程,就对应一个栈帧从入栈到出栈的过程。)
  2. 特点:线程私有,生命周期和线程相同。这个区域会出现两种异常 :
    StackOverflowError 异常: 若线程请求的深度大于虚拟机所允的深度 。
    OutOfMemoryError 异常:若虚拟机可以动态扩展,如果扩展是无法申请到足够的内存。

③ 本地方法栈:

  1. 概念:它与虚拟机栈所发挥的作用是相似的,区别是 java 虚拟机栈为执行 java方法服务,而本地方法栈是为本地方法服务。
  2. 特点:线程私有,也会抛出两类异常: StackOverflowError 和 OutOfMemoryError。

④ java 堆(重点):

  1. 概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
  2. 特点:线程共享,存放的是对象实例(所有的对象实例和数组), GC 管理的主要区域。可以处于物理上不连续的内存空间。

⑤ 方法区(重点):

  1. 概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代
    码等数据。
  2. 特点:线程共享的区域,抛出异常 OutOfMemory 异常:当方法区无法满足内存分配需求的时候。

简化理解:
java 虚拟机有三块主要的内存空间,分别是“虚拟机栈(后面简称栈)”、“方法区”、“堆区”,方法区存储类的信息,栈中存储方法执行时的栈帧以及局部变量,堆区中主要存储 new 出来的对象,以及对象内部的实例变量。其中垃圾回收器主要针对的是堆内存,方法区中最先有数据,因为程序执行之前会先进行类加载。栈内存活动最频繁,因为方法不断的执行并结束,不断的进行压栈弹栈操作。如图示:
在这里插入图片描述

预定义类

Date类(时间点),LocalDate类(日历表示法表示日期)
在这里插入图片描述

对象变量:不实际包含一个对象,只引用对象(存在于栈空间)

可以包含一个对象的引用,或者包含一个特殊值null(表示没有引用任何对象),但不可以对null值应用方法会产生NullPointerException异常。

对象的值存储在另外一个地方(堆空间),只对外提供一个地址用于引用,(当一个对象包含另一个对象变量时,它只是包含了另一个堆对象的指针)没有对象变量引用(没有任何指向)的对象,会被Java的垃圾回收机制自动回收,不会造成内存浪费。
具体理解可见: java 虚拟机内存管理

更改器方法:调用方法,对象状态会改变
访问器方法:只访问对象而不修改对象的方法

自定义类:

类中的字段

实例字段

普通封装起来的数据字段用private修饰即可
(关键字private确保只有类自身的方法可以访问这些实例字段)

实例字段的初始化:构造函数
但当实例变量没有手动赋值(空构造且未赋初始值),在创建对象的时候,即在 new对象 的时候,系统会对实例变量默认赋值:
在这里插入图片描述

final实例字段
此字段必须在构造对象时初始化,即必须保证每一个构造器执行之后,此字段值已经设置,并且以后不能再修改这个字段。
final关键字只表示存储在该字段值中的对象引用不会再指向另一个不同的对象,但指向的该对象的值可以更改。
eg: private final String name;

static静态字段
定义为static的字段,每个类只有一个这样的字段
非静态的实例字段,每个对象创建时都会创建一份,但静态实例字段,所有该类对象共享一个该实例字段,只属于类,不属于任一对象。
静态常量(static final)
eg: private static final double PI=3.14159;
可以使用(类名.PI)的方式访问

this:

this 可以看做一个变量,它是一个引用,存储在 Java 虚拟机堆内存的对象内部, this 这个引用保存了当前对象的内存地址指向自身,任何一个堆内存的 java 对象都有一个 this。
this 指向“当前对象”,也可以说 this 代表“当前对象”。
this 可以使用在实例方法中以及构造方法中,语法格式分别为“this.”和“this(…)”。 this 不能出现在带有 static 的方法当中。
大部分情况下 this 都是可以省略的,只有当在实例方法中区分局部变量和实例变量的时候不能省略。
this 使用在构造方法第一行(只能出现在第一行),通过当前构造方法调用本类当中其它的构造方法,其目的是为了代码复用。调用时的语法格式是: this(实际参数列表)

final :

final 表示不可改变的含义

  • 采用 final 修饰的类不能被继承
  • 采用 final 修饰的方法不能被覆盖
  • 采用 final 修饰的变量不能被修改
  • final 修饰的变量必须显示初始化
  • 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
  • 构造方法不能被 final 修饰
  • 会影响 JAVA类的初始化:final 定义的静态常量调用时不会执行 java 的类初始化方法,也就是说不会执行 static 代码块等相关语句.

static:

static 是 java 语言中的关键字,表示“静态的”,它可以用来修饰变量、方法、代码块等,修饰的变量叫做静态变量,修饰的方法叫做静态方法,修饰的代码块叫做静态代码块。在 java语言中凡是用 static 修饰的都是类相关的,不需要创建对象,直接通过“类名”即可访问,即使用“引用”去访问,在运行的时候也和堆内存当中的对象无关。

静态变量

java 中的变量包括:局部变量和成员变量,在方法体中声明的变量为局部变量,有效范围很小,只能在方法体中访问,方法结束之后局部变量内存就释放了,在内存方面局部变量存储在栈当中。在类体中定义的变量为成员变量,而成员变量又包括实例变量和静态变量,当成员变量声明时使用了 static 关键字,那么这种变量称为静态变量,没有使用 static 关键字称为实例变量,实例变量是对象级别的,每个对象的实例变量值可能不同,所以实例变量必须先创建对象,通过“引用”去访问,而静态变量访问时不需要创建对象,直接通过“类名”访问。实例变量存储在堆内存当中,静态变量存储在方法区当中。实例变量在构造方法执行过程中初始化,静态变量在类加载时初始化。

所有实例相关的,包括实例变量和实例方法,必须先创建对象,然后通过“引用”的方式去访问,如果空引用访问实例相关的成员,必然会出现空指针异常所有静态相关的,包括静态变量和静态方法,直接使用“类名”去访问。虽然静态相关的成员也能使用“引用”去访问,但这种方式并不被主张。

静态代码块:

	static{
java 语句;
}

静态代码块在类加载时执行,并且只执行一次。
例如我们要在类加载的时候解析某个文件,并且要求该文件只解析一次,那么此时就可以把解析该文件的代码写到静态代码块当中。
一个类当中可以编写多个静态代码块,并且静态代码块遵循自上而下的顺序依次执行,所以有的时候放在类体当中的代码是有执行顺序的(大部分情况下类体当中的代码没有顺序要求,方法体当中的代码是有顺序要求的,方法体当中的代码必须遵守自上而下的顺序依次逐行执行),另外静态代码块当中的代码在 main 方法执行之前执行,这是因为静态代码块在类加载时执行,并且只执行一次

静态方法(类方法):

从设计角度:方法描述类的行为动作,当某个动作在触发的时候需要对象的参与,这个方法应该定义为实例方法。
从代码角度:当方法体中需要直接访问当前对象的实例变量或者实例方法的时候,该方法必须定义为实例方法,因为只有实例方法中才有 this,静态方法中不存在 this。
静态方法不必创建对象即可调用,不能访问对象状态(非静态成员变量及方法),可以访问静态字段。其他方法可以访问静态方法。

使用静态方法的两种情况:

  • 方法不需要访问对象状态,即它所需要的所有参数都通过显式参数提供
  • 方法只需要访问类的静态字段

main方法:
main方法不对任何对象进行操作,在程序启动时还没有任何对象,由静态的main方法执行构造程序所需要的对象。

方法:

参数:

  • 隐式参数:出现在方法名之前的类类型对象(方法调用的目标/接收者)显式地列在方法声明中。
  • 显式参数:位于方法名后括号中的数值,用关键字this指示。

方法调用时参数的传递问题:

Java使用传值调用:方法接收的是调用者提供的值(即方法得到的是所有参数值的一个副本)
(c++中既有按值调用,也有按引用调用,方法可以修改按引用传递的变量的,不能修改按值传递的变量的值)

方法参数按类型分类:

  • 基本数据类型(不能修改方法参数的值)
  • 对象引用(虽然是按值调用,但方法可以得到一个与与原对象引用指向同一个对象的副本,二者引用同一个对象,因此该种引用也可以实现改变对象参数的状态)

在调用的时候参数传递给方法,这个过程就是赋值的过程,参数传递和“赋值规则”完全相同。
“赋值”运算的时候实际上和变量的数据类型无关,无论是基本数据类型还是引用数据类型,一律都是将变量中保存的“值”复制一份,然后将复制的这个“值”赋上去。他们的区别在于,如果是基本数据类型则和堆内存当中的对象无关,如果是引用数据类型由于传递的这个值是 java 对象的内存地址,所以会导致两个引用指向同一个堆内存中的 java 对象,通过任何一个引用去访问堆内存当中的对象,此对象内存都会受到影响。

对象构造:

构造方法是类中特殊的方法,通过调用构造方法来完成对象的创建,以及对象属性的初始化操作。

一个类当中可以定义多个构造方法,构造方法是支持重载机制的,具体调用哪个构造方法,那要看调用的时候传递的实际参数列表符合哪个构造方法了。(编译器用各个方法首部的参数类型与特定方法调用中所使用的值类型进行匹配,来选出正确的方法,此过程称为重载解析

构造方法语法结构:
[修饰符列表] 构造方法名(形式参数列表){
构造方法体;
}
调用构造方法语法格式: new 构造方法名(实际参数列表);

特点:

  • 与类同名
  • 可以有一个以上构造器
  • 可以有任意多个参数
  • 无返回值
  • 总是伴随着new操作符一起调用

构造方法虽然在返回值类型方面不写任何类型,但它执行结束之后实际上会返回该对象在堆内存当中的内存地址,这个时候可以定义变量接收对象的内存地址。
即 Data a=new Data(x,y,z);

默认字段初始化:
构造器中没有显式地为字段设置初值,即会被自动地赋为默认值。见实例字段部分。

显式字段初始化:
在类定义中即可直接为实例字段设置一个有意义的初值。在执行构造器之前先完成赋值操作。

无参构造:
无参构造器中,为对象状态设置为适当的默认值。

当一个类没有显示的定义任何构造方法的时候,系统默认提供无参数构造方法,当显示的定义构造方法之后,系统则不再提供无参数构造方法。无参数构造方法又叫做缺省构造器,或者默认构造方法。

如果类中提供了至少一个构造器,但是没有提供无参数的构造器,那么构造对象时如果不提供参数就是不合法的。

含参构造:
this指示隐式参数即所构造的对象,按照参数列表给定参数,分别赋值。
this还可以调用同一个类的另一个构造器
this(x,y,z)//必须在构造函数第一行

初始化块:
用大括号括起来的一段代码(建议放在字段定义之后):只要构造这个类的对象,这些代码就会被执行。首先运行初始化块,才运行构造器的主体部分。(不常见)
静态初始化块:初始化静态字段

初始化执行过程:
1、在需要时,虚拟机定位class文件,载入class文件,执行静态初始化(类变量,静态代码块)
2.使用new创建对象时,在堆上为对象分配空间
3.这块存储空间被清零,基本数据类型成员变量初始化为默认值,引用设置为null
4.按照类定义中出现顺序依次执行声明中的赋值和初始化块
5.执行构造方法

使用null引用
java.lang.NullPointerException 被称为空指针异常。
一个对象变量会包含一个对象的引用(引用就是一个变量,只不过该变量中存储的是 java 对象的内存地址),或者包含一个特殊值null(表示没有引用任何对象)
对null值应用一个方法,会产生空指针异常。

获取或设置实例字段的值:

  • 一个私有的数据字段(类的封装性)
  • 一个公共的字段访问器方法 (get方法){不可编写返回可变对象的引用的访问器方法;若需要返回可变对象的引用,应当先对其进行clone,对象克隆是指存放在另一个新位置上的对象副本,关于clone见第六章}
  • 一个公共的字段更改器方法(set方法)

实例方法:
实例方法必须先创建对象,通过引用去调用,

静态方法:
见static部分

Java允许使用包(package)将类组织在一个集合中。

包名

使用包的原因:确保类名的唯一性。
为了保证包名的绝对唯一性,通常用一个因特网域名以逆序的形式作为包名,然后对于不同的工程使用不同的子包。

类的导入

一个类可以使用所属包中的所有类,以及其他包中的公共类。
访问另一个包中的公共类:
1.使用完全限定名:包名+类名
2.使用import语句,导入包中的类,使用时即不必写出类的全名
(位于源文件顶部,package语句后)
PS:导入的多个包存在同名类,在使用类时需要完整包名。

还可以导入静态方法和静态字段
eg: import static java.lang.System.*;

在包中添加类

要想将类放入包中,就必须将包的名字放在源文件的开头,即放在定义这个包中各个类的代码之前。
eg: package com.pat.java;
若没有在源文件中防止package语句,源文件中的类就属于无名包,没有包名。
PS:编译器在编译源文件时不检查目录结构,即使包名与目录结构不对应也不会发生编译错误,但是无法正确运行,因为如果包与目录不匹配,虚拟机无法找到对应类进行运行。

类路径

类存储在文件系统的子目录中,其路径必须与包名匹配。
此外,类文件也可以存储在JAR(Java归档)文件中。在一个JAR文件中可以包含多个压缩形式的类文件和子目录。

文档注释:

javadoc 可以由源文件生成HTML文档。
添加特殊定界符/**开始的注释,在修改源代码的同时重新运行javadoc即可轻松保持两者一致性。

/** … */
类注释应该放在import语句之后,类定义之前
方法注释紧靠方法定义之前
成员变量注释在其定义之前

javadoc 从以下几项中抽取信息:

  • 模块
  • 公共类与接口
  • 公共的和受保护的字段
  • 公共的和受保护的构造器及方法

每个文档注释包含标记以及之后紧跟着的自由格式文本。标记以@开始,如@since,@param(参数)
在这里插入图片描述

自由格式文本的第一句应该是一个概要性的句子,javadoc 工具自动将这些句子抽取出来生成概要页。(可以使用HTML修饰符)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值