构造器
构造器与类同名
每个类可以有一个以上的构造器
构造器可以有0个、1个或多个参数
构造器没有返回值
构造器总是伴随着new操作一起使用
不要在构造器中定义与实例域重名的局部变量,其只能在构造器内部进行访问
访问器方法
只返回实例域的值,又称域访问器,一旦在构造器中设置完毕,就没有任何一个方法对他进行修改。
例如以下代码:
// 访问器
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public LocalDate getHireDay() {
return hireday;
}
代码块
import java.time.LocalDate;
public class EmployeeTest {
public static void main(String[] args) {
Employee[]staff=new Employee[3];
staff[0]=new Employee("Carl Cracker",75000,1987,12,15);
staff[1]=new Employee("Harry Hacker",50000,1989,10,1);
staff[2]=new Employee("Tony Tesster",40000,1990,3,15);
for(Employee e:staff) {
e.raiseSalary(5);
}
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;
}
}
类的访问权限
例:Employee类的方法可以访问Employee类的任何一个对象的私有域。
私有方法
为了实现一个私有方法,只需将关键字public改为private即可。
只要方法是私有的,它不会被外部的其他类操作调用,可以将其删去。如果方法是公有的,就不能将其删去,因为其他的代码很有可能依赖它。
final实例域
可以将实例域定义为final。构建对象时必须初始化这样的域。即必须确保在每一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够再对它进行修改。
静态域
给Employee类添加一个实例域id和一个静态域nextId。
那么,每一个雇员对象都有一个自己的id域,但这个类的所有实例域将共享一个nextId域。
如果有1000个Employee类的对象,则有1000个实例域id。但是只有一个静态域nextId。即使没有一个雇员对象,静态域nextId也存在。它属于类,而不属于任何一个独立的对象。
静态方法
静态方法是一种不能向对象实施操作的方法。例如,Math类的pow方法就是一个静态方法。
表达式Math.pow(x,a)计算幂。在运算时,不能使用任何Math对象。换句话说就是没有隐式参数。
main方法也是一个静态方法。
工厂方法构造对象无法换成构造器构造对象的原因
例工厂方法转换货币:
1.无法命名构造器。构造器的名字必须与类名相同。但是,这里希望得到的货币实例和百分比实例采取不同的名字。
2.当时用构造器时,无法改变构造的对象类型。而Factory方法将返回一个DecimalFormat类对象,这是NumberFormat的子类。
代码块
public class StaticTest {
public static void main(String[] args) {
Employee[] staff=new Employee[3];
staff[0]=new Employee("Tom",40000);
staff[1]=new Employee("Dick",60000);
staff[2]=new Employee("Harry",65000);
for(Employee e:staff) {
e.setId();
System.out.println("name="+e.getName()+",id="+e.getId()+",salary="+e.getSalary());
}
int n=Employee.getNextId();
System.out.println("Next avaiable id="+n);
}
}
class Employee{
private static int nextId=1;
private String name;
private double salary;
private int id;
public Employee(String n,double s) {
name=n;
salary=s;
id=0;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public int getId() {
return id;
}
public void setId() {
id=nextId;
nextId++;
}
public static int getNextId() {
return nextId;
}
public static void main(String[] args) {
Employee e=new Employee("Harry",50000);
System.out.println(e.getName()+" "+e.getSalary());
}
}
方法参数
Java程序设计语言总是采用按值调用。
即方法得到的所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
this
关键字this引用的方法是隐式参数。
代码块
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) {
x.raiseSalary(200);
System.out.println("Emd 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{
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;
}
}
重载
如果有多个方法(比如,StringBuilder构造器方法)有相同的名字、不同的参数,便产生了重载。
不能有两个名字相同、参数类型也相同却反悔不同类型值的方法。
无参数构造器
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器。这个构造器将所有的实例域设置为默认值。于是,实例域中的数值型数据设置为0、布尔型数据设置为false、所有对象变量设置为null。
代码块
import java.util.Random;
public class ConstructorTest {
public static void main(String[] args) {
Employee[]staff=new Employee[3];
staff[0]=new Employee("Harry",40000);
staff[1]=new Employee(60000);
staff[2]=new Employee();
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 {
Random generator=new Random();
//between 0 - 9999
nextId=generator.nextInt(10000);
}
//object initialization block
{
id=nextId;
nextId++;
}
public Employee(String n,double s) {
name=n;
salary=s;
}
public Employee(double s) {
//Call the Employee(String,double) constructor
this("Employee #"+ nextId, s);
}
public Employee(){
}
public String getName(){
return name;
}
public double getSalary() {
return salary;
}
public int getId() {
return id;
}
}
定义子类
关键字extends表名正在构造的新类派生于一个已存在的类。已存在的类称为超类(superclass)、基类(baseclass)或父类(parent class);新类称为子类(subclass)、派生类(derived class)或孩子类(child class)。
应该将通用的方法放在超类中,而将具有特殊用途的方法放在子类中。
覆盖方法
超类中有些方法对子类Manager并不一定适用。具体来说,Manager类中的getSalary方法应该返回薪水和奖金的总和。为此需要提供一个新的方法来覆盖(override)超类中的这个方法。可以使用特定的关键字super解决这个问题。例:super.getSalary();