浅谈java中的static关键字作用

通常,我们创建类时会指出那个类的对象的外观与行为。除非用new 创建那个类的一个对象,否则实际上并未得到任何东西。只有执行了new 后,才会正式生成数据存储空间,并可使用相应的方法。但在两种特殊的情形下,上述方法并不堪用。

一种情形是只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。

另一种情形是我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。为满足这两方面的要求,可使用static(静态)关键字。一旦将什么东西设为static,数据或方法就不会同那个类的任何对象实例联系到一起。所以尽管从未创建那个类的一个对象,仍能调用一个static 方法,或访问一些static 数据。而在这之前,对于非static 数据和方法,我们必须创建一个对象,并用那个对象访问数据或方法。这是由于非static 数据和方法必须知道它们操作的具体对象。当然,在正式使用前,由于static 方法不需要创建任何对象,所以它们不可简单地调用其他那些成员,同时不引用一个已命名的对象,从而直接访问非static 成员或方法(因为非static 成员和方法必须同一个特定的对象关联到一起)。有些面向对象的语言使用了“类数据”和“类方法”这两个术语。它们意味着数据和方法只是为作为一个整体的类而存在的,并不是为那个类的任何特定对象。有时,您会在其他一些Java 书刊里发现这样的称呼。为了将数据成员或方法设为static,只需在定义前置和这个关键字即可。

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。 被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。

只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象市,不生成static变量的副本,而是类的所有实例共享同一个static变量。

static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用--废话),但是不能在其他类中通过类名来直接引用,这一点很重要。实际上你需要搞明白,private是访问权限限定,static表示不要实例化就可以使用,这样就容易理解多了。static前面加上其它访问权限关键字的效果也以此类推。

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:
类名.静态方法名(参数列表...)
类名.静态变量名

用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块(用处非常大,呵呵)。

1、static变量
 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。

两者的区别是:
 对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
 对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

所以一般在需要实现以下两个功能时使用静态变量:
   在对象之间共享值时
   方便访问变量时


2、静态方法
   静态方法可以直接通过类名调用,任何的实例也都可以调用,
   因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。
   因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!

   因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

   例如为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。

   静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的


3、static代码块

 static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。

例如:

public class Test5 {
private static int a;
private int b;

static{
Test5.a=3;
System.out.println(a);
Test5 t=new Test5();
t.f();
t.b=1000;
System.out.println(t.b);
}
static{
Test5.a=4;
System.out.println(a);
}
public static void main(String[] args) {
// TODO 自动生成方法存根
}
static{
Test5.a=5;
System.out.println(a);
}
public void f(){
System.out.println("hhahhahah");
}
} 

运行结果:
3
hhahhahah
1000
4
5
利用静态代码块可以对一些static变量进行赋值,最后再看一眼这些例子,都一个static的main方法,这样JVM在运行main方法的时候可以直接调用而不用创建实例。

4、static和final一块用表示什么
   static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
   对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
   对于方法,表示不可覆盖,并且可以通过类名直接访问。

   有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。

   声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。声明为static的方法有以下几条限制:
   它们仅能调用其他的static 方法。
   它们只能访问static数据。
   它们不能以任何方式引用this 或super。
   如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static 块仅在该类被加载时执行一次。下面的例子显示的类有一个static方法,一些static变量,以及一个static 初始化块:

// Demonstrate static variables,methods,and blocks.

class UseStatic {
static int a = 3;
static int b;

static void meth(int x) {
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}

static {
System.out.println("Static block initialized.");
b = a * 4;
}

public static void main(String args[]) {
meth(42);
}
}

一旦UseStatic 类被装载,所有的static语句被运行。首先,a被设置为3,接着static 块执行(打印一条消息),最后,b被初始化为a*4 或12。然后调main(),main() 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。

注意:在一个static 方法中引用任何实例变量都是非法的。

下面是该程序的输出:

Static block initialized.
x = 42
a = 3
b = 12

在定义它们的类的外面,static 方法和变量能独立于任何对象而被使用。这样,你只要在类的名字后面加点号运算符即可。例如,如果你希望从类外面调用一个static方法,你可以使用下面通用的格式:

classname.method( )

这里,classname 是类的名字,在该类中定义static方法。可以看到,这种格式与通过对象引用变量调用非static方法的格式类似。一个static变量可以以同样的格式来访问——类名加点号运算符。这就是Java 如何实现全局功能和全局变量的一个控制版本。

下面是一个例子。在main() 中,static方法callme() 和static 变量b在它们的类之外被访问

class StaticDemo {
static int a = 42;
static int b = 99;
static void callme() {

System.out.println("a = " + a);
}
}

class StaticByName {

public static void main(String args[]) {
StaticDemo.callme();
System.out.println("b = " + StaticDemo.b);
}
}

下面是该程序的输出:

a = 42
b = 99
static成员是不能被其所在class创建的实例访问的。

如果不加static修饰的成员是对象成员,也就是归每个对象所有的。

加static修饰的成员是类成员,就是可以由一个类直接调用,为所有对象共有的


5、static内部类

   static一般用来修饰成员变量或函数也修饰代码块,一般不能修饰类,但是可以修饰内部类,被修饰的内部类可以直接作为一个普通类来用,不需要创建一个外部类的实例,而普通内部类的引用需要创建一个外部类的实例。

内部类特点:
   (1)内部类可体现逻辑上的从属关系,同时对于其他类可以控制内部类对外不可见。
   (2)外部类的成员变量的作用域是整个外部类,包括内部类。但外部类不能访问内部类的private成员。
   (3)逻辑上相关的类可以在一起,可以有效的实现信息隐藏。
   (4)内部类可以直接访问外部类的成员,可以用此实现多继承。
   (5)编译后内部类也被编译为单独的类,不过名称为outclass$inclass的形式。

static内部类型和非static内部类的区别:

  1、如是否可以创建静态的成员方法与成员变量(静态内部类可以创建静态的成员,而非静态的内部类不可以)
  2、对于访问外部类的成员的限制(静态内部类只可以访问外部类中的静态成员变量与成员方法,而非静态的内部类即可以访问所有的外部类成员方法与成员变量)。

例子:

静态内部类:
package innerClass;   
public class OutClass1 {   
    public int oid;   
    public String oname;   
    public static class InnerStaticClass1{   
        public int iid;   
        public String iname;   
    }   
}  
package innerClass;   
import innerClass.OutClass1.InnerStaticClass1;   
public class Test1 {   
    public static void main(String[] args) {   
        OutClass1 oc=new OutClass1();   
        InnerStaticClass1 ic=new InnerStaticClass1();   //不依赖与外部类的实例 
    }   
}  
非静态内部类:
package innerClass;   
public class OutClass2 {   
    public int oid;   
    public String oname;   
    public class InnerClass2   
    {   
        public int iid;   
        public String iname;   
    }   
}   
package innerClass;   
public class Test2 {   
    public static void main(String[] args) {   
        OutClass2 oc=new OutClass2();   
        OutClass2.InnerClass2 ic=oc.new InnerClass2(); //依赖与外部类的实例   
    }   
} 
注意静态的main()方法只能使用静态的成员变量或成员函数,因为静态方法初始化要早于实例对象。


6、static(静态)导包

   静态导包就是Java包的静态导入,用IMPORT static代替IMPORT静态导入包是JDK1.5中的新特性。
   一般我们导入一个类都用 IMPORT com…..ClassName;而静态导入是这样:IMPORT static com…..ClassName.*;这里的多了个static,还有就是类名ClassName后面多了个.* ,意思是导入这个类里的静态方法。当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用。

   好处:

   这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一个静态方法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写来的方便

   EXAMPLE:

   在Java 5中,IMPORT语句得到了增强,以便提供甚至更加强大的减少击键次数功能,虽然一些人争议说这是以可读性为代价的。这种新的特性成为静态导入。当你想使用static成员时,可以使用静态导入(在API中的类和你自己的类上,都可以使用该特性)。

下面是静态导入前后的代码实例:

在静态导入之前:
public class TestStatic {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.toHexString(42));
}
}
在静态导入之后:
import static java.lang.System.out;
import static java.lang.Integer.*;

public class TestStaticImport {
public static void main(String[] args) {
out.println(MAX_VALUE);
out.println(toHexString(42));
}
}
两个类都产生相同的输出:
2147483647
2a

使用静态导入特性的代码中将发生什么:
   1、虽然该特性通常称为“静态导入”,但语法必须是IMPORT static,后面跟你想导入的static成员的完全限定名称,或者通配符。在本例中,我们在System类的OUT对象上进行静态导入。
   2、在本例中,我们可能想使用java.lang.Integer类的几个static成员。该静态导入语句使用通配符来表达“我想在此类中的所有静态成员上进行静态导入”。
   3、现在我们终于看到静态导入特性的好处!我们不必在System.out.println中键入System。太好了!另外,我们不必在Integer.MAX_VALUE中键入INTEGER。因此,在这行代码中,我们能够将快捷方式用于静态方法和一个常量。
   4、最后,我们进行更多的快捷操作,这次针对INTEGER类的方法。关于该特性,我们已经有点儿讽刺意味儿了,但不仅我们是这样的。我们不认为节省少量的击键次数会让代码难于阅读一点,但许多开发人员要求将它添加到语言中。


下面是使用静态导入的几条原则:
    你必须说IMPORT static, 不能说static IMPORT。提防含糊不清的命名static成员。例如,如果你对INTEGER类和LONG类执行了静态导入,引用MAX_VALUE将导致
一个编译器错误,因为INTEGER和LONG都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。你可以在static对象引用、常量(记住,它们是static 或final)和static方法上进行静态导入。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十点摆码

有用你就打赏一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值