前言
对象都有name和age两个状态;
也就是说不同对象的name和age是不同的;但是在生活中有些东西不是属于某一个具体对象的,而是属于整个事务的类型。
比如:全世界人的总数,人的毁灭行为。
————————————————————————
状态和行为应该又对象和类型之分。
有的状态和行为应该属于对象,状态和行为可以不一样;
有的状态和行为应该属于类型,不属于对象。
问题:如何表示人类毁灭这个行为(destory)
那么就要用到static修饰符
————————————————————————
static修饰符特点
static修饰符表示静态的,可修饰字段,方法,内部类,其修饰的成员属于类,也就说static修饰的资源属于类,而不是对象。
所以static的真正作用:用来区分字段,方法,内部类,初始化代码块是属于对象还是属于类本身。
(1)static修饰的成员(字段/方法),随着所在类的加载而加载
当JVM把字节码文件加载进JVM的时候,static修饰的成员就已经在内存中存在了。
(2)优先于对象的存在
对象是我们手动通过new关键字创建出来的
(3)static修饰的成员被该类型的所有对象所共享
根据该类创建出来的任何对象,都可以访问static成员(猫天生爱吃鱼)
(4)直接使用类名访问static成员
因为static修饰的成员直接属于类,而不属于对象,所以可以直接使用类名访问static成员。
代码如下:
class Person
{
String name;
int age;
static int totalNum = 5;
// 自定义构造器
Person(String name, int age){
this.name = name;
this.age = age;
totalNum++;
}
}
class StaticDemo
{
public static void main(String[] args)
{
// 打印totalNum初始值,优先于对象的存在
System.out.println(Person.totalNum);
// 创建一个新的对象
Person p1 = new Person("Li",16);
// 打印当前totalNum值
System.out.println(Person.totalNum);
}
}
---------- 运行java ----------
5
6
输出完成 (耗时 0 秒) - 正常终止
class Person
{
String name;
int age;
static int totalNum = 5;
Person(String name, int age){
this.name = name;
this.age = age;
totalNum++;
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person p1 = new Person("Li",16); // 6
Person p2 = new Person("wang",18); // 7
System.out.println(Person.totalNum);
System.out.println(p1.totalNum); // p1.totalNum低层其实就是Person.totalNum
System.out.println(p2.totalNum); //同样,p2.totalNum低层其实就是Person.totalNum
}
}
---------- 运行java ----------
7
7
7
输出完成 (耗时 0 秒) - 正常终止
最后两行代码虽然用对象名调用了static修饰的totalNum变量,但是低层依然使用的类名来调用的。假如我们在只能的IDE开发工具中写这样的代码,工具一般会给我们警告的!
但是不能用类名直接调用非static方法!因为,static定义的方法和成员变量属于类,不属于对象,非static定义的方法和变量才属于对象! 如下代码:
class Person
{
String name;
int age;
static int totalNum = 5;
Person(String name, int age){
this.name = name;
this.age = age;
totalNum++;
}
void die(){
totalNum--;
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person.die();// 编译会报错,不能直接用类名调用非static方法!
}
}
---------- 编译java ----------
StaticDemo.java:30: 错误: 无法从静态上下文中引用非静态 方法 die()
Person.die();
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
static成员在JVM中的存储:
totalNum 该成员属于类,而非对象,随着字节码文件的加载就加载到了方法中,而不存在堆中
类成员和实例成员的访问
类中的成员:字段,方法,内部类;
类成员:使用static修饰的成员;
实例成员:没有使用static修饰符的成员;
1.类成员只能访问类成员,实例成员只能访问实例成员。代码证明如下:
class Person
{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
}
class StaticDemo
{
public static void main(String[] args)
{
String name = Person.name; //编译报错,不能使用类名访问非static成员,将Person类中的name字段使用static修饰才可以!
}
}
StaticDemo.java:9: 错误: 找不到符号
totalNum++;
^
符号: 变量 totalNum
位置: 类 Person
StaticDemo.java:18: 错误: 无法从静态上下文中引用非静态 变量 name
String name = Person.name; //编译报错,不能使用类名访问非static成员
^
2 个错误
输出完成 (耗时 0 秒) - 正常终止
2.类成员直接属于类,可以通过类来访问static字段和static方法;
3.实例成员只属于对象,通过对象来访问非static和非static方法;
(对象其实是可以访问类成员(static修饰的成员),但是低层依然使用类名访问的)
4.在static方法中,只能调用static成员。证明代码如下:
class StaticDemo
{
String info = "Hello";
public static void main(String[] args)
{
System.out.println(info); // 编译报错,static方法不能调用非static成员
}
}
---------- 编译java ----------
StaticDemo.java:18: 错误: 无法从静态上下文中引用非静态 变量 info
System.out.println(info);
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
5.非static方法,可以访问静态成员(static),也可以访问实例成员(非static);
class Person
{
String name;
static int age; // 使用static修饰age
Person(String name, int age){
this.name = name;
this.age = age;
}
public void print1(){
// 非static 修饰的方法可以访问非static字段和static字段
System.out.println(name);
System.out.println(age);
}
// 定义一个static修饰的方法
public static void print2(){
System.out.println(age); //static 修饰的方法只能访问static字段
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person p = new Person("LiMing",18);
p.print1();
p.print2();
}
}
---------- 运行java ----------
LiMing
18
18
输出完成 (耗时 0 秒) - 正常终止
什么时候定义成static的字段和方法?
如果这个状态和行为属于整个事务(类),就直接使用static修饰,它被所有对象所共享。
在开发中,往往把工具方法使用static修饰,如果不使用static修饰,则这些方法属于该类的实例对象,我们得先创建对象再调用方法,在开发工具中,对象只需要一份即可,可能创建N个对象,此时我们往往把该类设计为单例的,但是还是有些麻烦。
因此,在开发中设置工具方法时,为了简单,我们使用static修饰。
类成员的使用:
好处: 对象的共享数据进行单独空间的存储,可以节省空间,直接被类名调用,没有必要每个对象中都存储一份;
弊端: 生命周期过长。