Java 面向对象之 static 关键字
static 特点
- static 是一个修饰符, 用于修饰成员
- static 修饰的成员被所有的对象所共享
- static 优先于对象存在, 因为 static 的成员随着类的加载就已经存在了
- static 修饰的成员多了一种调用方式, 即可以直接被类名所调用, 类名.静态成员
- static 修饰的数据是共享数据, 对象中存储的是特有数据.
成员变量(实例变量)与静态变量(类变量) 的区别
- 两个变量的生命周期不同
成员变量随着对象的创建而存在, 随着对象的被回收而释放
静态变量随着类的加载而存在, 随着类的消失而消失 - 调用方式不同
成员变量只能被对象调用
静态变量可以被对象调用, 还可以被类名调用 - 别名不同
成员变量也称为实例变量
静态变量也称为类变量 - 数据存储位置不同
成员变量数据存储在堆内存的对象中, 所以也叫对象的特有数据
静态变量数据存储在方法区(共享数据区)的静态区, 所以也叫对象的共享数据
静态使用注意事项
- 静态方法只能访问静态成员(包括成员变量和成员函数), 非静态方法即可以访问静态成员, 也可以访问非静态成员.
- 静态方法中不可以使用 this 或者 super 关键字.
- 主函数是静态的, 所以只能访问静态方法和静态变量.
- 静态前面省略的是类名, 非静态前面省略的是 this
备注:- 主函数是静态的, 所以只能访问静态方法和静态变量.
public Demo
{
int num = 4;
public static void main(String[] args)
{
show();
}
public void show()
{
System.out.println(num);
}
}
// 编译失败, show() 方法和成员变量 num 都是非静态的.
// 改进
public Demo
{
int num = 4;
public static void main(String[] args)
{
new Demo().show(); // 使用对象调用 show() 方法
}
public void show()
{
System.out.println(num);
}
}
2. 静态前面省略的是类名, 非静态前面省略的是 this
class Person
{
public static void main(String[] args)
{
String name;
static String country = "CN";
public void show()
{
System.out.println(country+":"+name);
// 完整写法: System.out.println(Person.country+":"+this.name);
}
}
}
主函数解析
- 格式:
public static void main(String[] args)
- 主函数特殊之处
- 格式是固定的
- 被 JVM 所识别和调用
public: 因为权限必须是最大的;
static: 不需要对象, 直接用主函数所属类名调用即可
void: 主函数没有具体的返回值
main: 函数名, 不是关键字, 只是 JVM 识别的固定的名字
String[] args: 这是主函数的参数列表, 是一个数组类型的参数, 而且元素都是字符串类型
虚拟机调用主函数时, 传递了参数 new String[0].
static 内存图解
class Person
{
private String name;
private int age;
static String country = "CN";
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
public void show()
{
System.out.println(Person.country+":"+this.name+":"+this.age);
}
public static void method()
{
System.out.println(Person.country);
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person.method(); // 使用类名调用静态方法
Person p = new Person("旺财",20);
p.show();
}
}
静态什么时候使用?
- 静态变量
当分析对象中所具备的成员变量的值都是相同的, 这时这个成员就可以被静态修饰.
只有数据在对象中都是不同的, 那就是对象的特有数据, 必须存储在对象中, 是非静态的.
如果是相同的数据, 对象不需要作修改, 只需要使用即可, 不需要存储在对象中, 定义成静态的. - 静态函数
函数是否用静态修饰, 就参考一点, 就是该函数功能是否有访问到对象中的特有数据.
简单点说, 从源代码看, 该功能是否需要访问非静态的成员变量, 如果需要, 该功能就是非静态的.
如果不需要, 就可以将功能定义成静态的.当然, 也可以定义成非静态的.
但是非静态方法需要被对象调用, 而创建对象仅仅是为了调用非静态的, 非静态方法没有访问特有数据, 该对象的创建是没有意义的.
class Person
{
int age;
static String country = "CN";
public void speak()
{
System.out.println("haha");
}
}
class Demo
{
public static void main(String[] args)
{
Demo d = new Demo();
d.speak(); // 调用 speak() 方法需要创建对象, 但是 speak() 方法并没有访问特有数据, 对象的创建没有意义
}
}
// 改进
class Person
{
int age;
static String country = "CN";
public static void speak() // 将方法定义为静态的
{
System.out.println("haha");
}
}
class Demo
{
public static void main(String[] args)
{
Person.speak(); //使用类名调用该方法
}
}
静态代码块
特点: 随着类的加载而执行, 而且只执行一次.
作用: 用于给类进行初始化. 如果这个类的成员全是静态的, 并不需要创建对象.
public StaticCode
{
static // 静态代码块
{
System.out.println("haha");
}
void show()
{
System.out.println("show run");
}
}
class StaticCodeDemo
{
pulic static void main(String[] args)
{
new StaticCode().show();
}
}
构造代码块
定义: 定义在类中的代码块称为构造代码块
作用: 可以给所有对象初始化
构造函数: 是给对应的对象进行针对性的初始化.
局部代码块: 限定局部变量的生存周期. 定义在方法中.
执行顺序: 静态代码块先执行, 如果有对象, 执行构造代码块,再执行构造函数. 然后执行局部代码块
class Person
{
private String name;
Person()
{
name = "baby";
System.out.println("哇哇");
}
Person(String name)
{
this.name = name;
System.out.println("哇哇");
}
public void speak()
{
System.out.println("name:" + name);
}
}
class Demo
{
public static void main(String[] args)
{
Person p1 = new Person();
Person p2 = new Person("旺财");
p1.speak();
p2.speak();
}
}
// 改进
class Person
{
private String name;
// 类中的代码块称为构造代码块. 创建对象时,调用. 可以给所有对象进行初始化
{
System.out.println("person run");
}
Person()
{
name = "baby";
cry(); // 提高复用性
}
Person(String name)
{
this.name = name;
cry(); // 提高复用性
}
pulic void cry()
{
System.out.println("哇哇");
}
public void speak()
{
System.out.println("name:" + name);
}
}
class Demo
{
// 省略...
}
//再改进
class Person
{
private String name;
// 类中的代码块称为构造代码块. 创建对象时,调用. 可以给所有对象进行初始化
{
cry();
}
Person()
{
name = "baby";
}
Person(String name)
{
this.name = name;
}
pulic void cry()
{
System.out.println("哇哇");
}
public void speak()
{
System.out.println("name:" + name);
}
}
class Demo
{
// 省略...
}
_参考资料:_ - [JavaSE 基础视频(毕向东)](https://www.bilibili.com/video/av3092180/#page=1)