Java作为一门面向对象编程语言,支持以下基本特性:
- 多态
- 继承
- 封装
- 抽象
- 类
- 对象
- 实例
- 方法
- 消息传递
这一节,我们一起来学习这两个基本概念:类和对象。回顾一下上一节中我们提到的基本概念:
- 对象 - 对象包含状态和行为。例如,一只小狗是一个对象,它具有的状态有颜色、名字和品种,以及具有的行为有摇尾巴、犬吠和吃东西等。对象是类的实例。
- 类 - 类可以被理解为一个模板或蓝图,用于描述对象支持的类型、描述对象的行为和状态。
Java中的对象
让我们来更深入地学习一下什么是对象。在我们的现实生活中,有很多的东西都是对象,例如猫,狗和人等等,所有这些对象都有状态和行为属性。
比如说,狗的状态属性有:名字,品种,颜色;行为属性有:犬吠,摇尾巴,奔跑。
软件中的对象和现实生活中对象的概念特征非常相似。软件中的对象同样有状态和行为属性,状态存放于字段中,而行为通过方法来展示。因此,在软件开发中,方法操作对象内部的状态,同时,对象间的通信也通过方法来完成。
Java中的类
我们在上一节中提到过,类可以被理解为一个模板或蓝图,而对象就是根据类这个模板创建的。
下面这段代码展示的是一个简单的类。
public class Dog {
String breed;
int age;
String color;
void barking() {
}
void hungry() {
}
void sleeping() {
}
}
类可以包含下面这几种的变量类型:
- 局部变量 - 定义在方法、构造器和代码块中的变量被称为局部变量。局部变量会在随方法申明和初始化,并在方法执行完成的时候被销毁
- 实例变量 - 实例变量是在类中、方法外的变量。实例变量会随着类的初始化而初始化,能被类中的任意方法、构造器和代码块访问。
- 类变量 - 类变量是定义在类中、方法外,且被static关键字定义的变量。
一个类中可以有任意个方法,方法也可以定义成不同的访问类型。上面的代码中,barking(),hungry()和sleeping()都是方法。
下面,我们来看一下Java类中比较重要的几个概念。
构造器
当我们讨论类的时候,有几个比较重要的概念需要着重关注,构造器就是其中的一个。构造器也叫构造函数,每个类中都有构造器,如果在一个类中我们不明确地写一个构造器的话,Java编译器会为这个类创建一个默认的构造器。
每当一个新的对象被创建时,至少有一个构造器会被调用,来初始化新建的对象。需要注意的是,一个类可以有多个构造器,但必须有一个构造器和类的命名相同。
下面是一个构造器的例子。
构造器例子
public class Puppy {
public Puppy() {
}
public Puppy(String name) {
//这个构造器有一个参数:name
}
}
和许多编程语言一样,Java也支持单例模式,也就是说你只能对单例模式的类创建一个实例。
注意:构造器有两种不同的类型,我们会在后面的章节中详细讨论构造器。
创建一个对象
前面提到了,类为对象提供了蓝图。因此,基本上可以说,对象是由类创建而来。在Java中,创建新的对象时,使用关键字“new”。
从类创建对象时有3个步骤:
- 声明 - 变量声明时需要声明变量名和类型
- 实例化 - 使用关键字“new”来创建对象
- 初始化 - 关键字“new”后面跟着构造器,这就是新对象的初始化。
下面是创建对象的一个例子:
public class Puppy {
public Puppy(String name) {
//这个构造器有一个参数:name
System.out.println("传入的name是 :" + name );
}
public static void main(String []args) {
//创建一个对象:myPuppy
Puppy myPuppy = new Puppy( "tommy" );
}
}
在编译和运行上面程序后,会输出:
Passed Name is :tommy
访问实例变量和方法
实例变量和方法通过创建的对象来访问。下面代码展示了访问实例变量的步骤:
/* 首先创建一个对象 */
ObjectReference = new Constructor();
/* 然后调用一个变量 */
ObjectReference.variableName;
/* 可以这样调用类中的方法 */
ObjectReference.MethodName();
一个例子
下面这个例子阐述了如何访问类的实例变量和方法。
public class Puppy {
int puppyAge;
public Puppy(String name) {
// 构造器有一个传入参数:name
System.out.println("选择的名字是 :" + name );
}
public void setAge( int age ) {
puppyAge = age;
}
public int getAge( ) {
System.out.println("Puppy的年龄是 :" + puppyAge );
return puppyAge;
}
public static void main(String []args) {
/* 创建对象 */
Puppy myPuppy = new Puppy( "tommy" );
/* 调用类的方法来设置年龄 */
myPuppy.setAge( 2 );
/* 调用类的另一个方法来获取年龄 */
myPuppy.getAge( );
/* 同样可以这样访问实例变量 */
System.out.println("变量值是 :" + myPuppy.puppyAge );
}
}
编译和运行后,输出的结果为:
选择的名字是 :tommy
Puppy的年龄是 :2
变量值是 :2
源代码文件声明规则
在本节的最后,我们来看一下源代码文件的声明规则。当我们在源文件充声明类,使用import语句和package语句时,这些语法规则都是必须遵守的。
- 在一个源文件中,只能定义一个公共类(public class)
- 一个源文件中,可以有多个非公共类(non-public class)
- 源文件的名字应该和公共类的名字相同,只在最后多个“.java”的后缀。例如,类名是public class Employee{},那么源文件名字就应该是:Employee.java
- 如果类是定义在包里面的,那么package语句就应该在源文件的第一行。
- 如果文件中有引用其它开发包,那么import语句应该放在package语句和定义类的语句中间。如果没有引用其它开发包,那么import语句应该位于源文件的第一行。
- import和package语句将会隐含适用到源文件中的所有类中,同一个源文件中的类不可能会声明不同的import和package语句。
类可以定义成不同的访问级别,并且类也有几种不同类型:抽象类和finale类等等。我们将在访问修饰符章节中解释这些概念。除了这些类型的类,Java也有一些特殊的类,例如,内部类和匿名类。
Java包
简单地来说,包是用来对类和接口进行分类的。当开发Java程序时,会有成百上千的类和接口会被编写在程序中,因此我们必须给这些类进行分类,由此让开发工作变得更简单些。
Import语句
在Java中,只要提供完整的名字(包括报名和类名),编译器就可以轻松地定位到源代码和类。Import语句就是一种为编译器提供正确路径来定位指定类的方法。
举个例子,编译器执行到下面这一行import语句时,将会把包java/io下所有可访问的类加载出来:
import java.io.*;
一个简单的案例分析
我们创建两个类来进行案例分析:Employee和EmployeeTest。
首先,创建一个java文件,把下面的代码复制到文件中。需要注意的是,下面这段代码是Employee类,并且是一个公共类,因此保存文件后需要把文件名修改为和类名一致:Employee.java
Employee类里有4个实例变量:name,age,designation和salary。类里有一个明确定义的构造器,构造器有一个传入参数。
import java.io.*;
public class Employee {
String name;
int age;
String designation;
double salary;
//这是类Employee的构造器
public Employee(String name) {
this.name = name;
}
//给Employee的age变量赋值
public void empAge(int empAge) {
age = empAge;
}
/*给designation变量赋值*/
public void empDesignation(String empDesig) {
designation = empDesig;
}
/*给salary变量赋值*/
public void empSalary(double empSalary) {
salary = empSalary;
}
/*打印Employee的详情*/
public void printEmployee() {
System.out.println("Name:"+ name );
System.out.println("Age:" + age );
System.out.println("Designation:" + designation );
System.out.println("Salary:" + salary);
}
}
我们的系列教程前面提到过,程序运行是从main函数开始的。因此,为了运行Employee类,我们需要创建一个main方法和一个对象,我们在一个新的类中完成这两个创建任务。
下面的EmployeeTest类创建了Employee类的两个实例对象,并且调用了各自的方法来为变量分别赋值。
将下面的代码保存在EmployeeTest.java文件中。
import java.io.*;
public class EmployeeTest {
public static void main(String args[]) {
/* 使用构造器创建两个对象 */
Employee empOne = new Employee("James Smith");
Employee empTwo = new Employee("Mary Anne");
//给创建的两个对象调用方法
empOne.empAge(26);
empOne.empDesignation("Senior Software Engineer");
empOne.empSalary(1000);
empOne.printEmployee();
empTwo.empAge(21);
empTwo.empDesignation("Software Engineer");
empTwo.empSalary(500);
empTwo.printEmployee();
}
}
接着,编译这两个源文件然后运行EmployeeTest来看看运行结果:
C:\> javac Employee.java
C:\> javac EmployeeTest.java
C:\> java EmployeeTest
Name:James Smith
Age:26
Designation:Senior Software Engineer
Salary:1000.0
Name:Mary Anne
Age:21
Designation:Software Engineer
Salary:500.0
本篇小结
更多交流,欢迎加群(584017112):