Java 面向对象编程(基础)
Java 面向对象编程(基础)
sinarcsinx面向对象是一种开发软件的方法,使分析、设计和实现一个系统的方法尽可能接近人们认识一个系统的方法。包括三个方面:面向对象分析、面向对象设计、面向对象程序设计。
Java 语言是纯面向对象的语言。其所有数据类型都有相应的类,程序可以完全基于对象编写。
类与对象(OOP)
类 就是数据类型。可以是
int
也可以是人类
对象 就是其中具体的实例。可以是
100
从 类 到 对象,可以称为 创建一个对象,也可以说 实例化一个对象,或者 把对象实例化
- 类 是抽象的、概念的,代表一类事物
- 对象 是具体的、实际的,代表一个个具体事物
- 类 是 对象 的模板,对象 是 类 的一个个体,对应一个实例
下面,我们定义了一个类 Cat
并创建了一些 对象 cat1
cat2
:
1 | public class Code6_1{ |
属性/成员变量
从概念或叫法上看:成员变量 = 属性 = field(字段)
1 | class Cat{ |
其中,String name;
就是一个成员变量(属性)。
属性可以是基本数据类型,也可以是引用数据类型。
- 属性的定义语法同变量。
访问修饰符 属性类型 属性名
- 访问修饰符:控制属性的访问范围。有四种:
publie
protected
默认(空)
private
- 访问修饰符:控制属性的访问范围。有四种:
- 属性的定义类型可以为任意类型,包含 基本类型 或 引用类型
- 属性如果不赋值,有默认值。规则同 Java 数组、排序和查找
创建对象
先声明再创建:
1
2Cat cat1; //声明对象cat1
cat1 = new Cat(); //创建对象直接创建:
1
Cat cat2 = new Cat();
注意事项:
声明对象的场合,只是在内存中建立了一个引用。此时,该地址引用不指向任何内存空间。
对象的引用,也被称为对象的句柄。
使用 new 运算符创建对象实例时,会为对象分配空间,就会调用类的构造方法。那之后,会将该段内存的首地址赋给刚才建立的引用。
访问对象
基本语法:对象名.属性名
1 | System.out.println(cat1.name); |
在Java中,任何对象变量的值都是对储存在另外一个地方的某个对象的引用。
类与对象的内存访问机制
栈:一般存放基本数据类型(局部变量)
堆:存放对象(如
Cat cat1 = new Cat()
,是在这里开辟的空间)方法区:常量池(常量,比如字符串),类加载信息
- 创建对象时,先加载 类 信息,然后在 堆 中分配空间,栈 中的对象名被赋予指向那个空间的地址。
- 之后进行指定初始化。该对象的 属性 中,是 基本数据类型 的直接记录在 堆 中;是 字符串 的记录一个地址,该地址指向 方法区,那里的常量池有该字符串。
成员方法
在某些情况下,我们需要定义成员方法。比如 Cat
除了有属性(name
age
)外,还可以有一些行为比如玩耍。
1 | 修饰符 返回数据类型 方法名(形参列表){ |
方法名必须是一个合法的标识符
返回类型即返回值的类型。如果方法没有返回值,应声明为 void
修饰符段可以有几个不同的修饰符。
1
2
3public static strictfp final void method() {
System.out.println("哎咿呀~ 哎咿呀~");
}其中 public(访问修饰符)、static(static 关键字)、final(final 关键字)
—— 访问修饰符见 Java 面向对象编程(中级)
—— static 关键字见 Java 面向对象编程(高级)
—— final 关键字见 Java 面向对象编程(高级)
—— strictfp 关键字见 Java 常用类
参数列表是传递给方法的参数表。各个元素间以
,
分隔。每个元素由一个类型和一个标识符表示的参数组成。特别地,
参数类型... 标识符
这样的参数被称为可变参数—— 可变参数见 Java 面向对象编程(基础)
方法体是实际要执行的代码块。方法体一般用 return 作为方法的结束。
使用 成员方法,能提高代码的复用性。而且能把实现的细节封装起来,供其他用户调用。
1 | class Cat{ |
- 方法写好后,不去调用就不会输出
- 先创建对象,然后调用方法即可
下面,展示一个含有成员方法的代码:
1 | public class Code6_2{ |
方法的调用机制
以前文代码为例:
1 | ... |
- 当程序执行到方法时,在 栈 中开辟一个新的 栈空间。该空间里储存
n1 = 15
n2 = 135
,之后计算并储存结果res = 150
- 当方法执行完毕,或执行到
return
语句时,就会返回 - 把 新栈空间 中的
res = 150
返回 main栈 中调用方法的地方 - 返回后,继续执行该方法的后续代码
使用细节
访问修饰符:作用是控制方法的使用范围。
- 不写(默认访问控制范围)
- public:公共
- protected:受保护
- private:私有
—— 访问修饰符见 Java 面向对象编程(中级)
返回数据类型:
- 一个方法最多有一个返回值。要返回多个结果可以使用 数组。
- 返回类型为任意类型。包括 基本数据类型 和 引用数据类型。
- 如果方法要求有返回数据类型,则方法体中最后的执行语句必为
return 值
,且返回类型必须和 return 的值一致。 - 如果 返回数据类型 为
void
,则可以不写return
语句
方法名:
- 遵循驼峰命名法,最好见名知意,表达出该功能的意思。
参数列表(形参列表):
- 一个方法可以有 0 个参数,也可以有多个参数。参数间用
,
间隔。 - 参数类型可以为任意类型,包含 基本类型 和 引用类型。
- 调用带参数的方法时,一定对应着 参数列表 传入 相同类型 或 兼容类型 的参数。
- 方法定义时的参数称为 形式参数 ,简称 形参;方法调用时的参数(传入的参数)称为 实际参数,简称 实参。实参 与 形参 的类型、个数、顺序必须一致。
- 一个方法可以有 0 个参数,也可以有多个参数。参数间用
方法体:
- 写完成功能的具体语句。方法中不能再定义方法。即:方法不能嵌套定义。
调用细节:
同一个类中的方法调用,可以直接调用。
跨类的方法调用,需要创建新对象,然后再调用方法。
1 | class C1{ |
成员方法传参机制
Java 语言对对象采用的是 值传递,方法得到的总是那个传入对象的副本。
方法不能修改基本数据类型的参数。基本数据类型传递的是一个值,形参不影响实参。
方法可以改变对象参数的状态。
引用类型传递的是一个地址,形参和实参指向一处,两者总会相关。
但改变那个形参地址指向的场合,实参的指向不会改变。
方法递归调用
递归:即方法自己调用自己,每次调用时传入不同变量。递归有助于编程者解决复杂问题,同时可以让代码变得简洁。
下面,示范一个斐波那契数列方法
1 | class T{ |
使用细节
- 执行一个方法时,就创建一个新的受保护的独立 栈空间。
- 方法的局部变量是独立的,不会相互影响。
- 如果方法中使用的是引用变量,就会共享数据。因为 6 面向对象编程(基础)
- 递归必须向退出递归的条件逼近,否则就是无限递归,会提示
StackOverflowError
“死龟” - 当一个方法执行完毕,或遇到
return
就会返回。遵守谁调用就返回给谁。同时当方法执行完毕或返回时,该方法也执行完毕。
方法重载
方法重载(Overload):Java 中允许同一类中,多个同名方法的存在,但要求 形参列表 不一致。
这样,减轻了起名和记名的麻烦。
使用细节:
- 方法名:必须相同
- 形参列表:必须不同(参数的类型、个数、顺序,这其中至少一个不同)
- 返回值:无要求
签名:
由于重载的存在,要完整的描述一个方法,要指定方法名及参数类型。这叫做方法的签名。
如:
1 | public void act() {} |
两个方法的签名分别是:act()
和 act(int n)
可变参数
Java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
语法:访问修饰符 返回类型 方法名(数据类型... 形参名){代码块;}
1 | public void m(int... n){ |
使用细节
可变参数 的实参可以是 0 个,也可以是 任意多 个。
可变参数 的实参可以是数组
可变参数 本质就是数组
因此,出现:
1
2public void met(int... n){ //这个方法与下面的方法不能构成重载
}的场合,不能有方法:
1
2public void met(int[] n){ //这个方法与上面的方法不能构成重载
}可变参数 和 普通参数 可以一起放在形参列表,但必须保证 可变参数 在最后
1
public void m(double dou, int... n) {}
一个形参列表最多出现 一个 可变参数。
作用域
- 在 Java 编程中,主要的变量就是 属性(成员变量)和 局部变量。
- 我们说的 局部变量 一般是指在成员方法中定义的变量。
- 作用域的分类
- 全局变量:也就是 属性,作用域为整个类体
- 局部变量:除了属性外的其他变量。作用域为定义它的代码块中
- 全局变量(属性)可以不赋值直接使用,那个场合有默认值。局部变量必须赋值使用
使用细节
属性 和 局部变量 可以重名,访问时遵循就近原则
在同一作用域中,两个局部变量不能重名
属性 的生命周期较长。其伴随对象的创建而创建,伴随对象的销毁而销毁。
局部变量 生命周期较短。其伴随代码块的执行而创建,伴随代码块的结束而销毁。
全局变量/属性 可以被本类使用,也可以被其他类(通过对象)使用。
局部变量 只能被本类的对应方法中调用
全局变量/属性 可以加 修饰符
局部变量 不能加 修饰符
构造方法、构造器
构造方法又叫构造器(constructor),是类的一种特殊的方法。它的主要作用是完成对新对象的初始化。
语法:[修饰符] 方法名(形参列表){方法体}
- 构造器的修饰符可以是默认。也可以是别的
- 参数列表 规则同 成员方法
以下示范一个构造器:
1 | class T{ |
使用细节
构造器本质也是方法。所以,可以 构造器重载。
构造器名 和 类名 相同
构造器无返回值
构造器是完成对象的初始化,而不是创建
创建对象时,系统自动调用构造器
如果程序员没有定义构造器,系统会自动给类生成一个无参构造器(默认构造器)
一旦定义了自己的构造器,就不能用无参构造器了。除非显式的定义一个无参构造器
流程分析
1 | Person p1 = new Person("Amy", 10); |
加载 类信息(方法区)
在 堆 中开辟空间(地址)
完成对象初始化
首先默认初始化。
age = 0; name = null
之后显式初始化。
age = 20; name = null
其中,显式初始化和代码块初始化按编写的先后顺序依次进行。
之后构造器的初始化。
age = 10; name = "Amy"
把对象在 堆 中的 地址,返回给
p1
this 关键字
JVM 会给每个对象分配 this 代表当前对象。
相当于在 堆 中,this 指向自己(对象)
在类定义的方法中,Java 会自动用 this 关键字把所有变量和方法引用结合在一起。
遇到有同名的局部变量的场合,需要程序员加入 this 关键字进行区分。不加入 this 关键字的场合,Java 遵循就近原则。
1 | class Example{ |
上面这个类的 act()
方法实际有 2 个参数。对其调用:
1 | Example e = new Exmaple(); |
可见,出现在方法名前的参数 e
,以及出现在方法名后的括号中的参数 100
出现在方法名前的参数被称为 隐式参数(也称为 方法调用的 目标 或 接收者)
出现在方法名后的参数被称为 显式参数,就是所谓的实参
在每一个方法中,用 this 指代隐式参数。
1 | public void act(int n) { |
此时,再以相同方式调用方法:
1 | e.act(100); // <———— 相当于 e.n = 100; |
使用方法
this
关键字可以用来访问本类的属性、方法、构造器this
用于区分当前类的 属性 和 局部变量访问本类中成员方法的语法:
this.方法名
访问构造器的语法:
this(参数列表);
注意:只能在构造器中访问另一个构造器。而且,如果有这个语法,必须放置在第一条语句。
this
不能在类定义的 外部 使用,只能在类定义的 方法中 使用
附录
迷宫游戏代码
1 | /** |
八皇后代码
1 | import java.util.Scanner; |