Java之static关键字
1. 思考
Person p = new Person("lisi",20);
p.speak();
1.1 思考以下问题:
创建对象就是为了产生实例,并进行数据的封装。而调用功能时,却没有用到这些对象中封装的数据。
该对象的创建有意义吗?虽然可以编译并运行,但是在堆内存中空间较为浪费。怎么解决?
答:不建议创建对象。
1.2 那该怎么调用呢?
java中的解决方案就是 使用 static关键字,这是一个成员修饰符。
被静态static修饰的方法除了可以被对象调用外,还可以被类名调用。
2. static修饰函数:静态方法
2.1 静态看上去好厉害,是不是所有的方法都静态呢?
不行。考虑以下代码:
class Person
{
private String name;
private int age;
public static void speak()
{
System.out.println("name = " + this.name + ",age = " + this.age);
}
}
编译报错:无法从静态上下文中引用非静态变量。
2.2 为什么不行呢?
- 静态是随着类的加载就加载了。也是随着类的消失而消失了。
- 静态优先于对象存在,被对象共享。
- 因为静态先存在于内存中无法访问后来的对象的中的数据,所以静态无法访问非静态。而且内部无法书写this。因为这时对象有可能不存在,this没有任何指向。
2.2 那么什么时候需要将方法定义成静态的呢?
定义功能时,如果功能不需要访问类中定义的成员变量(非静态)时,该功能就需要静态修饰。
3. 静态方法使用的注意事项
- 静态方法不能访问非静态的成员。但是非静态可以访问静态成员的。
说明:静态的弊端在于访问出现局限性。好处是可以直接被类名调用。 - 静态方法中不允许出现this,super关键字。
4. 不引起注意的main函数
静态的主函数:
public static void main(String[] args)
public : 权限最大。
static :不需要对象。直接用给定的类名就可以访问该函数了。
void : 不需要返回值。
main : 函数名,该名称是固定的。
(String[] args) : 主函数的参数列表:字符串属性类型的参数。
args : arguments :参数。该名称就是一个变量名。
class MainDemo
{
public static void main(String[] args)
{
System.out.println(args); //[Ljava.lang.String;@1afae45
//根据这个结果,说明jvm传递了一个字符串类型的数组实体。
System.out.println(args.length); //0,得出结论 jvm传递的是 new String[0];
}
}
5. 静态变量
5.1 什么时候定义静态变量呢?
当该成员变量的值,每一个对象都一致时,就对该成员变量进行静态修饰。
5.2 静态变量和成员变量的区别:
-
所属范围不同。
静态变量所属于类,成员变量所属对象。
静态变量也称为:类变量;
成员变量也称为实例变量。 -
调用不同。
静态变量可以被对象和类调用(一般都用类名调用)
成员变量只能被对象调用。 -
加载时期不同。
静态变量随着类的加载而加载。
成员变量随着对象的加载而加载。 -
内存存储区域不同。
静态变量存储在方法区中。
成员变量存储在堆内存中。
5.3 代码示例
class Circle
{
private double radius; //圆的半径。
private static double pi = 3.14; //每一个圆对象中都存储一份,有点浪费内存空间。实现对象的共享。加入静态关键字修饰。
Circle(double radius)
{
this.radius = radius;
}
//获取圆的面积。
double getArea()
{
return radius*radius*pi;
}
static void show()
{
System.out.println("circle show run.."+pi);
}
}
class CircleDemo
{
public static void main(String[] args)
{
Circle c = new Circle(3);
}
}
6. 静态代码块
6.1 需求
需求:类一加载,需要做一些动作。不一定需要对象。
解决方案:静态代码块
6.2 加载的顺序
class Demo
{
static int x = 9; //静态变量有两次初始化。 一次默认初始化,一次显示初始化。
static //静态代码块。在静态变量显示初始化以后在执行。
{
System.out.println("类加载就执行的部..." + x);
}
static void show()
{
System.out.println("show run");
}
}
class StaticCodeDemo
{
public static void main(String[] args)
{
Demo.show();
Demo.show();
}
}
运行结果:
6.3 静态代码块的特点
随着类的加载而执行,仅执行一次。
6.4 静态代码块的作用
给类进行初始化。(在静态变量显示初始化以后在执行。)
7. 构造代码块与局部代码块
7.1 作用
构造代码块:用于给所有的对象初始化。很少用并很少见。说白了可以定义不同构造函数的共性代码。
局部代码块:控制局部变量的生命周期。
7.2 注意
- 构造代码块。只要创建对象就会被调用。给所有对象初始化,构造函数只给对应的对象针对性的初始化。
- 这里面可以定义不同构造函数的共性代码。
- 在成员变量显示初始化后执行
7.3 代码示例
class Demo
{
int x = 4; //成员变量 1,默认初始化,2,显示初始化。
{
// 构造代码块。只要创建对象就会被调用。给所有对象初始化,构造函数只给对应的对象针对性的初始化。
// 这里面可以定义不同构造函数的共性代码。
// 在成员变量显示初始化后执行
System.out.println("code run..." + x);
// System.out.println("----->hahah");
}
Demo()
{
System.out.println("demo run");
}
Demo(int x)
{
System.out.println("demo run...." + x);
// System.out.println("----->hahah");
}
}
class ConstructorCodeDemo
{
public static void main(String[] args)
{
new Demo();
new Demo(5);
{
// 局部代码块,作用:就可以控制局部变量的生命周期。
int x = 5;
System.out.println(" 局部代码块..."+x);
}
System.out.println(" over...");
}
}
运行结果: