java 对象和类(二)
用户自定义类
最简单的类定义形式为:
class ClassName
{
field1
field2
......
constructor1
constructor2
......
method1
method2
......
}
写一个自定义类的例子:
import java.time.*;
/**
* @author duke_coding@163.com
* @date 2018/9/4 14:53
*/
public class EmployeeTest {
public static void main(String[] args)
{ //构造一个Employee数组,并填入三个雇员对象
Employee[] staff = new Employee[3];
staff[0] = new Employee("刘甲",75000,1991,1,1);
staff[1] = new Employee("刘乙",50000,1991,2,2);
staff[2] = new Employee("刘丙",30000,1991,3,3);
//使用raiseSalary方法提升每个雇员5%的薪水
for (Employee e : staff)
e.raiseSalary(5);
//调用3种方法将每个雇员的信息打印出来
for (Employee e : staff)
System.out.println("name="+e.getName()+",salary="+e.getSalary()
+",hireDay="+e.getHireDay());
}
}
class Employee
{
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String n, double s, int year, int month, int day)
{
name = n;
salary = s;
hireDay = LocalDate.of(year,month,day);
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
对这个例子进行分析:
你可能会注意到这一个源文件包含了两个类,但是也可以将每一个类存在一个单独的源文件中。、
你会发现可以直接运行EmployeeTest.java,并没有显示的编译Employee.java,会发现正常运行。原因是java编译器发现EmployeeTest.java使用了Employee类时会自动查找Employee class文件,当查找不到时,会自动搜索Employee.java文件然后进行编译。重要的是:如果Employee.java版本比已有的Employee class文件版本新,java编译器会自动地重新编译这个文件。
Employee类中包含一个构造器和4个方法,这个类中的所有方法都被标记为public,意味着任何类的任何方法都可以调用这些方法。private确保只有Employee类自身的方法能够访问这些实例域,而其他类的方法不能够读写这些域。有两个实例域本身就是对象,name域是String类对象,hireDay是localDate类对象,类通常帮括类型属于某个类类型的实例域。
构造器
Employee类中的构造器与类同名,在构造Employee类的对象时,构造器会运行,以便将实例域初始化为所希望的状态。
- 构造器与类同名
- 每个类可以有一个以上的构造器
- 构造器可以有0个、1个或多个参数
- 构造器没有返回值
- 构造器总是伴随着new操作一起调用
注:不要在构造器中定义与实例域重名的局部变量。
隐式参数与显示参数
例如:test123.raiseSalary(5); //结果将test123.salary域的值增加5%
//其实调用的是执行的下列指令
double raise = test123.salary * 5 /100;
test123.salary += raise;
raiseSalary方法有两个参数。第一个参数为隐式参数,是出现在方法名前的Employee类对象。第二个参数位于方法名后面括号中的数值,这是一个显示参数。
可以看到,显示参数是明显地列在方法声明中的,例如double byPercent,关键字this表示隐式参数,如果需要的话可以按下列编写方式。
public void raiseSalary(double byPercent)
{
double raise = this.salary * byPercent /100;
this.salary += raise;
}
封装的优点
需要获得或设置实例域的值,应该提供下面三项内容:
- 一个私有的数据域
- 一个公有的域访问器方法
- 一个公有的域更改器方法
这样做比提供一个简单的公有数据域复杂,但是有明显的好处:可以改变内部实现,除了该类的方法之外,不会影响其他代码。例:
//将存储名字的域改为下面
String firstName;
String lastName;
那么getName方法可以改为返回
firstName + " " + lastName
对于这点改变,程序的其他部分完全不可见。
其次,更改器方法可以执行错误检查,然后直接对域进行赋值就不会处理这些。
注:不要编写返回引用可变对象的访问器方法,在上面的例子中如果将localDate类换成Date类就违反了这个设计原则。因为Date对象是可变的,这样就破坏了封装性,Date类中有一个更改器方法setTime,可以设置毫秒数。