静态成员
思考:利用类来创建很多个对象,每个对象都需要存储一个相同值的变量时,我们能不能只保存一个呢?静态成员(static)就是来解决这个问题。
举个例子,我们设定一个圆柱(class Cylinder)的类,再用这个类创建200个对象,我们会发现所有圆柱都有pi值,而且pi值都相同的,这样我们就得存200分相同的数据,这样大大浪费了空间,这时候我们就可以引入静态来解决
class Cylinder{
double radius;
int height;
double pi = 3.14;//这样每个对象都得创建一个相同的pi
}
1.静态成员
实例成员:属于对象,必须创建对象后才可调用的成员
例如:Cylinder c1 = new Cylinder();
c1.radius = 1; c1.Volume();
对象名.变量名; 对象名.方法名
这些都是实例成员
对比分析:
实例成员 :
1.不用static修饰的成员
2.属于对象,创建对象后才能访问成员
3.实例变量和实例方法
实例成员必须要实例化才能调用例如:Cylinder c1 = new Cylinder();
拓展:实例变量:定义在类中但在任何方法之外。
静态成员(类成员)
1.被static修饰的成员
2.属于类,无需创建对象即可访问
3.静态变量和静态方法
而静态成员可以直接调用如:Cylinder.count()
2.静态变量
静态变量:用static修饰的成员变量,类变量
引入了静态变量后的代码:
class Cylinder{
private static double pi = 3.14;
private static int num;
private double r,h;
......
}
由图可以看出,在由Cyliner类为模板创建出的c1,c2对象的空间中并没有pi和num,因为pi和num被设置为了静态变量
这里的静态变量也可以成为类变量或者说类的域,不属于****任何一个类的具体对象,可以看出c1,c2中是没有这两个变量的
静态变量不保存在对象内存空间中,而是保存在类的内存区域,是公共存储单元
可以看出当创建大量对象是,可以节省内存空间
使用格式
类名.静态变量, Cylinder.num(推荐)
对象名.静态变量名 c1.num(虽然正确但不推荐)
因为静态变量是存放在类中而不是对象中,所以第二种用法在表达上不准确
3.静态方法
静态方法:用static修饰的方法,类方法
属于整个类,内存中的代码段将随着类的定义而分配和装载,不被任何一个对象专有
class Cylinder{
private static double pi = 3.14;
private static int num=0;
private double r,h;
......
public static void count(){
System.out.println("创建了"+num+"对象");
}
......
}
使用格式
类名.静态变量, Cylinder.count()(推荐)
对象名.静态变量名 c1.count()(虽然正确但不推荐)
因为静态方法是存放在类中而不是对象中,所以第二种用法在表达上不准确
4.static的规则
静态的成员(类成员)不能访问实例成员,因为,实例变量只有在创建实例的时候才会被创建,而静态成员是加载类的时候被创建。所以有了静态成员未必据有实例变量,即使有了实例变量,那么多实例,它哪知道访问哪个实例变量
类成员不能访问实例成员,类成员属于类,作用域大于实例成员,举个不
class Cylinder{
private static double pi = 3.14;
private static int num=0;
private double r,h;
......
public static void count(){
System.out.println("创建了"+num+"对象");
}
......
}
在count()方法中不可以访问r,h,可以访问num,pi
编程:
创建一个类,定义静态方法least(),求若干数的最小值
class TestStatic
{
static void least(int[] array)
{
int min=array[0];
for(int i=1;i<array.length;i++)
{
if(array[i]<min)
min=array[i];
}
System.out.println("最小数:"+min);
}
}
public class Test
{
public static void main(String[] args)
{
int[] a={8,3,7,88,9,23};
TestStatic.least(a);
}
}
扩展
class Value {
static int c = 0;
Value() {
c = 15;
}
Value(int i) {
c = i;
}
static void inc() {
c++;
}
}
class Count {
public static void prt(String s) {
System.out.println(s);
}
Value v = new Value(10);
static Value v1, v2;
static {
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v1 = new Value(27);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v2 = new Value(15);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
}
public static void main(String[] args) {
Count ct = new Count();
prt("ct.v.c=" + ct.v.c);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v1.inc();
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
prt("ct.v.c=" + ct.v.c);
}
}
运行结果如下:
v1.c=0 v2.c=0
v1.c=27 v2.c=27
v1.c=15 v2.c=15
ct.c=10
v1.c=10 v2.c=10
v1.c=11 v2.c=11
ct.c=11
这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。