码迷,mamicode.com
首页 > 其他好文 > 详细

我们眼中的static关键字

时间:2015-01-31 16:21:45      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:java学习   静态方法   内部类   

 就在刚才我在看线程方面的东西时候,看见一段这样的代码

<span style="font-size:14px;">package book.thread;

public class Priority {
	
	static class MyThread extends Thread{
		private int ID = 0;
		public MyThread(int id){
			this.ID = id;
		}
		public void run(){
			System.out.println("MyThread-" + this.ID + 
					" begin! Priority: " + this.getPriority());

			System.out.println("MyThread-" + this.ID + " end!");
		}
	}

	public static void main(String[] args) {
		//建立3个优先级不同的线程
		MyThread[] myThreads = new MyThread[3];
		for (int i=0; i<3; i++){
			myThreads[i] = new MyThread(i+1);
			//三个线程的优先级分别是1,4,7
			myThreads[i].setPriority(i*3+1);
		}
		//按优先级从低到高启动线程
		for (int i=0; i<3; i++){
			myThreads[i].start();
		}
		//先启动的线程不一定先运行,虚拟机会考虑线程的优先级,同等情况下,优先级高的线程先运行
	}
}</span>
PS :   static class 我见的不多,对于static变量 static 方法 用的很多,但是static class 我真心不太明白,回去翻了一下核心技术卷,总结一下:

1.静态域:如果将域定义为static ,每个类中只有一个这样的域。而每个对象对于所有的实例域却有自己的一份拷贝。例如:

class Employee{
          private static int nextId = 1;
          private int id;

          ...  ...
}
每一个员工对象都有自己的id域,但这个类的所有实例将共享一个nextId域。若有10000个员工则有1000id,但是只有一个nextId,即使没有一个雇员对象,静态域nextId也存在,并属于类,不属于独立对象。

注释:在绝大多数面向对象语言中,静态域也成为类域。

public void setId(){
      id = nextId;
      nextId++;

}
harry.setId();//设置为静态域nextId当前值,并使其自身加1

Harry.id = Employee.nextId;
Employee.nextId++;

/*   静态域作用:
      1. 可以向前引用
      2. 变量属于类本身
      3. 类变量不依赖类的实例,类变量只在初始化时候在栈内存中被分配一次空间,无论类的实例被创建几次,都不再为类变量分配空间
      4. 通过类的任意一个实例来访问类变量,底层都将将其转为通过类本身来访问类变量,它们的效果是一样的
      5. 一旦类变量的值被改变,通过类或类的任意一个实例来访问类变量,得到的都将是被改变后的值
      6. 将在类的初始化之前初始化
*/
2.静态常量

public class Math{
       ...
       public static final double PI = 3.1415926;
       //如果省略static ,那么PI会变成实例变量,只能通过对象访问
       ...
}
Math.PI;//可以调用

//另一个多次使用的静态常量是system.out
public class System{
     ...
     public static final PrintStream out = ...;
     ...
}
/* 
   前面提到,每个类对象都可以对公有域进行修改,所以,最好不要将域设计为public。
   然而,公有常量(final域)没有问题。out声明为final后,不允许其他打印流赋给它:
*/
System.out = new PrintStream(...);// error -- out is final !!
3.静态方法

1> 可以通过自己的静态域来访问;

public static intgetNextId(){
         return nextId;
}
2>NumberFormat类使用工厂方法产生不同风格的格式对象

NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
<pre name="code" class="java">NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currencyFormatter.format(x));// $ 0.10
<pre name="code" class="java"><pre name="code" class="java">System.out.println(percentFormatter.format(x));// 10%




为何不利用构造器完成?

1)无法命名构造器。构造器名字必须与类名相同。但是,这里希望将得到的货币实例和百分比实例采用不同的名字

2)无法改变所构造的对象类型。Factory方法将返回一个DecimalFormat类对象,这是NumberFormat子类

3>主方法main

public class application{
      
      public static void main(String [] args){
             ...
      }
}
总结:
(1)可以实现某些特殊的设计模式:如Singleton;

(2)由于没有this指针,可以把某些系统API的回调函数以静态函数的形式封装到类的内部。因为系统API的回调函数通常都是那种非成员函数(孤立函 数),没有this指针的。比如你可以在类的内部写一个线程函数供CreateThread创建线程用,如果没有静态函数,那么这种回调函数就必须定义成 全局函数(非静态成员函数指针无法转换成全局函数指针),从而影响了OO的“封装性”。

(3)可以封装某些算法,比如数学函数,如ln,sin,tan等等,这些函数本就没必要属于任何一个对象,所以从类上调用感觉更好,比如定义一个数学函数类Math,调用Math::sin(3.14);如果非要用非静态函数,那就必须:
Math   math;
math.sin(3.14);
行是行,只是不爽:就为了一个根本无状态存储可言的数学函数还要引入一次对象的构造和一次对象的析构,当然不爽。而且既然有了对象,说不得你还得小心翼翼的定义拷贝构造函数、拷贝赋值运算符等等,对于一些纯算法的东西显然是不合适的。

(4)总之,从OOA/OOD的角度考虑,一切不需要实例化就可以有确定行为方式的函数都应该设计成静态的。
以上只是一些基本的考虑,并不是绝对的。绝对东西的只有一点:“静态函数不需要实例化就可以被调用,不会也不可以调用或操纵非静态成员”。记住这一点,那么实际编程中何时需要用,何时适合用,自然就更容易作出决定了。


4.静态对象

             静态对象                                                                非静态对象      

           是类共同拥有的.                                               是类独立拥有的,

           内存空间上是固定的                                        空间在各个附属类里面分配 

          先分配静态对象的空间                               继而再对非静态对象分配空间,也就是初始化顺序是先静态再非静态.

静态对象可以让相同类型的类之间共享共同的属性,这个共享是同步的,而且不用new,节省了空间

1、静态对象的数据在全局是唯一的,一改都改。如果你想要处理的东西是整个程序中唯一的,弄成静态是个好方法。 
2、非静态的东西你修改以后只是修改了他自己的数据,但是不会影响其他同类对象的数据。 
3、静态对象和非静态对象都是对象,是对象都是要实例化的。不同之处就是2者的数据表现和存储方式不一样。 

静态的好处:

 
1)引用方便。对于公用类型的变量,直接用 类名.静态方法名  或者  类名.静态变量名就可引用并且直接可以修改其属性值,不用getter和setter方法。 
2)保持数据的唯一性。此数据全局都是唯一的,修改他的任何一处地方,在程序所有使用到的地方都将会体现到这些数据的修改。

3)有效减少多余的浪费。

5.静态类


一般情况下是不可以用static修饰类的。如果一定要用static修饰类的话,通常static修饰的是匿名内部类。

在一个类中创建另外一个类,叫做成员内部类。这个成员内部类可以静态的(利用static关键字修饰),也可以是非静态的。由于静态的内部类在定义、使用的时候会有种种的限制。所以在实际工作中用到的并不多。

在开发过程中,内部类中使用的最多的还是非静态地成员内部类。不过在特定的情况下,静态内部类也能够发挥其独特的作用。

  一、静态内部类的使用目的。

  在定义内部类的时候,可以在其前面加上一个权限修饰符static。此时这个内部类就变为了静态内部类。不过由于

种种的原因,如使用上的限制等等因素(具体的使用限制,笔者在下面的内容中会详细阐述),在实际工作中用的并不

是很多。但是并不是说其没有价值。在某些特殊的情况下,少了这个静态内部类还真是不行。如在进行代码程序测试

的时候,如果在每一个Java源文件中都设置一个主方法(主方法是某个应用程序的入口,必须具有),那么会出现很多

额外的代码。而且最主要的时这段主程序的代码对于Java文件来说,只是一个形式,其本身并不需要这种主方法。但

是少了这个主方法又是万万不行的。在这种情况下,就可以将主方法写入到静态内部类中,从而不用为每个Java源文

件都设置一个类似的主方法。这对于代码测试是非常有用的。在一些中大型的应用程序开发中,则是一个常用的技术

手段。为此,这个静态内部类虽然不怎么常用,但是程序开发人员还必须要掌握它。也许在某个关键的时刻,其还可

以发挥巨大的作用也说不定。

 public class MainInStaticClass {

 static class Main{

public static void main() {

//将主方法写到静态内部类中,从而不必为每个源文件都这种一个类似的主方法

     new MainInStaticClass().print();

}

}

public static void main(String[] args){

new MainInStaticClass().print();

}

public void print(){

System.out.println("main in static inner class");

}

}

public class TestMain {

public static void main(String[] args) {

// new MainInStaticClass().print();

MainInStaticClass.Main.main();

new MainInStaticClass.Main();

}
}

二、静态内部类的使用限制。

  将某个内部类定义为静态类,跟将其他类定义为静态类的方法基本相同,引用规则也基本一致。不过其细节方面仍然有很大的不同。具体来说,主要有如下几个地方要引起各位程序开发人员的注意。

  一是静态成员(包括静态变量与静态成员)的定义。一般情况下,如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态成员变量与静态成员方法的。也就是说,在非静态内部类中不可以声明静态成员。如现在在一个student类中定义了一个内部类age,如果没有将这个类利用static关键字修饰,即没有定义为静态类,那么在这个内部类中如果要利用static关键字来修饰某个成员方法或者成员变量是不允许的。在编译的时候就通不过。故程序开发人员需要注意,只有将某个内部类修饰为静态类,然后才能够在这个类中定义静态的成员变量与成员方法。这是静态内部类都有的一个特性。也正是因为这个原因,有时候少了这个静态的内部类,很多工作就无法完成。或者说要绕一个大圈才能够实现某个用户的需求。这也是静态的内部类之所以要存在的一个重要原因。


后注:经过大家的指正,现声明:非静态内部类也可以定义静态成员但需要同时有final关键词修饰,静态方法鉴于无法用final修饰,仍必须是在静态内部类或者非内部类中定义。

  二是在成员的引用上,有比较大的限制。一般的非静态内部类,可以随意的访问外部类中的成员变量与成员方

法。即使这些成员方法被修饰为private(私有的成员变量或者方法),其非静态内部类都可以随意的访问。则是非静态

内部类的特权。因为在其他类中是无法访问被定义为私有的成员变量或则方法。但是如果一个内部类被定义为静态

的,那么在银用外部类的成员方法或则成员变量的时候,就会有诸多的限制。如不能够从静态内部类的对象中访问外

部类的非静态成员(包括成员变量与成员方法)这是什么意思呢?如果在外部类中定义了两个变量,一个是非静态的变

量,一个是静态的变量。那么在静态内部类中,无论在成员方法内部还是在其他地方,都只能够引用外部类中的静态

的变量,而不能够访问非静态的变量。在静态内部类中,可以定义静态的方法(也只有在静态的内部类中可以定义静态

的方法),在静态方法中引用外部类的成员。但是无论在内部类的什么地方引用,有一个共同点,即都只能够引用外部

类中的静态成员方法或者成员变量。对于那些非静态的成员变量与成员方法,在静态内部类中是无法访问的。这就是

静态内部类的最大使用限制。在普通的非静态内部类中是没有这个限制的。也正是这个原因,决定了静态内部类只应

用在一些特定的场合。其应用范围远远没有像非静态的内部类那样广泛。

 三是在创建静态内部类时不需要将静态内部类的实例绑定在外部类的实例上

通常情况下,在一个类中创建成员内部类的时候,有一个强制性的规定,即内部类的实例一定要绑定在外部类的实例

中。也就是说,在创建内部类之前要先在外部类中要利用new关键字来创建这个内部类的对象。如此的话如果从外部

类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。也就是说,普通非静态内部类的对象是依附

在外部类对象之中的。但是,如果成员开发人员创建的时静态内部类,那么这就又另当别论了。通常情况下,程序员

在定义静态内部类的时候,是不需要定义绑定在外部类的实例上的。也就是说,要在一个外部类中定义一个静态的内

部类,不需要利用关键字new来创建内部类的实例。即在创建静态类内部对象时,不需要其外部类的对象。

new MainInStaticClass.Main();

具体为什么会这样,一般程序开发人员不需要了解这么深入,只需要记住有这个规则即可。在定义静态内部类的时

候,千万不要犯画蛇添足的错误。

  从以上的分析中可以看出,静态内部类与非静态的内部类还是有很大的不同的。一般程序开发人员可以这么理

解,态的内部类对象隐式地在外部类中保存了一个引用,指向创建它的外部类对象。不管这么理解,程序开发人

员都需要牢记静态内部类与非静态内部类的差异。如是否可以创建静态的成员方法与成员变量(静态内部类可以创建静

态的成员而非静态的内部类不可以)、对于访问外部类的成员的限制(静态内部类只可以访问外部类中的静态成员变量

与成员方法而非静态的内部类即可以访问静态的也可以访问非静态的外部类成员方法与成员变量)。这两个差异是静态

内部类与非静态外部类最大的差异,也是静态内部类之所以存在的原因。了解了这个差异之后,程序开发人员还需要

知道,在什么情况下该使用静态内部类。如在程序测试的时候,为了避免在各个Java源文件中书写主方法的代码,可

以将主方法写入到静态内部类中,以减少代码的书写量,让代码更加的简洁。

  总之,静态内部类在Java语言中是一个很特殊的类,跟普通的静态类以及非静态的内部类都有很大的差异。作为

程序开发人员,必须要知道他们之间的差异,并在实际工作中在合适的地方采用合适的类。不过总的来说,静态内部

类的使用频率并不是很高。但是在有一些场合,如果没有这个内部静态类的话,可能会起到事倍功半的反面效果


参考:http://zhidao.baidu.com/question/149873207.html

           http://www.cnblogs.com/Bob-FD/archive/2012/09/17/2689359.html

          http://klcwt.iteye.com/blog/452834




我们眼中的static关键字

标签:java学习   静态方法   内部类   

原文地址:http://blog.csdn.net/cuiwjava/article/details/43340401

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!