Java学习6:static关键字

来源:互联网 发布:日语软件测试工程师 编辑:程序博客网 时间:2024/06/05 05:11

特点

  1. 是一个修饰符,用于修饰成员(成员变量和成员函数);
  2. 被所有对象所共享;
  3. 随着类的加载而加载,随着类的消失而消失,生命周期最长;
  4. 优先于对象存在:静态是先存在,对象是后存在;
  5. 当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用:类名.静态成员。
public class Demo{    public static void main(String[] args) {        Person p1 = new Person("zhangsan");        Person p2 = new Person("lisi");        p1.show();        System.out.println(Person.country);//静态成员直接被类名调用    }}class Person{    String name;//成员变量,实例变量    static String country = "CN";//静态的成员变量,类变量    Person(String name){        this.name = name;    }    void show(){        System.out.println(name + ":" + country);    }}

见下图,country前面加static,则会被放置于共享区;如果country前面不加static,则会在每个对象中存在country=“CN”:
这里写图片描述

实例变量和类变量的区别

存放位置

类变量随着类的加载而存在于方法区中;
实例变量随着对象的建立而存在于堆内存中。

生命周期

类变量生命周期最长, 随着类的消失而消失;
实例变量生命周期随着对象的消失而消失。

静态使用注意事项

1.静态方法只能访问静态成员,非静态方法既可以访问静态,也可以访问非静态;
2. 静态方法中不可以定义this、super关键字,因为静态优先于对象存在;
3. 主函数是静态的。

静态有利有弊

利处:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份、可以直接被类名调用;
弊端:生命周期过长、访问有局限性(只能访问静态)。

主函数的含义

public static void main(String[] arg)
public:代表该函数的访问权限是最大的;
static:代表主函数随着类的加载就已经存在了;
void:主函数没有具体的返回值;
main:不是关键字,但是是一个特殊的单词,可以被jvm识别;
String[] args:args(arguments),函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组;
主函数是固定格式的,被jvm所识别,jvm在调用主函数时,传入的是new String[0]。

public class Demo{    public static void main(String[] args){        System.out.println(args);//输出 [Ljava.lang.String;@135fbaa4        System.out.println(args.length);//输出 0    }}

命令行中使用java命令启动虚拟机执行Demo类时,其会调用该类中的main函数,在后面可以传入字符串,见下图:
这里写图片描述

public class Demo{    public static void main(String[] args){        System.out.println(args[0]);        System.out.println(args.length);    }}

什么时候使用静态

何时定义静态变量(类变量)?

当对象中出现共享数据时,该数据被静态所修饰;对象中的特有数据定义为非静态,存在于堆内存中。

何时定义静态函数?

当功能内部没有访问到非静态数据(对象的特有数据),该功能可以定义为静态的。

//需要定义为静态函数public class Demo{    public static void main(String[] args){        Person.show();//不建立对象,直接使用类调用函数    }}class Person{    String name;    //未使用非静态数据,定义为静态函数    //因为未使用静态数据,所以当只需要单独执行此函数时,    //建立对象是多余的,需要不建立对象也可调用此函数,所以定义为静态函数    public static void show(){        System.out.println("Person");    }}
//不能定义为静态函数public class Demo{    public static void main(String[] args){        Person p1 = new Person();        p1.show();    }}class Person{    String name;    //使用非静态数据,不能定义为静态函数    public  void show(){        System.out.println("Person:" + name);//需要打印姓名(非静态数据)    }}

静态的应用_ArrayTools类

每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。

Demo.java文件:

/*    虽然可以通过建立ArrayTools的对象使用这些方法对数组进行操作,但是:    1.对象适用于封装数据的,但是ArrayTools对象并未封装特有数据;    2.操作数组的每一个方法都没有用到ArrayTools对象中的特有数据。    此时,考虑到程序更严谨,是不需要对象的,可以将ArrayTools中的方法定义为static的,直接通过类名调用即可。    将方法都静态后,可以方便使用,但是该类还是可以被其他程序建立对象的,为了更加严谨,强制该类不能建立对象,可以将构造函数私有化:private ArrayTools(){}。*/public class Demo{    public static void main(String[] args){        int[] array = {44,41,43,45,46};        System.out.println("max = " + ArrayTools.getMax(array));//直接类名调用,不用生成对象        System.out.println("min = " + ArrayTools.getMin(array));        ArrayTools.printArray(array);        ArrayTools.selectSort(array);        ArrayTools.printArray(array);        int index = ArrayTools.binarySearch(array, 40);        System.out.println(index);       /* ArrayTools tools = new ArrayTools();        int[] array = {44,41,43,45,46};        System.out.println("max = " + tools.getMax(array));        System.out.println("min = " + tools.getMin(array));        tools.printArray(array);        tools.selectSort(array);        tools.printArray(array);        int index = tools.binarySearch(array, 40);        System.out.println(index);*/    }}

ArrayTools.java文件:

/** * Created by hacker on 2017/9/22. */public class ArrayTools {    private ArrayTools(){}//构造函数私有化    public static int getMax(int[] array){//求数组最大值        int max = 0;        for(int i=1; i<array.length; i++){            if(array[i] > array[max])                max = i;        }        return array[max];    }    public static int getMin(int[] array){//求数组最小值        int min = 0;        for(int i=1; i<array.length; i++){            if(array[i] < array[min])                min = i;        }        return array[min];    }    public static void printArray(int[] array){//输出数组        System.out.printf("[");        for(int i=0; i<array.length; i++){            if(i != array.length - 1)                 System.out.print(array[i] + ", ");            else                System.out.println(array[i] + "]");        }    }    public static void selectSort(int[] array){//选择排序        for(int i=0; i<array.length-1; i++){//遍历数组            for(int j=i+1; j<array.length; j++)                if(array[j] < array[i]) {                    int temp = array[i];                    array[i] = array[j];                    array[j] = temp;                }        }    }    public static void bubbleSort(int[] array){//冒泡排序        for (int i=0; i<array.length-1; i++)        for(int j=0; j<array.length-1-i; i++){            if(array[j] > array[j+1]){                int temp = array[j];                array[j] = array[j+1];                array[j+1] = temp;            }        }    }    public static int binarySearch(int[] array, int num){//二分法/折半查找法        int min = 0;        int max = array.length - 1;        int mid = (min + max) / 2;        while(min <= max) {            if (array[mid] < num) {                min = mid + 1;                mid = (min + max) / 2;            } else if (array[mid] > num) {                max = mid - 1;                mid = (min + max) / 2;            } else                return mid;        }        return -1;    }}

帮助文档的制作_以ArrayTools类为例

需求

如果将ArrayTools.class文件发送给其他人,其他人只需要将该文件设置到classpath的路径下,就可以使用该工具类,但是对方不清楚该类中定义了多少方法,所以需要制作程序使用说明书,java的说明书通过文档注释来完成。

制作方法

注意:私有的方法不会被提取到帮助文档。

/**  对数组进行操作的工具类,提供了获取最大值、最小值、输出数组、选择排序、冒泡排序、折半查找法功能。    @author 高世皓    @version V1.0 */public class ArrayTools {    /**     空参数构造函数,被私有化     */    private ArrayTools(){}    /**     获取一个整形数组中的最大值     @param  array 接收一个int类型的数组     @return 会返回一个该数组中的最大值     */    public static int getMax(int[] array){        int max = 0;        for(int i=1; i<array.length; i++){            if(array[i] > array[max])                max = i;        }        return array[max];    }    /**     获取一个整形数组中的最小值     @param  array 接收一个int类型的数组     @return 会返回一个该数组中的最小值     */    public static int getMin(int[] array){        int min = 0;        for(int i=1; i<array.length; i++){            if(array[i] < array[min])                min = i;        }        return array[min];    }    /**     打印一个整形数组中的元素     @param  array 接收一个int类型的数组     */    public static void printArray(int[] array){        System.out.printf("[");        for(int i=0; i<array.length; i++){            if(i != array.length - 1)                 System.out.print(array[i] + ", ");            else                System.out.println(array[i] + "]");        }    }    /**     选择排序,对一个整形数组按照从小到大的顺序排序     @param  array 接收一个int类型的数组     */    public static void selectSort(int[] array){        for(int i=0; i<array.length-1; i++){//遍历数组            for(int j=i+1; j<array.length; j++)                if(array[j] < array[i]) {                    int temp = array[i];                    array[i] = array[j];                    array[j] = temp;                }        }    }    /**     冒泡排序,对一个整形数组按照从小到大的顺序排序     @param  array 接收一个int类型的数组     */    public static void bubbleSort(int[] array){        for (int i=0; i<array.length-1; i++)        for(int j=0; j<array.length-1-i; i++){            if(array[j] > array[j+1]){                int temp = array[j];                array[j] = array[j+1];                array[j+1] = temp;            }        }    }    /**     二分法/折半查找法,查找某个数值在整形数组中的位置,没有返回-1     @param  array 接收一个int类型的数组     @param  num 要查找的数值     @return 返回查找到的位置索引     */    public static int binarySearch(int[] array, int num){        int min = 0;        int max = array.length - 1;        int mid = (min + max) / 2;        while(min <= max) {            if (array[mid] < num) {                min = mid + 1;                mid = (min + max) / 2;            } else if (array[mid] > num) {                max = mid - 1;                mid = (min + max) / 2;            } else                return mid;        }        return -1;    }}

使用命令javadoc -d myHelpDoc ArrayTools.java -author -version生成说明书,注意myHelpDoc为文件夹的名称,如果该目录下没有该文件夹,则会自动生成一个。

这里写图片描述

帮助文档效果

打开其中的index.html即可:
这里写图片描述

这里写图片描述

静态代码块

格式

static{
静态代码块中的执行语句。
}

特点

随着类的加载而运行,只执行一次,并优先于主函数,用于给类进行初始化的。
eg1:

/* b c a end */class staticCode{    static{        System.out.println("a");    }}class Demo{    static{        System.out.println("b");    }    public static void main(String[] args){        new staticCode();        new staticCode();//此时类已经加载了,不再执行静态代码块        System.out.println("end");    }    static{        System.out.println("c");    }}

eg2:

/*   a   show code */class staticCode{    static{        System.out.println("a");    }    public static void show(){        System.out.println("show code");    }}class Demo{    public static void main(String[] args){        staticCode.show();    }}

eg3:

/*    静态代码块    构造代码块, num = 2    构造函数2 */class staticCode{    int num = 2;    {//给对象初始化        System.out.println("构造代码块" + ", num = " + num);    }    static{//给类初始化,不能访问num,因为num为非静态变量        System.out.println("静态代码块");    }    staticCode(){        System.out.println("构造函数1");    }    staticCode(int x){        System.out.println("构造函数2");    }    public static void show(){        System.out.println("show code");    }}class Demo{    public static void main(String[] args){        new staticCode(4);    }}

对象的初始化过程

public class Demo{    public static void main(String[] args){        Person p = new Person("liming", 23);        p.show();    }}class Person{    private String name = "shgao";    private int age;    private static String country = "CN";    {//给对象初始化        System.out.println("构造代码块");    }    static {//给类初始化        System.out.println("静态代码块");    }    Person(String name, int age){        this.name = name;        this.age = age;        System.out.println("构造函数初始化");    }    void show(){        System.out.println("name: " + name + ", " +                            "age: " + age + ", country: " + country);    }}

执行顺序

 Person p = new Person("liming", 23);1.new用到了Person.class,会找到Person.class文件并加载到内存中;2.执行该类中的静态代码块和静态变量初始化,给类进行初始化,顺序由上至下;3.在堆内存中开辟空间,分配内存地址;4.在堆内存中建立对象的特有属性,并进行默认初始化(0 null);5.对对象进行显示初始化;5.对对象进行构造代码块初始化;6.对对象进行对应的构造函数初始化;7.将内存地址赋值给栈内存中的p变量。