简单类包包含一个main方法可以直接运行,main方法就是入口,一个程序都会有一个入口。但是面对真实的业务逻辑,一个工程项目是由大量的class文件组合而成,每个类都有自己的实例域或者实例方法。也许会写比较多的main方法,但是只有程序启动指定的main方法才是入口。
面对真实的业务,已有的类库是不能完全满足需求的,所以才有有了项目开发。
一个Employee类
看似简单,其实每个大公司都会HR系统,会涉及到员工对象。
最简单的类定义形式:
class ClassName{
field1,
field2,
...
constructor1,
constructor2,
...
method1,
method2
...
}
一个简单员工类
package com.wht.demo;
import java.util.Calendar;
import java.util.Date;
/**
* 员工类
* @author wht
*/
public class Employee {
private String name;
private double salary;
private Date hirDay;
public Employee(String name, double salary, int year,int month,int day) {
Calendar calendar = Calendar.getInstance();
calendar.set(year,month,day);
this.name = name;
this.salary = salary;
this.hirDay = calendar.getTime();
}
public void raiseSalary(double percent){
this.salary +=this.salary*percent/100;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public Date getHirDay() {
return hirDay;
}
}
类的使用
package com.wht.demo;
import java.text.SimpleDateFormat;
public class EmployeeTest {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
// 构造三个真实员工
Employee[] staff = new Employee[3];
staff[0] = new Employee("孙悟空", 25000.00, 2019, 10, 22);
staff[1] = new Employee("提莫队长", 25000.00, 2019, 10, 22);
staff[2] = new Employee("德玛西亚", 25000.00, 2019, 10, 22);
//业绩不错为每个员工加薪
for (Employee emp : staff) {
emp.raiseSalary(5);
}
//查看每个员工加薪后的信息
for (Employee emp : staff) {
System.out.println("姓名"+emp.getName()+",薪资"+emp.getSalary()+",入职时间"+simpleDateFormat.format(emp.getHirDay()));
}
}
}
运行结果:
姓名孙悟空,薪资26250.0,入职时间2019-11-22
姓名提莫队长,薪资26250.0,入职时间2019-11-22
姓名德玛西亚,薪资26250.0,入职时间2019-11-22
可以看到类的使用,类和对象的区别。类只是模板,不具有可用性,只有创造除了对象,才具有了实体,他的数据和方法才可以调用。
从上面也看到了类的封装性。
因为这两个类在同一目录下,手工可以这么编译
javac Employee*.java
通配符编译
回顾
看下这个对象的构造:
1、一个构造器
2、三个实例域
3、四个方法
所有的方法为public,意味着方法开发,向对象发送消息可以更改对象当前状态。
所有实例域都是私有的,确保了数据安全,不能随意设置,只能按照公开的方法进行修改实例域。
在这些方法中,我们可以添加校验逻辑,确保数据安全。
从构造器开始
public Employee(String name, double salary, int year,int month,int day) {
Calendar calendar = Calendar.getInstance();
calendar.set(year,month,day);
this.name = name;
this.salary = salary;
this.hirDay = calendar.getTime();
}
构造器与类同名。
在构造Employee类的对象时,构造器被运行,以便将实例域初始化为所希望的状态。
构造器与其他的方法有一个重要的不同。构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。
- 构造器与类同名。
- 每个类可以有一个以上的构造器。
- 构造器可以有0个、1个或多个参数。
- 构造器没有返回值。
- 构造器总是伴随着new操作一起调用。
java对象都是在堆中构造的
请注意:不要在构造器中定义与实例域重名的局部变量。
隐式参数与显示参数
方法用于操作对象以及存取它的实例域。
public void raiseSalary(double percent) {
this.salary += this.salary * percent / 100;
}
emp.raiseSalary(5);
raiseSalary方法有两个参数,第一个参数被称为隐式参数,是出现在方法名前的Employee对象。
隐士参数在python和js中使用更加明显。
第二个参数是明显地列在方法声明中的显示参数。
在每一个方法中,关键字this表示隐式参数。
更多的程序员喜欢携带this,因为这样可以将实例域与局部变量明显地分离开。
封装的优点
get set 方法被称为域访问器。
- 可以改变内部实现,除了该类的方法之外,不会影响其他代码。
- 更改器方法可以自行错误检查,然而直接对域进行赋值将不会进行这些处理。
基于类的访问权限
方法可以访问所有对象的私有数据。
私有方法
在实现一个类时,由于共有数据非常危险,所以应该将所有的数据域都设置为私有的。
方法应该如何设计?
共有方法是为外部调用,用于操作对象。
但是有些时候,我们需要把一个方法拆分成N多辅助方法,每个方法只做一件事(单一权责),而只有类内部使用的方法可以定义为私有方法:private。
当私有方法类内部不再需要了,可以直接删除。开发工具也会显示未被使用。
Final 实例域
如果实例域定义为final,构建对象时必须初始化这样的域。
也就是说,必须确保在每一个构造器执行之后,这个域的值被设置。
必须确保在每一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够再对它进行修改。
final修饰符大都应用于基本数据类型域,或不可变类的域,对于可变了的类,使用final修饰符可能会对读者造成混乱。