目录
一个例子引出static关键字
class Human {
//姓名
private String name;
//年龄
private int age;
//国籍
// private String country;
private static String country;
public Human() {
}
public Human(String name, int age) {
this.name = name;
this.age = age;
}
public Human(String name, int age, String country) {
this.name = name;
this.age = age;
this.country = country;
}
public void setCountry(String country) {
Human.country = country;
}
public void show() {
System.out.println("姓名:" + name + ",年龄:" + age + ",国籍:" + country);
}
}
public class HumanDemo {
public static void main(String[] args) {
//创建第一个对象
Human h1 = new Human("张杰", 42, "中国");
h1.show();
//创建第二个对象
Human h2 = new Human("彭于晏", 38);
h2.show();
//创建第三个对象
Human h3 = new Human("蔡徐坤", 22);
h3.show();
h3.setCountry("加拿大");
h1.show();
h2.show();
h3.show();
}
}
我们定义完并使用后发现,姓名和年龄不一样的,我们可以理解。但是我们选的几个人的国籍都是中国,这样我们每次在创建的时候,都会在堆内存中开辟这样的成员变量的内存空间。这样就造成了内存浪费。
针对于多个对象有着共同的成员变量,值是一样的情况,java就提供了一个关键字给我们使用——static关键字
static关键字
1.static关键字特点:可以修饰成员变量和成员方法
1)随着类的加载而加载
2)优先于对象而存在
3)被类的所有对象共享(举例:所有中国人的国籍信息都是一样的)
4)可以通过类名调用(一般情况下,只要我们看到一个类中有静态修饰的成员变量或者成员方法,一律推荐使用 类名.静态成员 这种方式去使用)
注:静态修饰的内容我们一般称之为类成员,与类相关的
class Student2 {
//非静态的成员变量
int num = 20;
//静态的成员变量
static int num2 = 30;
}
public class StaticDemo1 {
public static void main(String[] args) {
Student2 s1 = new Student2();
System.out.println(s1.num); //20
System.out.println(s1.num2); //30
System.out.println(Student2.num2); //30
}
}
2.什么时候使用static关键字呢?
如果某个成员变量是被所有的对象共享的时候,即值是一样的
3.static关键字注意事项
1)在静态方法中是没有this关键字的
this代表当前调用该方法的对象,static修饰的成员是优先于对象而存在的
static修饰的成员是随着类的加载而加载的,这时候好没有对象产生,也就说明没有this关键字
所以在静态方法中无法使用this关键字
2)静态方法只能访问静态的成员方法
class Student3 {
private String name;
private int age;
private static int a;
// public static int getAgeAgain(){
// return this.age; 报错
// }
public static void fun1() {
//尝试访问非静态的成员变量name
//无法从静态上下文中引用非静态 变量 name
// System.out.println(name); 报错
//尝试访问静态的成员变量a
//静态的成员方法可以访问静态成员变量
System.out.println(a);
//尝试访问非静态的成员方法show()
//无法从静态上下文中引用非静态 方法 show()
//静态的成员方法不能访问非静态的成员方法
// show();
//尝试访问静态的成员方法function()
//静态的成员方法可以访问静态的成员方法
function();
}
public void fun2() {
//尝试访问非静态的成员变量name
//非静态的成员方法可以访问非静态的成员变量name
System.out.println(name);
//尝试访问静态的成员变量a
//非静态的成员方法可以访问静态的成员变量a
System.out.println(a);
//尝试访问非静态的成员方法show()
//非静态的成员方法可以访问静态的成员方法
show();
//尝试访问静态的成员方法function()
//非静态的成员方法可以访问静态的成员方法
function();
}
public static void function() {
}
public void show() {
System.out.println(name + "----" + age);
}
}
public class StaticDemo2 {
public static void main(String[] args) {
}
}
static在内存中的解释
以最上方的案例为例子
Step1:程序先将class文件(Human.class,HumanDemo.class)加载到方法区中的class文件区
Human.class文件区的内容:成员变量,成员方法
HumanDemo.class文件区的方法:成员变量,成员方法
Step2:把每个class文件的方法加载到方法区
Human.class中方法区的内容:构造方法,show()方法,setCountry(String country)(假设这一部分地址值为0x001)
静态区:
Human的静态区内容:静态的成员变量country(随着类的加载而加载,此时默认值为null),静态的成员方法(假设这一部分地址值为0x01)
HumanDemo的静态区内容:静态的成员变量,静态的成员方法main()(假设这一部分地址值为0x02)
Step3:加载完毕,java虚拟机寻找到java的唯一入口main方法,去静态区中找,如果找到了将它加载到栈中去执行
Step4:读到Human h1在栈中开辟空间,读到new Human在堆里面开辟空间(一个创建对象里面包括name,age,静态标记0x01,方法标记0x001)
Step5:一开始创建出来的对象,系统给默认值:name=null,age=0;然后看显示赋值(没有,跳过),继续看构造方法赋值("张杰",42,"中国")(country赋值:按照静态标记0x01找到静态成员变量country,把中国赋给它)(假设在堆中创建对象的地址值为0x0001),有个隐含的this指向0x0001这个区域。初始化值全部都有结束以后,将地址值0x0001赋给栈中的变量h1(变量h1就能通过地址值找到对象在堆内存中的区域)
Step6:读到h1.show();按照h1地址值0x0001找到堆内存中的区域,找到name(张杰),age(42),按照静态标记0x01找到静态区中的country(中国)
Step7:读到Human h2在栈中开辟空间,读到new Human在堆里面开辟空间(一个创建对象里面包括name,age,静态标记0x01,方法标记0x001)
Step8:一开始创建出来的对象,系统给默认值:name=null,age=0;然后看显示赋值(没有,跳过),继续看构造方法赋值("彭于晏",38)(假设在堆中创建对象的地址值为0x0002),有个隐含的this指向0x0002这个区域。初始化值全部都有结束以后,将地址值0x0002赋给栈中的变量h2(变量h2就能通过地址值找到对象在堆内存中的区域)
Step9:读到h2.show();按照h2地址值0x0002找到堆内存中的区域,找到name(彭于晏),age(38),按照静态标记0x01找到静态区中的country(中国)
Step10:读到Human h3在栈中开辟空间,读到new Human在堆里面开辟空间(一个创建对象里面包括name,age,静态标记0x01,方法标记0x001)
Step11:一开始创建出来的对象,系统给默认值:name=null,age=0;然后看显示赋值(没有,跳过),继续看构造方法赋值("蔡徐坤",22)(假设在堆中创建对象的地址值为0x0003),有个隐含的this指向0x0003这个区域。初始化值全部都有结束以后,将地址值0x0003赋给栈中的变量h3(变量h3就能通过地址值找到对象在堆内存中的区域)
Step12:读到h3.show();按照h3地址值0x0003找到堆内存中的区域,找到name(蔡徐坤),age(22),按照静态标记0x01找到静态区中的country(中国)
......
静态变量与成员变量的区别
1.所属不同
静态变量属于类,所以也称为类变量
成员变量属于对象,所以也称为实例对象(对象变量)
2.内存中位置不同
静态变量存储于静态区的而方法区
成员变量存储于堆内存
3.内存中出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而创建,随着对象的消失而消失
4.调用不同
静态变量可以通过类名调用,也可以通过对象调用
成员变量只能通过对象名调用
main方法的格式讲解
1.public:公共的,访问权限是最大的,因为main是由JVM调用的,所以权限要足够大
2.static:静态的,不需要创建对象,通过类名直接调用,方便JVM访问
3.void:表示无返回值,因为返回值是返回给调用者的,而main方法是由JVM调用的,返回给它没有意义
4.String[] args:参数是一个字符串数组,数组的形参名是args
这个怎么么用呢?如何传参呢?值去哪里了呢?
JDK1.5之前,没有Scanner键盘录入的时候,程序员就是借助args传参
怎么用呢?
1.IDEA可以直接传参
2.命令传参
java 类名 参数