静态域与静态方法
静态域
静态修饰符为static。
如果一个域被定义为静态域,那么一个类中只能有一个静态域。而每一个对象的所有实例域都有自己的一份拷贝。例如:
class Employee
{
private static int nextid=1;
private int id;
}
我们现在创建100个Employee类的对象,那么对于这100个Employee类的对象,则有100个实例域id。它们一一对应。但是,它们共享一个静态域nextid。即使,没有一个Employee对象,静态域nextid也存在。他属于类,但是不属于任何一个对象。
静态常量
静态变量使用的比较少,一般来说,都是使用静态常量。比如说,Math中的PI
public class Math
{
.......
public static final double PI=3.14159263589;
.......
}
所以,我们才能在程序中使用Math.PI的形式调用这个常量。
另一个我们经常使用的静态常量是System.out。它在System类中的声明:
public class System
{
...
public static final PrintStream out=...;
....
}
之前说过,由于每个类的对象都可以对于公有域进行修改。所以,域尽量不要声明为public。但是,公有常量(即final域)没有问题。因为out被final修饰,不允许将其他打印流赋给它。
静态方法
只有静态才能调用静态。这是一定要注意的。
静态方法是一种不能向对象实施操作的方法。例如,Math的pow方法。
我们可以认为静态方法是没有this参数的方法(在一个非静态方法中,this参数表示这个方法的隐式参数.)
Employee类中的静态方法不能访问Id实例域,因为它不能操作对象。但是,静态方法可以访问自身类中的静态域。例如:
public static int getNextId(){
return nextId;
}
可以通过类名调用这个方法。
int n=Employee.getNextId();
在下面的两种情况使用静态方法:
- 一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(Math.pow())
- 一个方法只需要访问类的静态域(例如:Employee.getNextId())
main方法
需要注意,不需要使用对象调用静态方法。main方法也是个静态方法。main方法不对任何对象进行操作。事实上,在启动程序的时候还没任何一个对象。静态的main方法将执行并创建程序所需要的对象。每一个类可以有一个main方法。这是一个常用于对类进行单元测试的技巧。
我们写一个程序,体会一下静态的使用。
public class test1 {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("aaa", 500);
staff[1] = new Employee("bbb", 200);
staff[2] = new Employee("ccc", 400);
for (Employee employee : staff) {
employee.setId();
System.out.println(employee.getName()+" "+employee.getId()+" "+employee.getSalary());
}
int i = Employee.getnextid();
System.out.println(i);
}
}
public class Employee {
private static int nextid=1;
private String name;
private int id ;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId() {
id=nextid;
nextid++;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public static int getnextid(){
return nextid;
}
public static void main(String[] args) {
Employee harry = new Employee("harry", 500);
System.out.println(harry.getName()+" "+harry.salary);
}
}
方法参数
在程序设计语言当中,有关参数传递给方法的方法有两类。其中,Java用的是按值调用,表示方法接收的是调用者提供的值。也就是说,方法得到的是所有参数值的一个拷贝 ,特别的是,方法不能修改传递给它的任何参数变量内容。例如:
double percent=10;
harry.raiseSalary(percent);
在方法调用之后,percent的值还是10。
我们来剖析一下这种情况。
public static void test(){
x=3*x;
}
调用这个方法:
test(percent);
调用之后,percent的值还是10。
下面看一下具体执行:
- x被初始化为percent值的一个拷贝。(10)
- x被乘3后等于30.但是,percent还是10,拷贝的x为30。
- 这个方法结束之后,参数变量x不再使用,被舍弃。
然而,方法参数的基本类型有两种:
- 基本数据类型
- 对象引用
从以上看出,一个方法不可能修改一个基本数据类型。但是,对象引用作为参数就不一样。例如:
public static void test(Employee x) {
x.raiseSalary(200);
}
harry=new Employee (“aaaa”,120);
test(harry);
调用之后,一个雇员的薪金就提高了两倍。
具体执行过程为:
- x被初始化为harry值的拷贝,这里是一个对象的引用。
- raiseSalary方法应用用于这个对象的引用。x和harry同时引用的那个Employee 对象的薪金提高了200%。
- 方法结束后,x被抛弃。但是,harry继续引用那个薪金增至3倍的雇员对象。
从上面可以看出,Java程序设计语言对对象采用的不是引用调用,事实上,对象引用是按值传递的。
我们总计一下Java中方法参数的使用情况:
- 一个方法不能修改一个基本数据类型的参数。(数值型和布尔型)
- 一个方法可以改变一个对象参数的状态
- 一个方法不能让对象参数引用一个新的对象
我们以一个程序来总结一下:
/**
* @Author: 13679
* @CreateTime: 2019-10-26 16:12
*/
public class test0 {
public static void main(String[] args) {
System.out.println("Testing tripleValue:");
double percent=10;
System.out.println("before percent is "+percent);
tripleValue(percent);
System.out.println("after percent is " + percent);
System.out.println();
System.out.println("----------------------");
System.out.println("testing tripleSalary:");
Employee aaa = new Employee("aaa", 500);
System.out.println("before salary is "+aaa.getSalary());
tripleSalary(aaa);
System.out.println("after salary is " + aaa.getSalary());
System.out.println("");
System.out.println("-----------------------");
System.out.println("testing swap:");
Employee bbb = new Employee("bbb", 999);
Employee ccc = new Employee("ccc", 888);
System.out.println("before bbb is name "+bbb.getName());
System.out.println("before ccc is name " + ccc.getName());
System.out.println();
swap(bbb,ccc);
System.out.println();
System.out.println("after bbb is name " + bbb.getName());
System.out.println("after ccc is name " + ccc.getName());
}
public static void tripleValue(double x){
x=3*x;
System.out.println("End of method:x="+x);
}
public static void tripleSalary(Employee x){
x.raiseSalary(200);
System.out.println("End of method: salary="+x.getSalary());
}
public static void swap(Employee x,Employee y){
Employee z=x;
x=y;
y=z;
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 name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public void raiseSalary(double x){
double raise=salary*x/100;
salary+=raise;
}
}
.