零基础学Java(12)静态字段与静态方法
静态字段与静态方法
之前我们都定义的main方法都被标记了static修饰符,那到底是什么意思?下面我们来看看
静态字段
如果将一个字段定义为static,每个类只有一个这样的字段。而对于非静态的实例字段,每个对象都有自己的一个副本。例如,假设需要给每一个员工赋予唯一的标识码。这里给Employee类添加一个实例字段id和一个静态字段nextId:
class Employee {
// 定义静态字段nextId
private static int nextId = 1;
private int id;
}
现在,每一个Employee对象都有一个自己的id字段,但这个类的所有实例将共享一个nextId字段。换句话说,如果有1000个Employee类对象,则有1000个实例字段id,分别对应每一个对象。但是,只有一个静态字段nextId。即使没有Employee对象,静态字段nextId也存在。它属与类,而不属于任何单个的对象。
下面实现一个简单的方法:
public void setId() {
id = nextId;
nextId++;
}
假定为harry设置员工标识码:
harry.setId();
harry的id字段被设置为静态字段nextId当前的值,并且静态字段nextId的值加1:
harry.id = Employee.nextId;
Employee.nextId++
静态常量
静态变量使用的比较少,但静态常量却很常用。例如,在Math类中定义一个静态常量:
public class Math {
...
public static final double PI = 3.14159265358979323846;
...
}
在程序中,可以用Math.PI来访问这个常量。
如果省略关键字static,PI就变成了Math类的一个实例字段。也就是说,需要通过Math类的一个对象来访问PI,并且每一个Math对象都有它自己的一个PI副本。
你已经多次使用的另一个静态常量是System.out。它在System类中声明如下:
public class System {
...
public static final PrintStream out = ...;
...
}
前面曾经多次提到过,由于每个类对象都可以修改公共字段,所以,最好不要有公共字段。然而,公共常量(即final字段)却没问题。因为out被声明为final,所以,不允许再将它重新赋值为另一个打印流:
System.out = new PrintStream(...); // ERROR -- out is final
静态方法
静态方法是不在对象上执行的方法。例如,Math类的pow方法就是一个静态方法。表达式Math.pow(x, a)会计算幂x的a次方。在完成运算时,它并不使用任何Math对象。换句话说,它没有隐式参数。
可以认为静态方法是没有this参数的方法(在一个非静态的方法中,this参数指示这个方法的隐式参数)
Employee类的静态方法不能访问id实例字段,因为它不能在对象上执行操作。但是,静态方法可以访问静态字段。下面是这样一个静态方法的示例:
public static int getNextId() {
return nextId; // returns static field
}
可以提供类名来调用这个方法:
int n = Employee.getNextId();
这个方法可以省略关键字static吗?答案是肯定的。但是,这样一来,你就需要通过Employee类对象的引用来调用这个方法。
注意:可以使用对象调用静态方法,这是合法的。例如,如果harry是一个Employee对象,可以用harry.getNextId()代替Employee.getNextId()。不过,这种写法很容易造成混淆,其原因是getNextId方法计算的结果与harry毫无关系。我们建议使用类名而不是对象来调用静态方法。
在下面两种情况下可以使用静态方法:
- 方法不需要访问对象状态,因为它需要的所有参数都通过显式参数提供(例如:Math.pow)
- 方法只需要访问类的静态字段(例如:Employee.getNextId)。
工厂方法
静态方法还有另外一种常见的用途。类似LocalDate和NumberFormat的类使用静态工厂方法来构造对象。我们之前使用过工厂方法LocalDate.now和LocalDate.of。NumberFormat类如下生成不同风格的格式化对象:
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currencyFormatter.format(x)); // prints $0.10
System.out.printIn(percentFormatter.format(x)); // prints 10%
为什么NumberFormat类不利用构造器完成这些操作呢?这主要有两个原因:
- 无法命名构造器。构造器的名字必须与类名相同。但是,这里希望有两个不同的名字,分别得到货币实例和百分比实例。
- 使用构造器时,无法改变所构造对象的类型。而工厂方法实际上将返回
DecimalFormat类的对象,这是NumberFormat的一个子类。
main方法
需要注意,可以调用静态方法而不需要任何对象。例如,不需要构造Math类的任何对象就可以调用Math.pow
同理,main方法也是一个静态方法。
public class Application {
public static void main(String[] args) {
// construct objects here
...
}
}
main方法不对任何对象进行操作。事实上,在启动程序时还没有任何对象。静态的main方法将执行并构造程序所需要的对象。
提示:每一个类可以由一个main方法。这是常用于对类进行单元测试的一个技巧
例子
接下来我们创建Employee类,其中有一个静态字段nextId和一个静态方法getNextId。这里将三个Employee对象填入一个数组,然后打印员工信息。最后,打印出下一个可用的员工标识码来展示静态方法。
// 文件StaticTest.java
public class StaticTest {
public static void main(String[] args) {
System.out.println("1111");
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 available id=" + n);
}
}
class Employee {
// 静态字段nextId
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", 5000);
System.out.println(e.getName() + " " + e.getSalary());
}
}
这里我们定义了2个类StaticTest和Employee,这两个类分别有一个main函数
执行命令以下命令
java Employee
结果如下:
Harry 5000.0
当我们执行
java StaticTest
结果如下:
name=Tom, id=1, salary=40000.0
name=Dick, id=2, salary=60000.0
name=Harry, id=3, salary=65000.0
Next available id=4
两者会分别执行各自的main方法
零基础学Java(12)静态字段与静态方法的更多相关文章
- 零基础学Java第五节(面向对象一)
本篇文章是<零基础学Java>专栏的第五篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! 本文章首发于公众号[编程攻略] 类与对象 在哲学体系中,可以分为主 ...
- 零基础学Java第一节(语法格式、数据类型)
本篇文章是<零基础学Java>专栏的第一篇文章,从本篇文章开始,将会连更本专栏,带领大家将Java基础知识彻底学懂,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! ...
- 零基础学Java,PayPal技术专家手把手带你入门
在最权威的 TIOBE 编程语言排名榜单上,Java 常年稳居第一,可以说是世界上应用最为广泛的一门语言. 同时,在微服务.云计算.大数据.Android App 开发等领域,Java 也是当之无愧的 ...
- 零基础学Java第四节(字符串相关类)
本篇文章是<零基础学Java>专栏的第四篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! String 本文章首发于公众号[编程攻略] 在Java中,我们经 ...
- 零基础学Java第三节(基本输入输出)
本篇文章是<零基础学Java>专栏的第三篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! 本文章首发于公众号[编程攻略] Java程序的命令行参数 我们可以 ...
- 零基础学Java第二节(运算符、输入、选择流程控制)
本篇文章是<零基础学Java>专栏的第二篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! 第一章 运算符 1.1 算术运算符的概述和用法 运算符 对常量和变 ...
- 零基础学Java第六节(面向对象二)
本篇文章是<零基础学Java>专栏的第六篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! 本文章首发于公众号[编程攻略] 继承 创建一个Person类 我们 ...
- 零基础学Java(1)初识Java程序
前言 就国内来说,Java毫无疑问是后端语言中的No.1没有之一,所以今天我们也来0基础学习Java!!! Java的好处(针对测试工程师) 面试加分->涨薪 大多数公司服务端用的都是Java, ...
- 零基础学Java(14)对象构造
对象构造 之前学习了编写简单的构造器,可以定义对象的初始状态.但是,由于对象构造非常重要,所以Java提供了多种编写构造器的机制. 重载 有些类有多个构造器.例如,可以如下构造一个空的StringBu ...
随机推荐
- 项目文章|DNA(羟)甲基化研究揭示铁离子依赖表观调控促进狼疮致病性T细胞分化|易基因
易基因(羟)甲基化DNA免疫共沉淀测序(h)MeDIP-seq研究成果见刊<Journal of Clinical Investigation> 2022年5月2日,中南大学湘雅二医院赵明 ...
- Blazor和Vue对比学习(基础1.6):祖孙传值,联级和注入
前面章节,我们实现了父子组件之间的数据传递.大多数时候,我们以组件形式来构建页面的区块,会涉及到组件嵌套的问题,一层套一层.这种情况,很大概率需要将祖先的数据,传递给子孙后代去使用.我们当然可以使用父 ...
- python 批量探测服务端开放的TCP端口
现在大多服务器都有做icmp限制或直接禁掉,导致我们业务去连接服务器异常时无法判断是程序问题还是网络问题,所以写一个简单探测tcp端口脚本来探测服务器所开放的端口,再使用tcp测试双向时延来排掉网络问 ...
- spring boot 统一接口异常返回值
创建业务 Exception 一般在实际项目中,推荐创建自己的 Exception 类型,这样在后期会更容易处理,也比较方便统一,否则,可能每个人都抛出自己喜欢的异常类型,而造成代码混乱 Servic ...
- 运维:OAAS
IT和互联网运维的新篇章正要掀开,云计算和运维即服务(OaaS)正在为各类企业提供系统构建和扩展,帮助他们取得在线业务的成功. 互联网信息科技和运维一直在不断变化,包括了IT所覆盖的一切新工具.云.基 ...
- 关于我学git这档子事
创建本地分支并切换到该分支 git checkout -b *** 相当于如下2个命令: git branch *** git checkout *** 推送本地开发分支到远程开发分支 git pus ...
- Jmeter接口参数化<自动化>(csv文件)管理测试用例以及断言
1.创建相关线程组(不解释) 2.创建相应的请求(在请求中设置变量) 下面截图中①②③④⑤⑥⑦皆可以设置为变量 3.新建CSV文件 将请求中设置的变量为明确了解每个字段的含义(皆可以将变量填写到列表的 ...
- 2021.05.29【NOIP提高B组】模拟 总结
T1 题意:给你一个图,可以不花代价经过 \(K\) 条边,问从起点到终点的最短路 考试的想法:设 \(dis_{i,j}\) 表示从起点免费了 \(j\) 条边到 \(i\) 的最短路 然后直接跑 ...
- Linux/Ubuntu 安装Redis
更新记录 2022年6月15日 发布. 2022年6月12日 开始编写. 安装Redis 更新源 sudo apt update 安装redis sudo apt install redis-serv ...
- Spire.Office激活
更新记录: 2022年5月28日 初始代码便于复用 注意:最多支持到:E-ICEBLUE Spire.Office Platinum v6.10.3 引入命名空间: using Spire.Licen ...