1.内容涉及
- 使用预定义类
- 用户自定义类
- 静态方法
- 方法参数
- 对象构造
- 类设计技巧
2.内容详解
(一)使用预定义类
1.对象与对象变量
要想使用对象,首先必须构造对象,并指定其初始状态。然后对对象应用方法。
在Java程序设计语言中,要想使用构造器(或称构造函数)构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。
构造器的名字应该与类名相同。比如说,Date类的构造器名为Date。要想构造一个Date对象,需要在构造器前面加上new操作符,如下所示。
new Date();
这个表达式构造了一个新对象。这个对象被初始化为当前的日期和时间。如果需要的话也可以将这个对象传递给一个方法:
System.out.print(new Date());
或者,也可以对刚刚创建的对象应用一个方法。Date类中有一个toString方法。这个方法将返回日期的字符串描述。下面的语句可以说明如何对新构造的Date对象应用toString方法。
String s=new Date().toString();
在这两个例子中,构造的对象仅使用了一次。通常,你会希望构造的对象可以多次使用,因此,需要将对象存放在一个变量中:
Date birthday=new Date();
图三显示了对象变量birthday,它引用了新构造的对象。在对象与对变量之间存在着一个重要的区别。例如,以下语句:
Date deadline;
定义了一个对象变量deadline,它可以引用Date类型的对象。但是,一定要认识到:变量deadline不是一个对象,而且实际上它也没有引用任何对象。此时还不能在这个变量上使用任何Date方法。下面的语句
s=deadline.toString();//not yet
将产生编译错误。
必须首先初始化变量deadline,这里有两个选择。当然,可以初始化这个变量,让它引用一个新构造的对象:
deadline=new Date();
也可以设置这个变量,让它引用一个已有的对象:
deadline=birthday;
现在,这两个变量都引用同一个对象,请参见下图。要认识到重要的一点:对象变量并没有实际包含一个对象,它只是引用一个对象。
在Java中国,任何对象变量的值都是对存储在另外一个地方的某个对象的引用。new操作符的返回值也是一个引用。下面的语句:
Date deadline=new Date();
有两个部分。表达式new Date()构造了一个Date类型的对象,它的值是对新创建对象的引用。这个引用存储在变量deadline中。可以显示地将对象变量设置为null,指示这个对象变量目前没有引用任何对象。可以把Java中的对象变量看作类似于C++的对象指针。
Date birthday;//Java
//实际上,等同于
Date* birthday;//C++
(二)用户自定义类
1.从构造器开始
构造器与其他方法有一个重要的不同。构造器总是结合new运算符来调用。不能对一个已经存在的对象调用构造器来达到重新设置实例字段的目的。例如
Employee person=new Employee("Tony",50);
person.Employee("Iron man",60);//报错
现在只需要记住:
- 构造器与类同名。
- 每个类可以有一个以上的构造器。
- 构造器可以有0个、1个或多个参数。
- 构造器没有返回值。
- 构造器总是伴随着new操作符一起调用。
请注意,不要在构造器中定义与实例字段同名的局部变量。例如,下面的构造器将不会设置salary。(假设已经定义好了类Employee,它的成员变量有:name、salary、hireDay)。
public Employee(String n,double s,...)
{
String name=n;//ERROR
double salary=s;//ERROR
}
这个构造器声明了局部变量name和salary。这些变量只能在构造器内部访问。这些变量会屏蔽同名的实例。有些朋友偶尔会不假思索地写出这类代码,因为他们的手指会不自觉地增加数据类型。这种错误很难检查数来,因此,必须注意在所有的方法中都不要使用与实例字段同名的变量。
(三)静态方法
1.main方法
main方法不对任何对象进行操作。事实上,在启动程序是还没有任何对象。静态的main方法将执行并构造程序所需要的对象。每一个类可以有一个main方法。这是常用于对类进行单元测试的一个技巧。例如,可以在Employee类中添加一个mian方法:
class Employee
{
private String name;
private int age;
public Employee(String mname,int mage)
{
name=mname;
age=mage;
}
public Employee()
{
name="";
age=0;
}
public static void main(String[] args)
{
System.out.println("到里面来了");
}
}
如果想要独立地测试Employee类,只需要执行
java Employee
如果Employee类是一个更大型应用程序的一部分,就可以使用下面这条语句运行程序
java Application
Employee类的main方法永远不会执行。
需要注意,Employee类也有一个静态的main方法用于单元测试。试试运行 java JavaCoreTest和 java Employee,执行两个main方法。
主函数代码和执行结果如下图所示(用cmd命令行编译执行更加直观)。
public class JavaCoreTest {
public static void main(String[] args)
{
Employee person=new Employee("Tony",50);
System.out.println("在外面呢");
}
};
//Employee类在上文已经给出代码
执行结果如下
(四)方法参数
按值调用表示方法接收的是调用者提供的值。而按引用调用表示方法接收的是调用者提供的变量地址。方法可以修改按引用传递的变量的值,而不能修改按值传递的变量的值。
对于方法参数是基本数据类型(数字,布尔值)这里就不介绍了,大家应该都懂,这里主要强调对象引用。
你已经知道,一个方法不能修改基本数据类型的参数,而对象就不同了。很容易利用下面这个方法改变对象成员变量的值。
public static void tripleSalary(Employee x)
{
x.raiseSalary(200);
}
当调用
harry=new Employee(...)
tripleSalary(harry);
时,具体的执行过程为:
- x初始化为harry值的一个副本,这里就是一个对象引用。
- raiseSalary方法应用于这个对象的引用。x和harry同时引用的那个Employee对象的工资提高了200%。(明白改变了就行)
- 方法结束后,参数变量x不再使用。(如下图所示)
可以看到,实现一个改变对象参数状态的方法是完全可以的,实际上也相当常见。理由也很简单,方法得到的是对象引用的副本,原来的对象引用和这个副本都引用同一个对象。这使可能有些朋友认为Java程序设计语言对对象采用的是按引用调用,实际上,这种理解是不对的。由于这种理解具有一定的普遍性,所以很有必要给出一个反例来详细地说明一下这个问题。首先,编写一个交换两个Employee对象的方法:
public static void swap(Employee x,Employee y)
{
Employee temp=x;
x=y;
y=temp;
}
如果Java对对象采用的是按引用调用,那么这个方法就应该能够实现交换,但是这个方法并没有改变存储在变量a和b中的对象引用。swap方法的参数x和y被初始化为两个对象引用的副本,这个方法交换的是这两个副本。最终白费力气,在方法结束时参数变量x和y被丢弃了。原来的变量a和b仍然引用这个方法调用之前所引用的对象。这说明:Java程序设计语言对对象采用的不是按引用调用,实际上,对象引用是按值传递的。
下面总结一下再Java中对方法参数能做什么和不能做什么:
4. 方法不能修改基本数据类型的参数(即数值型或布尔型,比如1,2,3,true)。
5. 方法可以改变对象参数的状态。
6. 方法不能让一个对象参数引用一个新的对象。(好像就没有C++里的&方便了…)。
(五)对象构造
1.参数名
在编写很小的构造器时(这十分常见),常常在参数命名是感到困惑。
我们通常喜欢用单个字母作为参数名:
public Employee(String n,double s)
{
name=n;
salary=s;
}
但这样做有一个缺点:只有阅读代码才能够了解参数n和参数s的含义。有些程序员在每个参数前面加上一个前缀“a”:
public Employee(String aName,double aSalary)
{
name=aName;
salary=aSalary;
}
这样很清晰。读者一眼就能够看懂参数的含义。
还有一种技巧,它基于这样的事实:参数变量会遮蔽同名的实例字段。例如,如果将参数命名为salary,salary将指示这个参数,而不是实例字段。但是,还是可以用this.salary访问实例字段。回想一下,this指示隐式参数,也就是所构造的对象。下面是一个示例:
public Employee(String name,double salary)
{
this.name=name;
this.salary=salary;
}
(六)类设计技巧
1.一定要保证数据私有
2.一定要对数据进行初始化
3.不要在类中使用过多的基本类型
4.不是所有的字段都需要单独的字段访问器和字段更改器
5.分解过多指责的类
6.类名和方法名要能够体现它们的职责