关键字:Static
只可以修饰成员。
静态成员变量/类变量
特点:
- 随着所属类的字节码加载,就在方法区的静态区开辟内存了,这时还不存在对象;
- 因为随着类的加载就开辟内存了,所以既可以通过类名直接访问,也可以通过对象访问;
- 优先于没有被static修饰的成员变量开辟内存;
class Student {String name;//实例变量static String country="CN"; //类变量、静态成员变量 } class Demo1 {public static void main(String[] args){Student stu1=new Student();stu1.name="李四";Student stu2=new Student( );stu2.name="赵四";//在对象存在前已经开辟内存//可以通过类名直接访问System.out.println(Student.country);stu2.county="USA";System.out.println(stu1.country);//USA//county的内存只有一处,通过对象stu2更改,//再通过对象stu1访问,得到的便是更改后的数据} }
对比
非静态成员变量(实例变量)和静态成员变量的对比
- 存储数据
- 非静态成员变量存储的是每个对象特有的数据
- 静态成员变量存储的是所有对象共享的数据
- 访问方式
- 非静态成员变量只能通过对象来访问
- 静态成员变量既可以通过对象访问,也可以通过类访问
- 内存位置
- 非静态成员变量是随着所属对象的创建在堆中开辟内存
- 静态成员变量是随着类的字节码的加载,在方法区的静态区开辟内存
- 生命周期
- 非静态成员变量是随着所属对象的创建在堆中开辟内存,当所属对象成为垃圾时等待垃圾回收线程回收
- 静态成员变量是随着类的字节码的加载在方法区的静态区开辟内存,程序退出时才释放内存
静态方法
-
随着类的加载就加载到静态区,可以直接通过类访问
public static void fun() {} Student.fun();
-
必须通过对象访问
public void show() {} Student stu=new Student(); stu.show();
-
静态方法只能使用静态成员变量
非静态方法既可以使用静态成员变量,也可以使用非静态的成员变量class Student{String name;//实例变量static String country="CN"; //类变量//随着类的加载就加载到静态区,可以直接通过类名访问public static void fun(){//静态方法不能使用非静态成员System.out.print1n("He1lo" +country);}//必须通过对象访问,既可以使用静态的也可以使用非静态的public void show(){System.out.println("Hello:"+name+country);} } //静态方法只能使用静态成员 //非静态方法既可以使用静态的也可以使用非静态的 class Demo2{public static void main(String[] args){Student.fun();Student stu=new Student() ;stu.show();} }
-
什么情况下成员变量可以被修饰为static?
成员变量的值可以被所属类的对象共享 -
什么情况下成员方法可以被修饰为static?
当该方法没有用到所属类中的任何非静态成员时
静态应用——工具类
/**
*这是一个定义了操作数组常用功能的工具类,如求最大值、冒泡排序、二分法查找……
*@author xxx
*@version 1.0
*/
//若类是公共的,文件名必须与该类名称相同
public class ArrayTool{private ArrayTool(){}/***求数组中最大值*@param int[] 接收一个整型的数组*@return int 返回一个整型的数值*/public static int getMax(int[] arr){int max=arr[0];for(int i=1;i<arr.length;i++){if(arr[i]>max)max=arr[i];}return max;}/**冒泡排序算法@param int[] 接收一个整型的数组@return 无返回值*/public static void bubble(int[] arr){for(int i=0;i<arr.length-1;i++){for(int j=0;j<arr.length-i-1;j++){if(arr[j+1]<arr[j]){huan(arr,j+1,j);}}}}private static void huan(int[] arr,int i,int j){int c=arr[i];arr[i]=arr[j];arr[j]=c;}
}
解析主函数
public static void main(String[] args) {}
- **public:**该函数是公共的
- **Static:**该方法可以直接通过类名访问
- **void:**无返回值
- **main:**函数名
- **String[] args:**参数是字符串类型的数组
class Demo3{public static void main(String[] args){for(int i=0;i<args.length;i++){System.out.print1n(args[i]);}//Demo3 demos=new Demo3();//demos.main(66);main(88);}public static void main(int a){System.out.println(a);}
}
class Test{public static void main(string[] args){String[] arr={"hehe","xixi"};Demo3.main(arr);}
}
静态代码块
- 随着类的加载而执行,只执行一次,优先于main的执行
- static{……}
class Demo6
{static{System.out.println("a");}public static void main(String[] args){//Test test=new Test(); //a b c//Test.show(); //a b c 5//没有创建新的对象,因此不需要调用Test类Test test=null; //a b}static{System.out.println("b");}
}
class Test
{static int num=5; static{System.out.println("c");}public static void show(){System.out.println(num);}
}
构造代码块
- 对象一创建就执行,优先于构造函数执行
- 可以把所有对象共性的内容写在构造代码块中
- {……}
class Person
{int age;{System.out.println("哈哈");}Person(){}Person(int age){this.age=age;System.out.println("构造函数");}
}
class Demo7
{public static void main(String[] args){Person xiaohong=new Person(20);Person xiaoming=new Person(22);}
}
创建对象的过程
- 因为对象是依据字节码来创建,所以先加载字节码到方法区
- 如果有静态代码块执行静态代码块
- 在堆中开辟内存
- 给属性赋默认值
- 用初始值覆盖默认值
- 执行构造代码块
- 执行构造函数
- 把对象在堆中的地址赋给栈中的引用变量
执行次序
public class Person {//2:赋初值~{System.out.println("构造代码块");}//1:只执行一次~static{System.out.println("静态代码块");}//3public Person(){System.out.println("构造方法");}public static void main(String[] args) {Person person1=new Person();System.out.println("=============");Person person2 = new Person();}
}