Java学习6:static关键字

特点

  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”:
Java学习6:static关键字_第1张图片

实例变量和类变量的区别

存放位置

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

生命周期

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

静态使用注意事项

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函数,在后面可以传入字符串,见下图:
Java学习6:static关键字_第2张图片

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; iif(array[i] > array[max])
                max = i;
        }
        return array[max];
    }

    public static int getMin(int[] array){//求数组最小值
        int min = 0;
        for(int i=1; iif(array[i] < array[min])
                min = i;
        }
        return array[min];
    }

    public static void printArray(int[] array){//输出数组
        System.out.printf("[");
        for(int i=0; iif(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; i1; i++){//遍历数组
            for(int j=i+1; jif(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; i1; i++)
        for(int j=0; j1-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; iif(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; iif(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; iif(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; i1; i++){//遍历数组
            for(int j=i+1; jif(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; i1; i++)
        for(int j=0; j1-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为文件夹的名称,如果该目录下没有该文件夹,则会自动生成一个。

Java学习6:static关键字_第3张图片

帮助文档效果

打开其中的index.html即可:
Java学习6:static关键字_第4张图片

Java学习6:static关键字_第5张图片

静态代码块

格式

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变量。

你可能感兴趣的:(Java)