1 类变量
1.1 简要介绍
由一个简单的程序引出:
public class Example1 {
int n;
static int num = 10; //有 static 修饰
//此时 num 即为一个类变量(静态变量),static 表示静态的
//这个变量的最大特点是,它会被 Example 类的所有对象实例,共享
public Example1(int n) {
this.n = n;
}
}
建立一个测试例:
public class Test {
public static void main(String[] args) {
//创建2个对象
Example1 exam1 = new Example1(3);
Example1 exam2 = new Example1(4);
System.out.println(exam1.n);//输出3
System.out.println(exam2.n);//输出4
System.out.println(exam1.num);//输出10
System.out.println(exam2.num);//输出10
System.out.println(Example.num);//输出10
}
}
在上面的测试例中,我们创建了2个对象 exam1、exam2,每个对象在创建时都会独立的创建一个属于自己的属性 n, 而不会创建静态属性 num, 因为 num 是所有 Example 类的对象所共享的,n 是所有的对象独有的。
1.2 类变量的内存布局
书接上回,既然类变量不会随着对象的创建而创建,那么类变量在内存中的存在形式是什么呢?
关于静态变量存放的位置,主要有2种观点,一种说是在方法区,一种说是在堆区域,这和我们使用的jdk版本也有一定的关系。
有感兴趣的读者,可以参考以下2篇博客:
- https://blog.csdn.net/x_iya/article/details/81260154/
- https://www.zhihu.com/question/59174759/answer/163207831
对于本篇博客讨论的内容来说,我们需要记住的是:static 变量是所有对象共享的,不管 static 变量在哪里,共识是:
- static 变量是同一个类所有对象共享
- static 类变量,在类加载的时候就生成了,即类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问。
1.3 什么是类变量
1.3.1 定义
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取得的值都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量,相信看过上面类变量的内存布局会有更加深刻的认识。
1.3.2 类变量的定义语法
// 访问修饰符 static 数据类型 变量名;[推荐]
// static 访问修饰符 数据类型 变量名;
public static int n;
static public int m;
1.3.3 类变量的访问
// 类名.类变量名
// 对象名.类变量名 [静态变量的访问修饰符的访问权限和范围和普通属性是一样的]
Example1.num;
exam1.num;
类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问。
public class Test1 {
public static void main(String[] args) {
//类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问。
System.out.println(Example1.num);
}
}
1.4 类变量使用的注意事项
-
什么时候需要类变量?
当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量):比如:定义一个学生类,用来统计所有的学生需要交多少钱。
-
类变量与实例变量的区别。
类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
-
使用 static 进行修饰,称为类变量或者静态变量,否则称为实例变量/普通变量/非静态变量
-
类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,我们更推荐前一种。
-
实例变量不能通过 类名.类变量名 来进行访问,因为实例变量是每个对象所独有的。
-
类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了。
-
类变量的生命周期是随着类加载开始,随着类消亡而销毁。
2 类方法
2.1 基本介绍
类方法也叫静态方法,形式如下:
// 访问修饰符 static 数据返回类型 方法名() { } [更为推荐使用]
// static 访问修饰符 数据返回类型 方法名() { }
public class Example2 {
public static void f1() { }
static public int f2() { }
}
类方法的调用:
// 类名.类方法名
// 对象名.类方法名
public class Test2 {
public static void main(String[] args) {
Example2 a = new Example2();
a.f1();// 对象名.类方法名
Example2.f1();// 对象名.类方法名
}
}
2.2 什么时候使用类方法
- 如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用)。
以上是 Math 类中的源码,方法功能为开方,可以看出这个方法是静态方法,所以我们在日常使用中,一般直接通过类名调用即可。Math.sqrt(9);
-
当我们开发自己的工具类时,可以将自己的方法做成静态的,方便调用。
-
当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
比如:工具类(utils)中的方法
Mat 类、Arrays 类等
总结: 在实际开发中,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用,比如打印数组、排序等。
2.3 类方法使用的注意事项
-
类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:
-
类方法中无 this 的参数
-
普通方法中隐含着 this 的参数
-
public static void hi() {//静态方法,类方法
//类方法中不允许使用和对象有关的关键字,
//比如this 和 super。普通方法(成员方法)可以。
//System.out.println(this.n1);
}
- 类方法可以通过类名调用,也可以通过对象名调用。
Math.sqrt(9);//通过类名调用
Examle2 b = new Example2();
b.f1();//通过对象名调用
- 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用。
- 类方法(静态方法)中,只能访问静态变量或着静态方法。
class D {
private int n1 = 100;
private static int n2 = 200;
public void say() {//非静态方法,普通方法
}
public static void hi() {
System.out.println(n1);//访问非静态
System.out.println(n2);//访问静态
}
//类方法(静态方法)中 只能访问 静态变量 或静态方法
//口诀:静态方法只能访问静态成员.
public static void hello() {
System.out.println(n2);
System.out.println(D.n2);
//System.out.println(this.n2);不能使用
hi();//OK
//say();//错误,say()为非静态方法
}
- 普通方法既可以访问非静态成员,也可以访问静态成员。
总结: 静态方法,只能访问静态的成员和静态的方法;非静态的方法,可以访问静态的成员和非静态的成员。(都必须遵守访问权限)
3 理解 main 方法
3.1 main方法的执行
解释 main 方法的形式:public static void main(String[] args) { }
- main 方法是由虚拟机调用的
- java虚拟机需要调用类的 main() 方法,所以该方法的访问权限必须是 public
- javaz虚拟机在执行 main() 方法时不必创建对象,所以该方法必须是 static
- 该方法接收 String 类型的数组参数,该数组中保存执行 java 命令时传递给所运行的类的参数。
- java 执行的程序 参数1 参数2 参数3 …
3.2 注意事项
- 在 main() 方法中,我们可以直接调用 main 方法所在类的静态方法或静态属性。
- 但是,在 main 中,不能直接访问该类的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。
public class Main {
//静态的变量/属性
private static String name="棐木";
//非静态的变量/属性
private int n1=10000;
//静态方法
public static void hi() {
System.out.println("我是静态方法hi");
}
//非静态方法
public static void cry() {
System.out.println("我是非静态方法cry");
}
public static void main(String[] args) {
//可以直接使用 name
//1. 静态方法main 可以访问本类的静态成员
System.out.println("name=" + name);//访问静态属性
hi();//访问静态方法
//2. 静态方法main 不可以访问本类的非静态成员
//System.out.println("n1=" + n1);//错误,不能访问非静态属性
//cry();//不能访问非静态方法
//3. 静态方法main 要访问本类的非静态成员,需要先创建对象 , 再调用即可
Main01 main01 = new Main01();
System.out.println(main01.n1);//ok
main01.cry()
}
}
3.3 IDEA 中向 main 中传递参数
由以下程序说明:
public class CommandPara {
public static void main(String[] args) {
//输出args 数组
for(int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
在 IDEA 中向 main 传参步骤: