Java简明教程系列(3) - 对象和类

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):

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章