目录
- 1. 面向对象
- 2. 类与对象
- 3. 面向对象在内存中的执行原理
- 4. 类和对象注意事项
- 5. this 关键字
- 6. 构造器
- 6.1 什么是构造器?
- 6.2 构造器作用
- 6.3 构造器应用场景
- 7. 封装性
- 7.1 什么是封装?
- 7.2 封装的设计规范
- 7.3 封装的书写
- 8. 实体JavaBean
正文开始
1. 面向对象
要想了解面向对象,我们首先要了解对象是什么,咱们这里讨论的可不是你的男/女朋友,而是在 Java 语言中非常重要的知识点。
我们真实生活中,有着各种各样的事物,比如一个人、一棵树、一本书等等。我们编程肯定是为了来解决现实中的问题,所以当我们把构成问题的事物数字化,得到的就是它的“对象”,对象是为了描述某个事物在解决问题中的行为。
面向对象编程,就是把解决一个问题所需要的数据和处理方法交给对象,让对象来处理问题。这样开发更符合人类的思维习惯,使得编程更加简单直观。
2. 类与对象
类是对问题共性的描述,而对象是对问题个性的描述。可以将类看作是图纸,对象就是根据图纸做出来的实物。
比如一个类描述的是“人”,包括了“姓名”、“年龄”、“性别”。而依托于这个类,创建出的一个对象“姓名:wwangxu”、”年龄:20“、“性别:男”。这就是通过“人”这张图纸(类),做出了“姓名为wwangxu”的这个实物(对象)。
类由属性和方法组成:
- 属性:该事物的特征,比如一个人的年龄、性别等。
- 方法:该事物的行为,比如吃饭、走路、睡觉等。
类必须依托对象才可以使用,而对象的各种操作都是在类中定义的。可以理解为:没法直接使用图纸来进行图纸中的操作,而必须把事物造出来才能操作,并且造出来的实物的使用方法都是在图纸中指出的。
下面我们来看一下类与对象在程序中的具体实现:
// 对象的定义格式
类名称 对象名称 = new 类名称();// 通过对象访问类中的属性
对象名称.属性//通过对象访问类中的方法
对象名称.方法(实参列表)
我们引入一个具体的例子来学习一下:
Student.java
//定义类
public class Student{//类的属性String name;int age;//类的方法public void Judgment(){if(age >= 18){System.out.println("成年了");}else{System.out.println("未成年");}}
}
test.java
public class test {public static void main(String[] args) {//定义对象1Student s1 = new Student();//通过对象访问类中的属性s1.name = "wwangxu";s1.age = 19;//通过对象访问类中的方法s1.Judgment();//定义对象2Student s2 = new Student();s2.name = "xiaoming";s2.age = 15;s2.Judgment();}
}
类的定义有以下要求:
- 类必须编写在后缀为.java的文件中;
- 一个.java文件中,可以有多个类,但public修饰的类只能有一个;
- public修饰的类名必须与其对应的.java文件的文件名相同
- 同一个包中不能有文件名重复的类
3. 面向对象在内存中的执行原理
想要更深入的了解面向对象,我们就需要学习面向对象编程的过程在内存中是如何实现的
部分 java 程序会存储在以下区域中:
- 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中。
- 堆:存放new出来的对象,注意创建出来的对象只包含各自的成员变量,不包括成员方法。
- 方法区:可以看做是一块独立于Java堆的内存空间,可存储方法。
下面我们根据此图来详细学习(图源黑马程序员课件)
-
主函数中第一句Student s1 = new Student()原理为:
- Student s1表示的是在栈内存中,创建了一个Student类型的变量,变量名为s1
- 而new Student()会在堆内存中创建一个对象,而对象中包含学生的属性名和属性值,同时系统会为这个Student对象分配一个地址值0x4f3f5b24。
- 栈内存中的变量s1存储的就是这个地址值,再次调用该变量时,就是通过这个地址来找到对象。
-
当执行s1.name=“播妞”时,其实就是通过s1找到对象的地址,再通过对象找到对象的name属性,再给对象的name属性赋值为播妞;
-
当执行s1.printTotalScore()时,先通过s1找到对象的地址,再通过对象找到类的地址,再通过方法区中的方法来执行该方法。
-
对象 s2 及其他操作同上。
4. 类和对象注意事项
- 类名的命名建议使用英文单词,并且每个单词首字母大写,使用驼峰命名法,例如:Student、Apple…
- 类中定义的变量也称为成员变量(对象的属性),类中定义的方法也成为成员方法(对象的行为)
- 成员本身存在默认值,各类型初始值如下:
类型 | 默认值 |
---|---|
byte、short、char、int、long | 0 |
float、double | 0.0 |
boolean | false |
数组、String | null |
- 一个.java文件中,可以有多个 class类,但只能有一个被 public 修饰,且该类名必须与文件名相同
- 对象与对象之间的数据不会互相影响,但当多个变量指向同一个对象时,多个变量所保存的地址是相同的,此时他们之间会相互影响
- 如果某个对象没有一个变量引用他,那么该对象无法操作,该对象会成为所谓的垃圾对象
5. this 关键字
在类与对象中,this 关键字较为常用,我们先来了解一下它的含义。
this 就是一个变量,用在成员方法中,可以拿到当前类的对象。
由上图我们可以看到,this 就是拿到我们当前类的对象,它存储的內容与定义对象的变量相同,而且哪一个对象调用成员方法中的 this,this 指向的就是哪个对象。
了解了 this 的含义,那他的使用场景有哪些呢?
当我们的成员方法需要传参时,而这时它的形参名与该类的成员变量名有冲突时,可以使用 this 来避免错误。
例如:
public class Student{// 成员变量// 代表通过所需要的分数double sorce;// 成员方法// 判断是否通过public void checkPass(double sorce){if(sorce > sorce){System.out.println("恭喜你通过了!");}else{System.out.println("很遗憾,你落选了");}}
}
上述代码我们可以看到一个问题:该成员方法的目的是比较用户传进来的成绩和通过的分数,来判断用户是否通过,但成员方法的形参名与成员变量名有冲突,所以这时就不得不使用 this 关键字,可修改为以下代码:
public class Student{// 成员变量// 代表通过所需要的分数double sorce;// 成员方法// 判断是否通过public void checkPass(double sorce){// this 代表该对象// this.sorce 就代表该对象的成员变量,也就是该类中定义的那个 sorce// 而 sorce 遵循就近原则,代表形参if(sorce > this.sorce){System.out.println("恭喜你通过了!");}else{System.out.println("很遗憾,你落选了");}}
}
6. 构造器
6.1 什么是构造器?
构造器是一种特殊的方法,但这个方法没有返回值类型,并且方法名必须和类名相同。
例如:
public class Student{public Student() {System.out.prinln("这是一个无参数构造器");}public Student(int age) {System.out.println("这是一个有参数构造器");}
}
6.2 构造器作用
构造器既然与类名相同,也就代表着,当我们创建对象时,对应的构造器也会执行
例如:
可以看到,当我们创建对象时,根据传参的不同,会执行相应的构造器,换句话说:new 对象就是在执行构造器
6.3 构造器应用场景
构造器是在创建对象时起作用的,所以可以在创建对象时给对象的属性做一些初始化操作,例如:
可以看到,当我们在创建对象时,通过有参构造器,就可以进行传参并初始化对应的成员变量。
构造器在使用时应注意以下几点:
- 在一个类中,若不书写构造器,Java 会自动生成一个无参数构造器;
- 一旦定义了有参数构造器,Java 便不会提供无参数构造器,此时建议自己写一个无参数构造器
7. 封装性
面向对象有三个核心的特性:封装性、继承性、多态性。下面我们来了解以下封装性
7.1 什么是封装?
封装就是用类设计对象处理某一个事物的数据时,把要处理的数据,以及处理数据的方法,都设计到一个对象中去。不恰当的说,就是自己的问题自己解决。
比如:在设计学生类时,我们把学生的各种信息以及需要用到的方法都封装到一个类中。
public class Student {String name;double score;public void CheckPass(){if(score > 60){System.out.println("及格了");}else{System.out.println("没及格");}}
}
7.2 封装的设计规范
封装的设计规范可以总结为:合理隐藏、合理暴露。
我们将一系列信息封装成一个类,是为了让用户使用这个类来解决问题,我们更希望用户能够调用一个接口便能解决一个复杂问题,而不是把一个复杂问题交给用户自己去做。就如同车企做一台汽车,车企让用户通过油门、刹车、方向盘等方式来操控汽车,而不是让用户直接控制发动机、点火装置、行车电脑等内部的设备,因为这样不仅操作复杂,还非常危险。
7.3 封装的书写
首先我们介绍一个修饰符private,被该修饰符修饰的变量或者方法,只能在本类中被访问。
例如:
public class Student {private int i = 1;int j = 2;public void Print(){System.out.println(i);// 输出1System.out.println(j);// 输出2}
}class Tree {Student st = new Student();public void Print(){System.out.println(st.i);// 报错System.out.println(st.j);// 输出2}
}
如上述代码所示,private int i就相当于把变量i封装在Student对象的内部,不对外暴露,也就不能直接访问这个变量了。
我们可以通过对外暴露一个方法,通过该方法来间接访问变量,这样既不会直接暴露成员变量,又可以访问它。
例如:
public class Student {private int score;// 赋值public void setScore(double score){this.score = score;}// 获取public void getScore(){return score;}
}
上述代码中,我们将变量score隐藏起来,通过方法setScore(double score)就可以来接收用户的输入,通过方法getScore()就可以来获取变量的值,这样合理隐藏,合理暴露的编程思想使得代码更为安全。
8. 实体JavaBean
在面向对象编程中,我们会经常书写一种特殊的类——实体JavaBean类,它有如下特点:
- 这个类中的成员变量都要私有,并且要对外提供getXXX、setXXX方法
- 类中必须要有一个公共的无参的构造器
例如:
public class Student {//所有成员变量都要私有化private String name;private int id;private double score;//类中必须提供一个公共的无参构造器public Student() {}//为每个成员变量提供Getter和Setterpublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}
}
实体类中除了有给对象存取数据的方法,就没有其他功能了,所以实体类的作用就是来封装数据。
实际开发中,我们将数据单独通过实体JavaBean类来封装,处理数据的方法又通过另一个类来封装。这样就实现了数据和数据业务处理相分离。
例如:
本文结束