1. 为什么要使用静态变量、常量和方法

     通常,在处理问题,会遇到多个不同的类要使用同一变量,常量或方法,然而,同一个常量在不同的类中创建时系统都会为之分配内存,造成内存浪费,如果能将这些不同类中的变量共享到一个内存中,那就大大减少了内存的使用,而静态变量(关键字 static)就是解决这个问题的。如下图所示:

java uml图静态常量 java静态常量和静态变量_python

 

 

2. 被声明的static的变量,常量和方法被称为静态成员,静态成员属于类所有,区别于个别对象,可以在本类或其他类使用类名“.”运算符调用静态成员。如下代码:

1 public class AnyThing {
 2     static double PI = 3.1415;           //在类中定义静态常量
 3     static int id;                       //在类中定义静态变量
 4     public static void method1(){        //在类中定义静态方法
 5         
 6     }
 7     public void method2(){
 8         System.out.println(AnyThing.PI);  //调用静态常量
 9         System.out.println(AnyThing.id);  //调用静态变量
10         AnyThing.method1();               //调用静态方法
11     }
12 }



注意:(1) 虽然静态成员可以使用“对象.静态成员”的形式进行调用,但通常不这么使用,这样容易混淆静态成员和非静态成员。

             (2) 在静态方法中不可以使用this关键字。

             (3) 在静态方法中不可以直接调用非静态方法。

             (4) 在Java中规定不能将方法中的局部变量声明为static的。

             (5) 如果在执行类时,希望先执行类的初始化动作,可以使用static定义一个静态区域,例如

1 public class example{
2    static{
3          ...
4    }
5 }


当这段代码被执行时,首先执行static块中的程序,并且只会执行一次,即在类加载的时候就被执行,之后执行main()方法。并且只是自上而下的顺序执行。

3.在java中,静态方法和普通方法的区别:



1、在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 2、静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。 3、程序的static块只能调用静态方法,不能调用实例的方法。 如果要追溯其区别的根源,可以这样理解:在编译期间静态方法的行为就已经确定,而实例方法只有在运行期间当实例确定之后才能确定。



基本练习



package test_01;

public class static_class {
    
    static int a =100;
    int b=200;                      //实例变量

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        // static int a =100;       //局部变量不能定义static
        System.out.println("主函数");
        static_fangfa();
        //public_fangfa();   //也不能在静态函数中调用静态函数 ,除非把非静态函数变为静态函数
    }
    
    // 静态块
    static {
        System.out.println("静态块");
    }
    

    public static_class() {
        // TODO Auto-generated constructor stub
        System.out.println("构造方法");    
    }
    
    private static void static_fangfa() {

        System.out.println("静态函数"); 
        static_class static_class1 =new static_class();
        System.out.println(static_class1.a);
        // System.out.println(static_class.b);   // 静态函数里面不能调用静态变量
    }
    
    public void public_fangfa() {
        int c = 100+b;
        System.out.println("非静态函数"+c);
    }
}



输出结果:



静态块 主函数 静态函数 构造方法 100



4.静态代码段

a. 静态代码块只能定义在类里面,它独立于任何方法,不能定义在方法里面

b.静态代码块里面的变量都是局部变量,只在本块内有效

c.静态代码块会在类被加载时自动执行,而无论加载者是JVM还是其他的类

d. 一个类中允许定义多个静态代码块,执行的顺序根据定义的顺序进行

e.静态代码块只能访问类的静态成员,而不允许访问实例成员

5.java中的初始化顺序

JAVA类首次装入时,会对静态成员变量或方法进行一次初始化,但方法不被调用是不会执行的,静态成员变量和静态初始化块级别相同,非静态成员变量和非静态初始化块级别相同。

初始化顺序:先初始化父类的静态代码--->初始化子类的静态代码-->
(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码(变量定义等)--->初始化父类构造函数--->初始化子类非静态代码(变量定义等)--->初始化子类构造函数

类只有在使用New调用创建的时候才会被JAVA类装载器装入创建类实例时,首先按照父子继承关系进行初始化类实例创建时候,首先初始化块部分先执行,然后是构造方法;然后从本类继承的子类的初始化块执行,最后是子类的构造方法类消除时候,首先消除子类部分,再消除父类部分

  • 静态变量: 在类内部中,方法的外部声明的对象而且加上static;
  • 实例变量: 在类内部中,声明不需要加static;
  • static 函数名() --> 可以通过 类名.函数名() 调用,也可以通过 类对象.函数名() 调用;
  • 函数名()   -->只能通过类对象.函数名()  调用;

6.Java静态对象和非静态对象的区别

                                        静态对象                                                       非静态对象     
拥有属性:               是类共同拥有的                                            是类各对象独立拥有的
内存分配:              内存空间上是固定的                                      空间在各个附属类里面分配 
分配顺序:              先分配静态对象的空间                    继而再对非静态对象分配空间,也就是初始化顺序是先静态再非静态。

7.Java静态对象的特点

A,静态对象的数据在全局是唯一的,一改都改。如果你想要处理的东西是整个程序中唯一的,弄成静态是个好方法。非静态的东西你修改以后只是修改了他自己的数据,但是不会影响其他同类对象的数据。 
B,引用方便。直接用类名.静态方法名  或者  类名.静态变量名就可引用并且直接可以修改其属性值,不用get和set方法。
C,保持数据的唯一性。此数据全局都是唯一的,修改他的任何一处地方,在程序所有使用到的地方都将会体现到这些数据的修改。有效减少多余的浪费。

D,static final用来修饰成员变量和成员方法,可简单理解为“全局常量”。对于变量,表示一旦给值就不可修改;对于方法,表示不可覆盖。

8.静态变量、静态方法和静态块

       通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象(跟类是否有static修饰无关)。

       你可以将方法和变量都声明为static。static 成员的最常见的 例子是main( ) 。声明为static的方法有以下几条限制: ·

A,它们仅能调用其他的static 方法

B,它们只能访问static数据

C,它们不能以任何方式引用this 或super(this涉及到对象,super 与继承有关)

       示例:Static 块仅在该类被加载时执行一次。下面的例子显示的类有一个static方法,一些static变量,以及一个static 初始化块。



public class TestNew {  
    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) {  
        // TODO Auto-generated method stub  
        meth(42);  
    }  
}



执行结果是:



static blockinitialized x = 42 a = 3 b = 12



      上述classTestNew的执行顺序是:首先static 块执行(打印一条消息),a被设置为3,最后b被初始化为a*4 成12。然后调用main(),main () 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。

9.外部使用静态变量或者静态方法

       在定义它们的类的外面,static方法和变量能独立于任何对象而被使用,你只要在类的名字后面加点号运算符即可。可以看到,这种格式与通过对象引用变量调用非static方法或者变量的格式类似。示例:



class StaticDemo{  
    static int a = 42;  
    static int b = 99;  
    static void callme(){  
        System.out.println("a = "+a);  
    }  
}  
public class TestNew {  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        StaticDemo.callme();  
        System.out.println("b = "+StaticDemo.b);  
    }  
}



  执行结果:



a = 42 b = 99



10.静态内部类

静态内部类是指在一个类的内部,又定义了一个用static修饰的类。

A,首先,用内部类是因为内部类与所在外部类有一定的关系,往往只有该外部类调用此内部类。所以没有必要专门用一个Java文件存放这个类。

B,静态方法、静态成员变量。它唯一的作用就是随着类的加载(而不是随着对象的产生)而产生,以致可以用类名+静态成员名直接获得。这样静态内部类就可以理解了,它可以直接被用外部类名+内部类名获得。


public class Build {
      ..............
    public static class VERSION {
           ................
           public static final String RELEASE =getString("ro.build.version.release");
           ................
     }
     ................
}


在外部可以直接通过Build.VERSION.RELEASE来访问。

11. 静态常量

静态常量不可变,可以直接被访问,如类名.静态常量名。例如:



public class MathTest{
   public static final double PI= 3.1415926;
}



可以直接采用MathTest.PI的形式访问该PI常量。

13. 静态类与内部类的区别

内部类

1、内部类拥有普通类的所有特性,也拥有类成员变量的特性 
2、内部类可以访问其外部类的成员变量,属性,方法,其它内部类

静态内部类

1、只有内部类才能声明为static,也可以说是静态内部类 
2、只有静态内部类才能拥有静态成员,普通内部类只能定义普通成员 
3、静态类跟静态方法一样,只能访问其外部类的静态成员 
4、如果在外部类的静态方法中访问内部类,这时候只能访问静态内部类


/**
 * 外部类,不能声明为 static
 * 
 * @author zhanqi
 * 
 */
public class OuterClass {
    private int ab = 1;
    private static int sab = 2;
    /**
     * 普通内部类
     */
    public class NormalInnerClass {
        // private static int age = 22;
        private int age = 22; // 不能声明为static
        public NormalInnerClass() {
            // 可以访问外部类静态与非静态成员
            System.out.println(ab);
            System.out.println(sab);
        }
    }
    /**
     * 静态内部类
     */
    public static class StaticInnerClass {
        // 定义静态与非静态成员都是可以的
        private static int age = 22;
        private int age2 = 22;
        private void echo() {
            // System.out.println(ab);
            System.out.println(sab);// 只能访问外部类的静态成员
        }
    }
}


内部类实例化

1.访问内部类,必须使用:外部类.内部类,OutClass.InnerClass 
2.普通内部类必须绑定在其外部类的实例上 
3.静态内部类可以直接 new

/**
 * 外部类访问内部类
 */
public class OuterClass {
    /**
     * 普通方法
     */
    public void method() {
        StaticInnerClass sic = new StaticInnerClass();
        NormalInnerClass nic = new NormalInnerClass();
    }
    /**
     * Main
     */
    public static void main(String[] args) {
        // 在静态方法中,只能访问静态成员,静态内部类
        // NormalInnerClass nic = new NormalInnerClass();
        StaticInnerClass sic = new StaticInnerClass();
    }
}
/**
 * 其它类访问内部类
 */
class Test {
    public static void main(String[] args) {
        /**
         * 1:其它类访问内部类,必须使用:外部类.内部类,OutClass.InnerClass
         * 2:普通内部类必须绑定在其外部类的实例上
         * 3:静态内部类可以直接 new
         */
        OuterClass.StaticInnerClass sic = new OuterClass.StaticInnerClass();
        // OuterClass.NormalInnerClass n = new OuterClass.NormalInnerClass();
        OuterClass oc = new OuterClass();
        OuterClass.NormalInnerClass nic = oc.new NormalInnerClass();
    }
}

静态对象

静态对象我们经常使用,但是对静态对象和非静态对象的区别却并不一定那么了解。下表格就是静态对象和非静态对象主要区别。

1.拥有的对象,静态对象是类共同拥有的 ,而非静态对象是由类单独拥有; 
2.内存空间,静态对象内存空间是固定,非静态类对象是附着相关类的分配; 
3.分配顺序,先分配静态对象的空间,然后才会分配非静态对象也就是初始化。