9、面向对象(基础)
一、类与对象
1、概述
-
为什么需要类与对象?
对某些问题,,单独地定义变量解决,或者使用数组来解决,会不利于数据的管理,且效率低下,由此,Java设计者引入类与对象(OOP),其根本原因在于现有技术不能完美解决新的需求
-
什么是类与对象?
<对象>:现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,面向对象思想,是人类最自然的一种思考方式,它将所有预处理的问题抽象成对象。人类解决问题的方式,总是将复杂的事物简单化,思考这些对象,都是由哪些部分组成的,而往往将其划分为两个部分即静态部分和动态部分
graph LR 类 --> 静态部分 类 --> 动态部分 静态部分 --> 属性 动态部分 --> 行为 属性 --> 共同定义抽象出一个对象 行为 --> 共同定义抽象出一个对象通过属性和行为即可定义出一个具体的对象
<类>:类就是对同一类事物的统称
-
怎么定义类和对象?
//类的定义
权限修饰符 class 类名 {
//属性
//方法
}
例子:
class Person {
String name;
int age;
}
//对象的定义
类名 对象名 = new 类名{};
例子:
Person teacher = new Person{"毛主席", 24};
- 类和对象的区别?
- 类是抽象的,概念的,代表一类事物;对象是实际的,具体的,代表一个具体的事物
- 类是对象的模板,对象是类的一个个实例
2、属性/成员变量/field(字段)
属性可以是基本数据类型,也可以是引用类型(数组、类、接口)
(1)属性的定义
访问修饰符 属性类型 属性名;
属性如果不赋值,有默认值,与数组一样
(2)Java创建对象的流程分析
Person P = new Person;
p.name = "tony";
p.age = 10;
- 先加载类信息在方法区(属性及方法信息仅加载一次)
- 在堆中分配空间,默认初始化,将地址赋值给P
- 给对象赋值
3、成员方法
成员方法对应于类对象的行为
(1)成员方法
-
语法
权限修饰符 返回值类型 方法名(参数类型 参数名) { 方法体; return 返回值; }
-
权限(访问)修饰符
访问级别 | 访问修饰控制符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public:对外公开 | ✔ | ✔ | ✔ | ✔ |
受保护 | protected:对子类和同一个包中的类公开 | ✔ | ✔ | ✔ | ❌ |
默认 | 无 | ✔ | ✔ | ❌ | ❌ |
私有 | private:不对外公开,类内部使用 | ✔ | ❌ | ❌ | ❌ |
(2)方法的调用机制
(3)返回数据类型
- 一个方法最多有一个返回值,若有多个返回值可以返回数组
- 返回类型可以为任意类型(基本类型和引用类型)
- 如果方法要求有返回数据类型,方法的最后执行语句为return,且类型一致
- 如果返回值为void,可以无return或只有return
(4)形参列表
- 一个方法可以有0个形参,也可以有多个形参,中间用”,“隔开
- 形参可以为任意类型
- 形式参数的数据类型必须于传入的数据一致——包括类型、个数、顺序
- 方法定义时的参数叫形参,方法调用时为实参
(5)方法的调用
- 同一个类中,方法可以直接调用
方法名(参数);
- 跨类中的A类对象调用B类方法,须通过对象名调用
对象名.方法名(参数);
(6)方法的传参机制
- 传递基本数据类型时传递的是值(值拷贝),形参的任何改变不影响实参
- 传递引用数据类型时,传递的是地址,形参的改变会影响实参
(7)方法的递归调用
本质上是流程控制,即一层执行完返回上一层
- 没执行一个方法就创建一个新的空间
- 方法的局部变量是独立的,不会相互影响
- 如果方法传递引用类的成员变量,会使其他层公用该空间
- 递归必须向退出递归的条件逼近,否则会出现无限递归——即”死龟”
- 当一个方法执行完毕,或执行return退出,就会返回,谁调用,结果就返回给谁
递归的回溯现象(见10.递归的回溯现象与八皇后问题)
4、方法重载(overload)
(1)Java中允许同一个类中,多个同名方法的存在,但要球形参列表不一致
- 好处
- 起名的麻烦减少了
- 记名的麻烦减少了
(2)重载的使用
- 方法名相同
- 形参列表必须不同
- 返回类型无要求
5、可变参数
Java允许将同一个类中多个同名,同功能但参数个数不同的方法封装成一个方法,通过可变参数实现
- 语法
访问修饰符 返回类型 方法名 (数据类型 ... 形参名) {
}
- 使用:使用可变参数时,可以当作数组使用,形参名为数组名
public class VarParameter01 {
public static void main(String[] args) {
AAA m = new AAA();
System.out.println("结果为:" + m.sum(1, 5, 100));
}
}
class AAA {
// //方法重载
// public int sum(int n1, int n2) {
// return n1 + n2;
// }
// public int sum(int n1, int n2, int n3) {
// return n1 + n2 + n3;
// }
// public int sum(int n1, int n2, int n3, int n4) {
// return n1 + n2 + n3 + n4;
// }
//上面三个方法名称相同,功能相同,参数个数不同,用可变参数优化
public int sum(int... nums) {
System.out.println("接收参数的个数为:" + nums.length);
int res = 0;
for(int i = 0; i < nums.length; ++i) {
res += nums[i];
}
return res;
}
}
6、作用域
(1)变量作用域
- 全局变量:在类体中定义的变量,即成员变量/属性
- 局部变量:在方法体中定义的变量,作用域为定义其的代码块中
(2)使用细节
- 全局变量可以直接使用,有默认值(和数组一样),局部变量必须赋值
- 全局变量可以和局部变量同名,使用时就近使用
- 属性随对象的创建而创建,随对象的销毁而销毁
局部变量随方法的创建而创建,随方法的执行完毕而销毁
-
作用域范围不同
- 全局变量/属性/成员变量:可以被本类使用,被其他类使用(对象)
- 局部变量:只能在本类对应的方法中使用
-
修饰符不同
- 全局变量:可以加修饰符
- 局部变量:不可以加修饰符
7、构造器/构造方法(constructor)
-
功能:创建对象时,直接给对象属性赋值,完成对新对象的初始化
-
语法
修饰符 类名(形参列表) {
}
-
注意
-
修饰符可以为默认
-
构造器没有返回值类型的修饰
-
方法名必须和类名一样
-
形参列表和方法的规则一样
-
构造器的调用由系统完成
-
一个类可以定义多个构造器,即构造器的重载(构造器的本质是方法,构造器重载即方法的重载)
-
若是没有定义构造器,则会给类生成默认无参构造器
-
定义构造器后,将覆盖默认构造器,若要使用无参构造器,需要重载,定义默认无参构造器
-
8、this关键字
-
功能:this引用本类的一个对象,可以调用本类成员变量和成员方法
this明确引用的是类属性,而不是类方法中的局部变量
class Person {
public String name;
public int age;
//构造器
public Person(String name) {
name = name;//将局部变量赋值给局部变量
this.name = name;//将形参赋值给当前调用该方法的对象的属性
}
}
- this的使用细节
- this关键字可以用来访问本类的属性、方法、构造器
- this用于区分当前类的属性和局部变量
- 访问方法:
this.方法名(参数列表);
- 访问构造器:
this(参数列表)
——只能在一个构造器中访问另一个构造器,且必须为第一条语句 - this不能在类的定义外部使用