本文是Java基础课程的第六课。主要介绍面向对象编程思想、Java中类和对象的概念及如何使用、包和导入包等内容
文章目录
一、面向对象
1、什么是对象
万事万物皆为对象,对象是具体的。能看的见、摸得着的任何物品都是对象,比如一只猫、一只狗、一只鸭子、一辆汽车、一个板凳、一台电脑等等,甚至看不见、摸不着的的事物也是对象,比如一个想法、一种策略、一个命令等等。认识一个对象往往通过两个方面进行,一是对象具有什么状态,二是对象具有什么行为。对象的状态即该对象本身固有的属性,例如一只猫有年龄、体重、毛色等,对象的行为即对象具有的功能,比如一只猫可以捉老鼠是、上树、跳跃等。
2、什么是类
类是具有相同的状态和行为的一组对象的集合,类是抽象的。例如有一组对象,他们都具有姓名、身高、体重、学号这些状态(属性),并且他们也都具有听课、做作业这些行为,他们便可以归纳为同一类,即学生类。日常生活中我们经常不知不觉的进行着分类,比如坏人、宠物、家具、数据类型等。
3、如何理解面向对象
可以毫不夸张的说,面向对象是程序开发人员认识、理解世界的世界观,方法论。
面向对象的基本哲学是,世界是由各种各样具有自己的内部状态(属性)和运动规律(行为)的对象所组成的;不同对象之间的相互作用和通讯构成了完整的现实世界。
从方法论的角度可以认为,在描述世界的过程中,使用的模型或系统的结构应该直接与现实世界的结构相对应,应该围绕现实世界中的对象来构造模型或系统,通过对象的相互作用来反映世界的运行过程。这样建立起来的系统才最符合现实世界的本来面目。
面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,Object Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及最常听到的面向对象编程(OOP,Object Oriented Programming)等等。
4、面向对象程序设计
面向对象程序设计(Object Oriented Programming,OOP)是一种基于面向对象思想的计算机软件设计方法,是目前软件开发的主流方法。
面向对象程序设计指的是,在设计一个软件系统时,尽可能运用人类的自然思维方式,将问题域中的事物抽象地表示为系统中的对象,作为系统的基本构成单位,使系统直接地映射问题域,保持问题域中事物及其相互关系的本来面貌。
二、Java中的类和对象
Java是一种纯粹的面向对象的语言,每一个程序至少包含一个类,所有的数据(属性)和操作(行为)都封装到类中。
1、声明类
Java中用关键字class
来声明类,具体语法格式如下:
class 类名 {
// 成员变量声明部分,即属性
// 成员方法声明部分,即行为
}
说明:
- 类声明在Java源文件中(扩展名为
.java
的文本文件),一个源文件中只能声明一个公开的类(用public
关键词修饰的类),源文件名必须与该类名相同。同时,一个源文件中也可以声明多个非空开类。 - 类的声明包括类首和类主体两部分:类首确定类名,其中
class
是声明类的关键字,类名需符合标识符的命名规范,并约定所有单词首字母大写,一般为一个名词或名词性短语;类主体声明类有哪些属性及声明类有哪些行为,属性用成员变量来体现;行为用成员方法来体现。 - 声明成员变量的语法就是申明变量的语法,只不过成员变量声明在类主体内,不在方法中。方法中申明的变量称之为局部变量。
- 声明成员方法时,成员方法名需符合标识符的命名规范,并约定首字母小写,其余单词首字母大写,一般为一个动词或动宾短语。
- 声明类,也就是创建了一种新的引用数据类型。
下面是一个实例:
public class Student {
// 声明成员变量
String name; // 姓名
int age; // 年龄
String studentNo; // 学号
// 声明成员方法
// 自我介绍的方法
void introduce(){
System.out.printf("大家好,我是%s,我今年%d岁,我的学号是:%s", name, age, studentNo);
}
}
说明:
- 声明了一个学生类,该类具有的属性为姓名、年龄、学号;该类具有的行为是进行自我介绍。
- 一个类可以用UML类图来描述,如下:
2、创建对象
被声明过的类可以用来创建对象,所谓的创建对象就是声明变量并初始化的过程。
下面是一个实例:
public class Test {
public static void main(String[] args) {
// 声明一个Student类型的变量
Student stu1;
// 创建一个Student类型的对象并通过"=="初始化变量stu1
stu1 = new Student();
// 或者写在一起
Student stu2 = new Student();
}
}
说明:
- 使用
new
运算符创建对象,实质就是为对象在堆内存中分配内存空间。 new Student()
会创建一个Student
类的对象,这个过程也叫做实例化一个Student
类的对象。- 一个类可以实例化多个对象,不同对象在内存中是独立的。
3、使用对象
对象被创建后(或称被实例化后),这个对象就拥有了所属类的属性和方法,对象可以使用.
运算符来访问属性(访问成员变量)或执行行为(调用成员方法)。
下面是一个示例:
public class Test {
public static void main(String[] args) {
Student stu;
stu = new Student();
// 向对象的属性赋值
stu.name = "林冲";
stu.age = 21;
stu.studentNo = "10001";
// 调用对象的方法
stu.introduce();
}
}
- 本例中,在
main
方法中声明了一个Student
类型的变量stu
,并实例化了一个Student
类型的对象,赋值给了变量stu
,之后通过变量stu
访问了该对象的属性并对属性进行了赋值,最后调用了该对象的方法introduce()
。
4、对象的内存分配
上面示例中的代码在运行时,内存中是怎样变化的呢,下面用图示来说明:
说明:
- 执行代码
Student stu
时,在main
方法对应栈帧的局部变量表中,为Student
类型的变量stu
分配一块内存。 - 执行
stu = new Student()
时,首先,new
操作符会让JVM在堆内存中分配一块内存空间(最主要的就是为属性分配内存空间),用来存储一个Student
类型的对象,之后,赋值操作会将堆内存中已经分配好的内存空间的首地址存储到变量stu
在局部变量表里对应的位置。 - 在堆内存中为刚才创建的
Student
对象的name
属性,age
属性,studentNo
属性赋值,即向这些变量对应的内存中存入值,基本数据类型存具体数据,引用类型存内存地址编号。 - 后续依次运行之后的代码…
注意,实例化一个Student
对象时,该对象的属性是具有初始值(默认值)的,byte
、short
、int
、long
类型的属性的初始值是0
,float
、double
类型的属性的初始值是0.0
,boolean
类型的属性的初始值是false
,char
类型的属性的初始值是'\u0000'
,引用类型的属性的初始值是null
。
下面是一个示例:
public class Test {
public static void main(String[] args) {
Student stu;
stu = new Student();
stu.introduce();
}
}
输出的结果将是:
大家好,我是null,我今年0岁,我的学号是:null
事实上,在堆中分配内存,总会默认的进行初始化,堆中分配的内存中总是有初始值;而在栈中分配内存,则需要显式的初始化。
5、空指针 null
观察并运行下面的示例:
public class Test {
public static void main(String[] args) {
Student stu;
stu = null;
stu.introduce();
}
}
当执行stu.introduce()
时,程序会抛出一个异常,如下:
Exception in thread "main" java.lang.NullPointerException
at com.luas.test.Test.main(Test.java:5)
造成这个异常的原因就在于stu = null
这一句代码,将变量stu
赋值为null
。
引用类型的变量应该存储一个内存地址编号,而null
值则表明变量没有引用任何内存地址编号,是一个空引用。当变量的值是null
时,访问属性或调用方法,都将会抛出NullPointerException
。
三、包
在复杂的文件系统中,文件分门别类存储在不同的文件夹中,便于组织管理及查找,同时也避免文件的重名问题。在程序设计过程中,一个系统工程需要编写几百个甚至上千个文件,可能有很多开发人员共同协作完成,也存在组织管理类文件和避免类文件同名等问题。Java中使用包来解决,Java的类文件存储在不同的包中。
1、将类组织在包中
在每一个类文件最前面,使用关键字package
说明该类文件中的类组织在哪个包中。
下面是一个示例:
package com.codeke.java.test1;
public class Student {
// 声明成员变量
String name; // 姓名
int age; // 年龄
String studentNo; // 学号
// 声明方法
// 自我介绍的方法
void introduce(){
System.out.printf("大家好,我是%s,我今年%d岁,我的学号是:%s", name, age, studentNo);
}
}
说明:
- 使用了
package
语句说明了类Student
在包com.codeke.java.test1
中,项目中应该有对应的包路径结构,同时,包名会在磁盘上生成对应的文件目录。如下:
- 一个类文件中只能有一条
package
语句,且位于类文件最上面(忽略注释)。 - 同一个包中类名不可以相同,不同包中类名可以相同。
类所属的包名.类名
称之为类的完全限定名,如例子中Student
类的完全限定名为com.codeke.java.test1.Student
。- 通常,每个公司开发的软件系统中,开头的包名都是该公司的域名倒置。
2、常见的Java系统包
JDK中已经为开发者提供了许多声明好的类,称为类库,位于JDK安装目录下的\lib
目录中,开发者可以直接使用。同时,JDK中将这些类按相关的功能都组织在一个个不同的包中,这些包常被称作系统包,常见的系统包有:
系统包 | 说明 |
---|---|
java.lang | Java语言的核心类,如String 、Math 、System 等 |
java.util | 大量的工具类,如Scanner 、Random 等 |
java.net | Java网络编程的相关类 |
java.io | Java输入 \ 输出操作的相关类 |
java.text | 一些Java格式化的相关类 |
java.sql | Java对数据库操作的相关类 |
java.awt 和java.swing | Java下图形界面程序开发的相关类 |
3、导入其他包中的类
程序开发过程中,经常需要在一个类中使用另外一个包中的类,此时就需要导入其他包中的类。通常有两种方法,一是使用import
语句,另一种是使用类的完全限定名。
3.1、使用import语句
下面是一个示例:
package com.codeke.java.test2;
import com.codeke.java.test1.Student;
public class Test {
public static void main(String[] args) {
Student stu = new Student();
}
}
说明:
import
语句在package
语句下,类声明上方,一个类文件中可以包含任意数量的import
语句。一个类文件中导入某个类后,该类文件中的声明的所有类中均可以使用被导入的类。- 可以使用
*
来导入某个包中的多个类,比如将java.util
包下的所有类都导入进来,可以使用import java.util.*;
。 - 同包中的类在使用时无需显式导入;
java.lang
包中的类在使用时无需显式导入。
3.2、使用类的完全限定名
下面是一个示例:
package com.codeke.java.test2;
public class Test {
public static void main(String[] args) {
com.codeke.java.test1.Student stu = new com.codeke.java.test1.Student();
}
}
说明:
- 无需赘述。