当我们在设计类的时候 发现多个对象中有共享数据的时候 我们就可以把这个共享的数据 定义为静态的。
下面name age虽然每个对象都有 但是值不一定一样 对象的特有数据->成员变量grade虽然每个对象也都有 但是值一样 对象的共有数据-> 静态变量,静态的东西从堆中对象的空间里抽取放到静态方法区,这样在对象创建的过程中可以节省空间。
/*假如有三个学生,他们的年龄,名字可能相同,也可让能不相同,但是他们来自于同一年级,我们就可以将他们的年纪设置成静态的*/
class Test1{
public static void main(String [] args){
Grade stu1=new Grade("alice",15);
Grade stu2=new Grade("Tom",15);
Grade stu3=new Grade("Luce",16);
System.out.println(stu1.name);//1.先去堆内存中对象的所属空间里找,结果找到了
System.out.println(stu1.age);//1.先去堆内存中对象的所属空间里找,结果找到了
/*1.先去堆内存中对象的所属空间里找,没有找到,再去静态 方法区中该对 象所属类的空间里找*/
System.out.println(stu1.grade);
System.out.println(stu2.grade);
System.out.println(stu3.grade);
}
}
class Grade{
String name; //姓名
int age; //年龄
static int grade=3; //年级
public Grade(String name1,int age1){
name=name1;
age=age1;
}
}
静态变量与成员变量的区别:
静态变量 | 成员变量 | |
生命周期 | 静态变量随着类的加载而创建 随着程序结束而消失 | 成员变量随着对象的创建而创建 随着对象的消亡而消亡 |
调用方式 | 静态变量可以被对象调用 也可以直接用类调用 | 成员变量必须先创建对象 在通过对象去调用 |
存储位置 | 静态变量存在于静态方法区中类的所属空间里 | 成员变量存在于堆内存中对象的所属空间里 |
命名 | 成员变量-对象的特有属性 | 静态变量-对象的共有属性 |
思考:静态变量的存在是因为有共享的数据那么静态函数意味着就是对象的共有行为吗?
回答:不是的,每一个对象他的行为的具体的实现方式可能是不一样的,所以,静态函数不可能是对象的共有行为。
1.静态函数 只能访问静态的成员变量 如果访问非静态成员变量 那么无法通过编译,
非静态方法 既能访问静态的成员变量,也能访问非静态的成员变量
class Test1{
public static void main(String [] args){
Grade stu1=new Grade("alice",15);
Grade stu2=new Grade("Tom",15);
Grade stu3=new Grade("Luce",16);
stu1.show_age();//静态函数调用非静态变量
}
}
class Grade{
String name; //姓名
int age; //年龄
static int grade=3; //年级
public Grade(String name1,int age1){
name=name1;
age=age1;
}
public static void show_age(){
System.out.println("age"+age);
}
}
编译报错:
2.无需创建对象, 静态也称之为是类的成员,我们可以直接通过类去调用静态函数。
调用方法: 类.静态函数
非静态函数需要先创建对象,再通过对象掉用成员函数
class Test1{
public static void main(String [] args){
Grade stu1=new Grade("alice",15);
Grade stu2=new Grade("Tom",15);
Grade stu3=new Grade("Luce",16);
System.out.println("通过类调用grade结果是:"+Grade.grade);
}
}
class Grade{
String name; //姓名
int age; //年龄
static int grade=3; //年级
public Grade(String name1,int age1){
name=name1;
age=age1;
}
}
3.静态函数中不存在this关键字,因为this关键字表示当前对象的地址,静态函数跟对象无关。
提到静态代码块先讲一下代码块:
代码块 { ... }
局部代码块:存在于函数当中(包括函数) for(){...} if(){...}
构造代码块:直接在类中出现的{...}
当对象创建一次 构造代码块执行一次
作用等同于构造函数静态代码块:直接在类中出现的static{...}
当类被加载的时候 仅且只执行一次
作用于 对类进行一些初始化操作 JDBC
静态代码块的用途例子:
单例模式:使用场景是 某一个类只能创建一个对象,比如某一个朝代的皇帝 只能是唯一的。
1.既然只能创建一个对象的话 就得不能让外界去创建对象
限制使用new不现实
只能从对象的创建流程中考虑 只要有一个步骤不行 对象就创建不出来
开辟空间分配地址 是由计算机底层决定 我们也控制不了
构造函数执行 只需要将构造函数私有化即可
2.既然外界不能创建对象 我们还得保证对象的创建
所以我们只能在类内部创建对象
Single s=new Single(); 将Single s=new Single()写成静态函数,这样当类被加载的时候 仅且只执行一次。
为了保护数据成员我们将Single s=new Single()写成私有的,通过接口实现对其的访问
3.内部创建出对象 还得向外界提供
因为private 外界不能直接访问
所以向外界提供一个函数 外界通过调用函数获取对象
class SingleTest{
public static void main(String[] args){
Single s1=Single.getInstance();//通过接口实现创建对象
Single s2=Single.getInstance();
Single s3=Single.getInstance();
System.out.println(s1==s2);//判断对象s1和对象s2是否为同一个对象
System.out.println(s2==s3);//判断对象s3和对象s2是否为同一个对象
}
}
class Single{
private static Single s=new Single();/*将Single s=new Single()写成静态函数,这样当类被加载的时候 仅且只执行一次。为了保护数据成员我们将Single s=new Single()写成私有的,通过接口实现对其的访问*/
private Single(){}
public static Single getInstance(){
return s;
}
}