一.static关键字是什么?
static修饰的代码属于类,没有static修饰的属于对象
二.java为什么要设计static关键字?
因为要方便类去使用自己的方法和变量
1.如果方法和变量没有static关键字修饰
public class A {
public String name="admin";
public void run(){
System.out.println("跑得很快");
}
public void flay(){
System.out.println("飞得很高");
}
}
public class Test {
public static void main(String[] args) {
A a=new A();
a.run();
a.flay();
a.name="aa";
}
}
这里没有static关键字,如果方法和变量属于非静态的,他们只有在对象当中才会被分配内存空间那么也就是只能有对象才能调用,类不可以调用自己的属性和方法(不推荐)
2.如果方法和变量有static关键字修饰
public class A {
public static String name="admin";
public static void run(){
System.out.println("跑得很快");
}
public static void flay(){
System.out.println("飞得很高");
}
}
public class Test {
public static void main(String[] args) {
A a=new A();
a.run();
a.flay();
a.name="aa";
A.name = "xxx";
A.run();
A.flay();
}
}
有static关键字,如果方法和变量属于静态的,方法和变量会被储存在方法区,能够直接被类调用(推荐)
三.static关键字怎么用?
static可以修饰变量、方法和代码块
1.修饰变量
stati修饰的变量属于类变量,存储在方法区的静态常量池中,被所有对象共享
public class A {
public static String name="admin";
public String address="张三";
public static void run(int num){
System.out.println("跑了"+num+"米");
}
public String toString() {
return "A{" +
"name='" + name + '\'' +
"address='" + address + '\'' +
'}';
}
public class Test {
public static void main(String[] args) {
A a1=new A();
A a2=new A();
a1.name="李四";
a1.address="北京";
a1.run(10);
a2.name="王五";
a2.address="上海";
a2.run(20);
System.out.println(a1.toString());
System.out.println(a2.toString());
}
}
输出结果:
1.static修饰符修饰的代码属于类,属于类的东西是被对象所共享的。
2.此时static修饰的静态常量池里的name先是admin,再被修改为李四,最后被修改为王五,所以最终static修饰的name为王五,输出结果P1和P2的name均为王五。
3.这里void虽然被static修饰,但是方法谁调用就是谁的,方法是使用,而这个变量相当于内存空间,共享的是一块空间,所以输出结果是p1的num为10,p2的num为20。
2.修饰方法
(1)非静态方法可以调用静态方法
例如:
public class Test extends Base{
public static void run(){
}
public void flay(){
run();
}
}
flay()想要表达的时候就已经创建好了对象,有对象就一定有类(类是创建对象的模板),那么静态方法一定是存在的
(2)static修饰的方法无法调用到非静态方法
如果一个方法想要被main方法或者静态方法调用,有两种方法:
1.在非静态方法上加上static
2.在main方法中创建对象,让对象调用该非静态方法
3.修饰代码块
在main方法之前运行,目的是优化程序运行
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
}
class Base{
static {
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
public static void main(String[] args) {
new Test();
}
}
输出结果:
流程如下:
扫描---------->加载(编译)----------->运行
程序执行先去找main()方法自动程序
1.首先扫描Base类,发现没有父类
2.将Base.class加载进方法区,此时Base类当中的static代码块执行
3.main方法入栈—>执行 new Test();创建Test类对象,扫描发现有Base类父类,但是已经扫描过了就不扫描了
4.将Test.class加载进方法区,此时Test类当中的static代码块执行
5.创建子类之前先创建父类对象,先执行Base()构造器,在执行Test()构造器
例:
public class Demo {
public Demo(String aa){
System.out.println("==="+aa);
}
static {
System.out.println("11");
}
public static Demo demo=new Demo( "+++");
static {
System.out.println("22");
}
}
class Test{
public static void main(String[] args) {
Demo demo=new Demo("---");
}
}
输出结果:
流程如下:
扫描---------->加载(编译)----------->运行
1.main方法在哪里我们就先去扫描那个类—>首先去扫描Test类,发现没有父类,也没有static修饰的代码,那么编译Test类,并且将main方法入栈。
2.执行new Demo(“- - -”);在执行之前扫描Demo类,发现没有父类,所以编译Demo类,在编译的过程中static代码块按顺序优先执行。
3.首先输出的是11。
4.执行 public static Demo demo = new Demo(“+++” );此时会涉及到调用Demo构造方法,所以输出= = = + + +。
5.输出22。
6.编译完毕,回到main方法中继续执行new Demo(“—”);现在可以创建对象了!也就是进行到了运行阶段。
7.通过调用构造器创建对象:= = = - - -。