static 关键字
基本概念
-
使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级升级为类层级,也就是整个类只有一份并被所有对象共享,该成员变量随着类的加载 (把字节码文件往内存中读的过程) 准备就绪,与是否创建对象无关(在创建对象前使用类名.的方式去访问就可以判断出与是否创建对象无关了)。
-
-
-
static 关键字修饰的成员可以使用引用 . 的方式访问(对象层级),但推荐使用 类名 . 的方式(类层级)。
/* 编程实现People类的封装 */ public class People { // 1、私有化成员变量 private String name; // 姓名 private int age; // 年龄 // private String country; // 国籍 未被static关键字所修饰的成员变量隶属于对象层级,也就是每个对象都拥有独立的一份 public static String country; // 加了static关键字之后隶属于类层级,也就是整个类只有一份并且被所有对象所共享 // 3、在构造方法中调用set方法进行合理值的判断 public People() {} public People(String name, int age, String country) { setName(name); setAge(age); setCountry(country); } // 2、提供公有的get和set方法,并在方法体中进行合理值的判断 public String getName() { return name; } public int getAge() { return age; } public String getCountry() { return country; } public void setName(String name) { this.name = name; } public void setAge(int age) { if(age > 0 && age <= 150) { this.age = age; } else { System.out.println("年龄不合理!!!"); } } public void setCountry(String country) { this.country = country; } public void show() { System.out.println("我是" + getName() + ",今年" + getAge() + "岁了,来自" + getCountry() + "\n"); } }
/* 编程实现People类的测试 */ public class PeopleTest { public static void main(String[] args) { // 3、验证static关键字修饰的静态成员(类变量)是否与创建对象无关 类名.的方式 => 与创建对象无关 System.out.println("获取到的国籍信息是:" + People.country); // null // 1、使用有参方式构造两个People类型的对象并打印特征 People p1 = new People("淳神", 21, "中国"); p1.show(); // 我是淳神,今年21岁了,来自中国 People p2 = new People("佘儿", 20, "中国"); p2.show(); // 我是佘儿,今年20岁了,来自中国 System.out.println("--------------------------------------"); // 2、验证static关键字修饰的静态成员(类成员)是否被所有对象共享 => 确实是共享的内容 p1.country = "华夏"; p1.show(); // 华夏 p2.show(); // 华夏 证明了country是共享的 People p3 = new People(); p3.show(); // 华夏 } }
使用方式
-
static 关键字不仅可以修饰成员变量,还可以修饰成员方法。
-
在非静态成员方法中既能访问非静态的成员又能访问静态的成员。(成员:成员变量 + 成员方法,因为静态成员被所有对象共享,静态成员变量也可以通过引用.的方式进行访问)
-
在静态成员方法中只能访问静态成员变量而不能访问非静态成员(成员:成员变量 + 成员方法,因为此时可能还没有创建对象,在静态成员方法中不能使用this也是此理,因为是通过类名.的方式来调用的,此时并没有对象,而this是当前对象),当然,也可能此时已经创建了对象,但是只要有没创建对象的可能性,那我们就不能解析,又一次证明了Java是一门安全的语言。
-
在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用static关键字修饰。(不能滥用static关键字)
-
静态测试类
/* 编程实现static关键字的使用 */ public class StaticTest { // static 关键字的用法一:修饰成员变量 private int cnt = 1; // 隶属于对象层级,也就是每个对象都拥有独立的一份 private static int snt = 2; // 隶属于类层级,也就是所有被类对象都共享同一份 // static 关键的用法二:修饰成员方法 // 自定义非静态的成员方法 需要使用引用.的方式访问 public void show() { // 结论一:在非静态的成员方法中,既能访问非静态的成员变量,还可以访问静态的成员变量(类成员变量) System.out.println("cnt = " + this.cnt); // 1 System.out.println("snt = " + this.snt); // 2 静态成员被所有对象共享,this关键字可以省略 } // 自定义静态的成员方法 推荐使用类名.的方式访问,当然使用引用.的方式访问也是可以的 public static void test() { // 结论二:静态成员方法中没有this关键字,因为是可以通过类名.的方式调用的 // System.out.println("cnt = " + this.cnt); // 编译报错 错误: 无法从静态上下文中引用非静态 变量 this this代表当前正在调用的对象,但是现在静态方法不是用引用.调用的,此时使用类名.访问,当前没有对象 // System.out.println("snt = " + this.snt); // 错误: 无法从静态上下文中引用非静态 变量 this // System.out.println("cnt = " + cnt); // 编译报错 错误: 无法从静态上下文中引用非静态 变量 cnt // 结论三:在静态成员方法中只能访问静态成员变量而不能访问非静态成员 System.out.println("snt = " + snt); // } public static void main(String[] args) { StaticTest st = new StaticTest(); st.show(); System.out.println("-----------------------------------"); StaticTest.test(); } }
-
使用static后修改的People类
/* 编程实现People类的封装 */ public class People { // 1、私有化成员变量 private String name; // 姓名 private int age; // 年龄 // private String country; // 国籍 未被static关键字所修饰的成员变量隶属于对象层级,也就是每个对象都拥有独立的一份 // public static String country; // 加了static关键字之后隶属于类层级,也就是整个类只有一份并且被所有对象所共享 private static String country; // 3、在构造方法中调用set方法进行合理值的判断 public People() {} public People(String name, int age/*, String country*/) { setName(name); setAge(age); // setCountry(country); } // 2、提供公有的get和set方法,并在方法体中进行合理值的判断 public String getName() { return name; } public int getAge() { return age; } public static String getCountry() { return country; } public void setName(String name) { this.name = name; } public void setAge(int age) { if(age > 0 && age <= 150) { this.age = age; } else { System.out.println("年龄不合理!!!"); } } public static void setCountry(String country) { // this.country = country; People.country = country; } public void show() { System.out.println("我是" + getName() + ",今年" + getAge() + "岁了,来自" + getCountry() + "\n"); } }
-
使用static关键字后修改的PeopleTest类
/* 编程实现People类的测试 */ public class PeopleTest { public static void main(String[] args) { // 3、验证static关键字修饰的静态成员(类变量)是否与创建对象无关 类名.的方式 => 与创建对象无关 // System.out.println("获取到的国籍信息是:" + People.country); // null System.out.println("获取到的国籍信息是:" + People.getCountry()); // null // 1、使用有参方式构造两个People类型的对象并打印特征 // People p1 = new People("淳神", 21, "中国"); People p1 = new People("淳神", 21); p1.show(); // 我是淳神,今年21岁了,来自中国 // People p2 = new People("佘儿", 20, "中国"); People p2 = new People("佘儿", 20); p2.show(); // 我是佘儿,今年20岁了,来自中国 System.out.println("--------------------------------------"); // 2、验证static关键字修饰的静态成员(类成员)是否被所有对象共享 => 确实是共享的内容 // p1.country = "华夏"; p1.setCountry("华夏"); // p1.show(); // 华夏 // p2.show(); // 华夏 证明了country是共享的 System.out.println("第一个对象的国籍是:" + p1.getCountry()); System.out.println("第二个对象的国籍是:" + p2.getCountry()); People p3 = new People(); // p3.show(); // 华夏 System.out.println("第三个对象的国籍是:" + p3.getCountry()); } }
构造块和静态代码块(熟悉)
-
构造块:在类体中直接使用{}括起来的代码块。在类体的里面,方法块的外面,不属于任何一个方法。
-
每创建一个对象都会执行一次构造块。
-
静态代码块:使用static关键字修饰的构造块。
-
静态代码块随着类加载时执行一次。
-
这一块暂时用不到,但是后续会用到,一定要会。
/* 编程实现构造块和静态代码块的使用 */ public class BlockTest { // 当需要在执行构造方法之前做一些准备工作时,则将准备工作的相关代码写在构造快中即可,比如:在创建对象时对成员变量进行的统一初始化操作 /* 构造方法有很多不同的版本,调用不同版本的构造方法成员变量的初始化结果值可能不同, 此时可以通过构造快实现一个统一的成员变量初始化, 无论调用哪个构造方法,都可以让它做一个统一的初始化, 这也是构造块比构造方法更强大的一个点 */ // 构造块是在执行构造方法之前执行 // 注意:创建一次对象执行一次 { System.out.println("构造块"); // (2) } // 执行顺序:静态代码块 => 构造块 => 构造方法 因为静态代码块是随着类的加载就准备就绪的 // 静态代码块会随着类的加载而准备就绪,类的加载只有一次,所以静态代码块就执行一次,会先于构造块执行 // 静态代码块与是否创建对象无关,是在类加载的时候执行的,而构造块是在创建对象时对成员变量进行统一的初始化操作,是在创建对象的时候执行的,故而先执行静态代码块 // 当需要在执行代码块之前随着类的加载做一些准备工作时,则编写代码到静态代码块中,比如:加载数据库的驱动包等 // 注意:随着类的加载只会被执行一次 static { System.out.println("############静态代码块!"); // (1) } // 自定义构造方法 public BlockTest() { System.out.println("==============构造方法体!"); //(3) } public static void main(String[] args) { BlockTest bt = new BlockTest(); // 构造快是为了统一给成员变量进行初始化的,且在构造方法之前执行,每次new一个对象的时候都会调用构造块中的内容 // 构造块会随着对象的创建而去执行,而且每次创建对象都会执行构造块 BlockTest bt2 = new BlockTest(); } }
又见main方法
-
语法格式:public static void main(String[] args) {}
-
形参列表的价值在于把外面的数据带到方法体里面。
-
参数使用的举例。
-
给main方法传参:java xxx 参数1 参数2 参数3 即:参数跟在类名后面,使用空格隔开,实参使用空格隔开,有点像之前的可变长参数。如:java MainTest 张飞 关 羽 刘备 就相当于告诉它启动Java虚拟机MainTest这个类,而且往MainTest类的main方法中传递了三个实参,分别是:张飞、关羽、刘备。
/* 编程实现 main 方法的测试 */ public class MainTest { public static void main(String[] args) { System.out.println("参数数组中元素的个数是:" + args.length); System.out.println("传递给main方法的实际参数是:"); for(int i = 0; i < args.length; i ++) { System.out.println("下标为" + i + "的形参变量数值为:" + args[i]); } } } -----------------------------------dos窗口中的执行结果:------------------------------------- D:\拉勾学习\JavaBasics笔记\第一阶段_JavaSE\模块二_Java面向对象编程\Code\任务3:static关键字和继承>javac MainTest.java D:\拉勾学习\JavaBasics笔记\第一阶段_JavaSE\模块二_Java面向对象编程\Code\任务3:static关键字和继承>java MainTest 张飞 关 羽 刘备 参数数组中元素的个数是:3 传递给main方法的实际参数是: 下标为0的形参变量数值为:张飞 下标为1的形参变量数值为:关羽 下标为2的形参变量数值为:刘备