JAVA——静态成员,剖析main函数机理

静态:static
用法:是一个修饰符,用于修饰成员(成员变量,成员函数).
当成员被静态修饰以后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用。类名.静态成员。
特有数据随着对象存储。

class Person
{
    String name;    //成员变量,实例变量
    static String country = "CN";       //静态成员变量,类变量
    public static void show()
    {
        System.out.println(name);
    }
}

static特点:
1>随着类的加载而加载,随着类的消失而消失,说明它的声明周期长。因此对于那些不被共享的数据如果定义为静态的,那就会很耗资源。
2>优先于对象存在,就是说Person类加载以后,static类型变量就存在于方法区了,而对象还没创建呢。静态是先存在的,对象是后存在的。
3>被所有对象所共享
4>可以直接被类名所调用

class Person
{
    String name;    //成员变量,实例变量
    static String country = "CN";       //静态成员变量,类变量
    public static void show()
    {
        System.out.println(country+name);
    }
}
class StaticDemo{
    public static void main(String[] args)
    {
        Person p = new Person();
        p.name = "Zhangsan";
        p.show();
        System.out.println(Person.country);
    }
}

实例变量与类变量的区别:
1.存放位置:类变量随着类的加载而存在于方法区中,实例变量随着对象的建立而存在于堆内存中。
2.生命周期:类变量的生命周期最长,随着类的消失而消失;实例变量生命周期随着对象的消失而消失。

静态使用的注意事项:

1>静态方法只能访问静态成员(成员和方法),非静态方法既可以访问静态也可以访问非静态。
当用Person调用show时,系统会提示错误。现在我们这么想,因为name是属于对象的,随着对象的创建而创建,而静态函数show是随着类的创建而创建的,对象都没创建,你就调用name,肯定不对嘛!

2>静态方法中不可以定义this,super关键字。因为静态优先于对象存在,所以静态方法中不可以出现this。

3>主函数是静态的

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

主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用。

class MainDemo{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

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

class MainDemo{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
    public static void main(int x)
    {

    }
}

这是函数重载,虚拟机只识别字符数组格式的main函数。
很多人对虚拟机到底传了啥值给main函数
System.out.println(args);打印看看[Ljava.lang.String;@139a55,[数组实体,String类型,@139a55是哈希值。
那么数组的长度又是多少呢?System.out.println(args.length);
结果为0;
所以传入的是new String[0];

//其实我们可以修改传入的值;
//对于上面的主函数,
System.out.println(args.length);
System.out.println(args[]);
//在DOS下运行:
javac MainDemo.java
java MainDemo haha heiehi hoho
//运行结果为:
//3
//haha

什么时候使用静态?
从两方面入手:因为静态修饰的内容有成员变量和函数。什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰,对象中的特有数据要定义为非静态存在于堆内存中。

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

class Person
{
    String name;
    public static void show()
    {
        System.out.println("HAHA");
    }
}
class StaticDemo
{
    public static void main(String[] args)
    {
        Person.show();
    }
}

这里show()没有用到对象的特有数据name,所以可以设为static的。

static代码块

/**静态代码块: 格式: static { 静态代码块中的执行语句。 } 特点:随着类的加载而执行,只执行一次。用于给类进行初始化的。并优先于主函数 */
class StaticBlock
{
    static
    {
        System.out.print("a ");
    }
}

class StaticBlockDemo
{
    static
    {
        System.out.print("b ");
    }
    public static void main(String[] args)
    {
        new StaticBlock();
        new StaticBlock();
        System.out.print("Over");
    }
    static
    {
        System.out.print("c ");
    }

}
//b c a over 因为StaticBlock加载完一次以后下次就不再加载了。

static的应用

/** 这是一个可以对数组进行操作的工具类,该类中提供了,获取最值,排序等功能。 @author Jungle @version V1.1 */
public class ArrayDemo {
    /** 空参数构造函数。 */
    private ArrayDemo(){};
    /** 获取一个整型数组中的最大值  @param arr 接收一个int类型的数组  @return 会返回一个该数组中最大值 */
    public static int getMax(int[] arr)
        {
            int max = 0;
            for(int i = 1;i<arr.length;i++)
            {
                if(arr[i]>arr[max])
                {
                    max = i;
                }
            }
            return arr[max];
        }

        /** 获取一个整型数组中的最小值  @param arr 接收一个int类型的数组  @return 会返回一个该数组中最小值 */
        public static int getMin(int[] arr)
        {
            int min = 0;
            for(int i = 1;i<arr.length;i++)
            {
                if(arr[i]<arr[min])
                {
                    min = i;
                }
            }
            return arr[min];
        }
            /** 给int数组进行选择排序。  @param arr 接收一个int类型的数组 */
        public static void selectSort(int[] arr)
        {
            for(int i = 0;i<arr.length-1;i++)
                for(int j =i+1;j<arr.length;j++ )
                {
                    if(arr[i]>arr[j])
                    {
                        swap(arr,i,j);
                    }
                }
        }
        /** 给int数组进行冒泡排序。  @param arr 接收一个int类型的数组 */
        public static void bubbleSort(int []arr)
        {
            for(int i = 0;i<arr.length-1;i++)
                for(int j =0;j<arr.length-i-1;j++)
                {
                    if(arr[j]>arr[j+1])
                    {
                        swap(arr,j,j+1);
                    }
                }
        }
        /** 给数组中元素进行位置的置换  @param arr 接收一个int类型的数组  @param a 要置换的位置  @param b 要置换的位置 */
        private static void swap(int[] arr,int a,int b )
        {
            int temp = arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }

        /** 用于打印数组中的元素。打印形式是[element1,element2,element3,.....]  @param arr 接收一个int类型的数组 */
        public static void prinT(int[] arr)
        {
            System.out.print("[");
            for(int k = 0;k<arr.length;k++)
        {
            if(k!=arr.length-1)
                System.out.print(arr[k]+",");
            else
                System.out.print(arr[k]+"]");
        }
    }

}

/* 一个类中默认会有一个空的构造函数,该构造函数的的权限随着类的访问权限的变化而变化。 */


class ArrayToolDemo
{
    public static void main(String[] args)
    {
        int []arr = {3,4,1,8,6,9,15,2};
        /*ArrayDemo tool = new ArrayDemo(); int max = tool.getMax(arr); int min = tool.getMin(arr); System.out.print("max:"+max+"\t"+"min:"+min+"\n"); tool.selectSort(arr); tool.prinT(arr);*/
        int max = ArrayDemo.getMax(arr);
        int min = ArrayDemo.getMin(arr);
        System.out.print("max:"+max+"\t"+"min:"+min+"\n");
        ArrayDemo.selectSort(arr);
        ArrayDemo.prinT(arr);

    }
}

注释部分是本来想用对象调用方法的,后来static用上以后,根本没有创建对象的必要了。

例子:

class Demo
    public void func()
    {
        //位置1;
    }
    class Inner{}
    public static void main(String[] args)
    {
        Demo d = new Demo();
        //位置2
    }
}
A.在位置1new Inner();//OK
B.在位置2new Inner();//不可以,因为主函数是静态的。如果访问Inner需要被static修饰
C.在位置2new d.Inner();//不可以,new new Demo().Inner();是错误格式
D.在位置2new Demo.Inner();//错误,因为Inner不是静态的。

你可能感兴趣的:(java,String,函数,对象,存储)