对象和类

方法参数

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个副本。具体来讲,方法不能修改传递给它的任何参数变量的内容。

方法参数有两种类型

  • 基本数据类型(数字、布尔值)
  • 对象引用

例1:

/**
 * This program demonstrates parameter passing in Java.
 * @version 1.00 2000-01-27
 * @author Cay Horstmann
 */
public class ParamTest
{
   public static void main(String[] args)
   {
      /*
       * Test 1: Methods can't modify numeric parameters
       */
      System.out.println("Testing tripleValue:");
      double percent = 10;
      System.out.println("Before: percent=" + percent);
      tripleValue(percent);
      System.out.println("After: percent=" + percent);

      /*
       * Test 2: Methods can change the state of object parameters
       */
      System.out.println("\nTesting tripleSalary:");
      Employee harry = new Employee("Harry", 50000);
      System.out.println("Before: salary=" + harry.getSalary());
      tripleSalary(harry);
      System.out.println("After: salary=" + harry.getSalary());

      /*
       * Test 3: Methods can't attach new objects to object parameters
       */
      System.out.println("\nTesting swap:");
      Employee a = new Employee("Alice", 70000);
      Employee b = new Employee("Bob", 60000);
      System.out.println("Before: a=" + a.getName());
      System.out.println("Before: b=" + b.getName());
      swap(a, b);
      System.out.println("After: a=" + a.getName());
      System.out.println("After: b=" + b.getName());
   }

   public static void tripleValue(double x) // doesn't work
   {
      x = 3 * x;
      System.out.println("End of method: x=" + x);
   }

   public static void tripleSalary(Employee x) // works
   {
      x.raiseSalary(200);
      System.out.println("End of method: salary=" + x.getSalary());
   }

   public static void swap(Employee x, Employee y)
   {
      Employee temp = x;
      x = y;
      y = temp;
      System.out.println("End of method: x=" + x.getName());
      System.out.println("End of method: y=" + y.getName());
   }
}

class Employee // simplified Employee class
{
   private String name;
   private double salary;

   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public void raiseSalary(double byPercent)
   {
      double raise = salary * byPercent / 100;
      salary += raise;
   }
}

从以上例子可以看到

  • 基本数据类型(数字、布尔值)做方法参数,传进来的一个copy副本,不能修改原参数,只能修改副本。
  • 方法可以改变对象参数的状态(因为方法里的对象参数和原对象都指向一个内存空间)。对象参数改变,原对象也跟着改变。
  • 方法不能让一个对象参数引用一个新的参数对象。(对象参数的内存空间指向已经定了,作为参数也不能改变,就算改变也只是在方法内部有效)

对象构造

初始化块

java对象初始化数据字段共有三种方法:

  • 在构造器中设置值

  • 在声明中赋值

  • 初始化块赋值(不常用,通常会直接将初始化代码块放在构造器中)

    class Employee
    {
       private static int nextId;
    
       private int id;
       private String name = ""; // instance field initialization
       private double salary;
      
       // static initialization block
       static
       {
          Random generator = new Random();
          // set nextId to a random number between 0 and 9999
          nextId = generator.nextInt(10000);
       }
    
       // object initialization block 
      // 下面的就是初始化块
       {
          id = nextId;
          nextId++;
       }
       }
    

调用构造器的处理步骤

由于初始化数据字段有多种途径,所以列出构造过程的所有路径可能让人很困惑。下面是调用构造器的具体处理步骤:

  • 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器。
  • 否则:
    • 所有的数据字段初始化为其默认值(0、false或null)。~如在无参构造器里调用有参构造器。
    • 按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块。
  • 执行构造器主体代码

例2

import java.util.*;

/**
 * This program demonstrates object construction.
 * @version 1.01 2004-02-19
 * @author Cay Horstmann
 */
public class ConstructorTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      Employee[] staff = new Employee[3];

      staff[0] = new Employee("Harry", 40000);
      staff[1] = new Employee(60000);
      staff[2] = new Employee();

      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
               + e.getSalary());
   }
}

class Employee
{
   private static int nextId;

   private int id;
   private String name = ""; // instance field initialization
   private double salary;
  
   // static initialization block  静态初始化块
   static
   {
      Random generator = new Random();
      // set nextId to a random number between 0 and 9999
      nextId = generator.nextInt(10000);
   }

   // object initialization block   初始化块
   {
      id = nextId;
      nextId++;
   }

   // three overloaded constructors
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }

   public Employee(double s)
   {
      // calls the Employee(String, double) constructor
      this("Employee #" + nextId, s);
   }

   // the default constructor
   public Employee()
   {
      // name initialized to ""--see above
      // salary not explicitly set--initialized to 0
      // id initialized in initialization block
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public int getId()
   {
      return id;
   }
}

执行结果

name=Harry,id=2659,salary=40000.0
name=Employee #2660,id=2660,salary=60000.0
name=,id=2661,salary=0.0

Java允许使用包(package)将类组织在一个集合中。借助包可以方便地组织自己的代码,并将自己的代码与别人提供的代码库分开管理。

静态导入

有一种import语句允许导入静态方法和静态字段,而不只是类。

例如,如果在源文件顶部,添加一条指令:

import static java.lang.System.*; 或导入特定的方法或者字段:import static java.lang.System.out;

就可以使用System类的静态方法和静态字段,而不必加类名前缀:

out.println("Goobye,World!");

posted @ 2021-09-13 14:28  石佳炜  阅读(36)  评论(0编辑  收藏  举报