文章目录
this和static
1. static关键字
- static修饰的统一都是静态的,都是类相关的,不需要 nwe 对象。直接采用"类名."访问
- 当一个属性是类级别的属性所有对象的这个属性的值都是一样的,建议定义为静态变量。
/* file: StaticTest01.java */
/*
static:
1、static 翻译为 “静态”
2、所有的static关键字修饰的都是类相关的,类级别的。
3、所有static修饰的,都是采用 “类名.” 的方式访问。
4、static修饰的变量:静态变量
5、static修饰的方法:静态方法
变量的分类:
- 变量根据申明的位置进行划分:
- 在方法体当中声明的变零叫做:局部变量。
- 在方法体外声明的变零叫做:成员变量。
- 成员变量又可以分为:
- 实例变量
- 静态变量
*/
class VarTest{
// 一下实例的,都是对象相关的,访问时采用 "引用."的方式访问。需要先new对象。
// 实例相关的,必须先有对象,才能访问,可能会出现空指针异常。
// 成员变量中的实例变量
int i;
//实例方法
public void m2(){
//局部变量
int x = 100;
}
// 成员变量中的静态代变量
static int k;
// 静态方法
public static void m1(){
// 局部变量
int x = 200;
}
}
2.什么时候变量声明为实例的,什么时候声明为静态的?
- 如果这个类型的所有对象的某个属性都是一样的,不建议定义为实例变量,浪费内存空间。
建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。
将属性 国籍 设置为 实例变量
/* file: StaticTest02.java */
/*
什么时候变量声明为实例的,什么时候声明为静态的?
*/
public class StaticTest02{
public static void main(String[] args){
Chinese c1 = new Chinese("123423455231456241", "张三", "中国");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(c1.country);
Chinese c2 = new Chinese("252345125453425234", "李四", "中国");
System.out.println(c2.idCard);
System.out.println(c2.name);
System.out.println(c2.country);
}
}
// 定义一个类:中国人
class Chinese{
// 身份证号
String idCard;
// 姓名
String name;
// 国籍
// 对于“中国人”这个类来说,国籍都是“中国”,不会随着对象的改变而改变。
// 显然国籍并不是对象级别的特征。
// 国籍属于整个类的特征。内存图的特征。
// 假设声明为实例变量,内存图是怎样的?
// 假设声明为静态变量,内存图又是怎样的?
String country;
// 无参构造
public Chinese(){
}
// 有参构造
public Chinese(String s1, String s2, String s3){
idCard = s1;
name = s2;
country = s3;
}
}
- 内存图:
将属性 国籍 设置为 静态变量
/* file: StaticTest03.java */
*/
/*
实例的:一定要使用"引用."来访问
静态的:建议使用"类名."来访问,但是用"引用."也行(不建议使用"引用.")。
静态的如果使用"引用."来访问会让程序员产生疑惑:程序员以为是实例的呢。
结论:
空指针异常只是在什么情况下才会发生呢?
只会在访问"实例"相关的,才会出现空指针异常。
*/
public class StaticTest02{
public static void main(String[] args){
// 访问中国人的国籍
// 静态变量应该使用类名.的方式访问
System.out.println(Chinese.country);
Chinese c1 = new Chinese("123423455231456241", "张三");
System.out.println(c1.idCard);
System.out.println(c1.name);
Chinese c2 = new Chinese("252345125453425234", "李四");
System.out.println(c2.idCard);
System.out.println(c2.name);
// idCard 是实例变量,必须先呢 new 对象,通过“引用.”访问
// 错误:无法从静态上下文引用非静态变量 idCard
//System.out.println(Chinese.idCard);
}
}
// 定义一个类:中国人
class Chinese{
// 身份证号
// 每一个人的身份证号不同,所以身份证号应该是实例变量,一个对象一份。
String idCard;
// 姓名
// 姓名也是一个人一个姓名,姓名也应该是实例变量。
String name;
// 国籍
// 重点重点五颗星: 加载 static 的变量叫做静态变量
// 静态变量在类加载时初始化,不需要 new 对象,静态变量的空间就开出来了.
// 静态变量存储在方法区.
static String country = "中国";
// 无参构造
public Chinese(){
}
// 有参构造
public Chinese(String s1, String s2){
idCard = s1;
name = s2;
}
}
- 内存图
3.关于方法来说,什么时候定义为实例方法,什么时候定义为静态方法?
- 有没有参考标准。
- 此方法一般都是描述了一个行为,如果说该行为必须由对象去触发。那么该方法定义为实例方法。
- 参考标准:
-
当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。
-
我们以后开发中,大部分情况下,如果是工具类的话,工具类当中的方法
一般都是静态的。(静态方法有一个优点,是不需要new对象,直接采用类名
调用,极其方便。工具类就是为了方便,所以工具类中的方法一般都是static的。) -
什么是工具类?????
工具类就是为了方便编程而开发的一些类。 -
类=属性+方法
- 属性描述的是:状态
- 方法描述的是:行为动作
- 一个方法代表了一个动作。
-
什么时候方法定义为实例方法?
张三考试,得分90
李四考试,得分100
不同的对象参加考试的结果不同。
我们可以认定"考试"这个行为是与对象相关的行为。
建议将"考试"这个方法定义为实例方法。
-
/* file: StaticTest04.java */
public class StaticTest04{
public static void main(String[] args){
// 这是比较正规的方式,静态方法采用“类名.”
StaticTest04.doSome();
// 对象
StaticTest04 st = new StaticTest04();
//用"引用."访问
st.doOther();
st = null;
// 不会出现空指针异常
st.doSome(); // 这个代码在最终执行董事时候还是会转换为:StaticTest04.doSome();
// 实例方法doOther()
// 对象级别的方法(先new对象,通过"引用."来访问)
// 错误: 无法从静态上下文中引用非静态 方法 doOther()
//StaticTest04.doOther();
StaticTest04 st2 = new StaticTest04();
st2.doOther();
// 空引用
st2 = null;
// 空引用调用实例方法会出现什么问题?空指针异常。
//st2.doOther();
}
// 静态方法(静态方法不需要 new 对象,直接使用“类名.”来访问)
// 但是也可以使用 "引用."的来访问,不建议使用。
public static void doSome(){
// 用"引用."访问
System.out.println("静态方法doSome()执行了!");
}
// 实例方法(实例相关的都需要 new 对象,使用"引用."来访问)
public void doOther(){
System.out.println("实例方法doOther()执行了!");
}
}
4.static关键字定义静态代码块
-
使用static关键字可以定义:静态代码块
-
什么是静态代码块,语法是什么?
static {
java语句;
java语句;
}
-
static静态代码块在什么时候执行呢?
- 类加载时执行。并且只执行一次。
- 静态代码块有这样的特征/特点。
-
注意:静态代码块在类加载时执行,并且在main方法执行之前执行。
-
静态代码块一般是按照自上而下的顺序执行。
-
静态代码块有啥用?
- 第一:静态代码块不是那么常用。(不是每一个类当中都要写的东西。)
- 第二:静态代码块这种语法机制实际上是sun公司给我们java程序员的一个特殊的时刻/时间
这个时机叫做:类加载时机。
-
具体的业务:
项目经理说了:大家注意了,所有我们编写的程序中,只要是类加载了,请记录一下
类加载的日志信息(在哪年哪月哪日几时几分几秒,哪个类加载到JVM当中了)。
思考:这些记录日志信息的代码写到哪里?
写到静态代码块中
/* file: StaticTest06.java */
public class StaticTest06{
//静态代码块
static{
System.out.println("A");
}
//一个类中可以编写多个静态代码块
static{
System.out.println("B");
}
public static void main(String[] args){
System.out.println("hello world!");
}
// 编写一个静态代码块
static {
System.out.println("C");
}
/*程序执行结果:
A
B
C
hello world!
*/
}
静态变量在什么时候初始化?类加载时初始化。静态变量存储在哪里?方法区。
/* file: StaticTest07.java */
public class StaticTest07{
// 静态变量在什么时候初始化?类加载时初始化。
// 静态变量存储在哪里?方法区。
static int i = 100;
static{
// 这里可以访问 i 吗?
System.out.println("i = " + i);
}
// 实例变量
int k = 111; // k变量是实例变量,在构造方法执行时内存才会开辟。
static {
// k变量可以访问吗?
// static静态代码块在类加载时执行,并且只只执行一次。
// 类加载实时 k变量还没有开辟出来呢
//无法从静态上下文中引用非静态 变量 k
//System.out.println("k = " + k);
//这里可以访问那么吗?
//错误: 非法前向引用
// 静态代码块和静态变量都在类加载的时候执行,时间相同,只能靠代码的前后顺序来决定谁先执行
//System.out.println("name = " + name);
}
// 静态变量在静态代码块下面
static String name = "张三";
//入口(main方法执行之前实际上执行了很多代码)
public static void main(String[] args){
System.out.println("main begin");
}
}
- 总结:
- 到目前为止,你遇到的所有java程序,有顺序要求的是哪些?
- 第一:对于一个方法来说,方法体中的代码是有顺序的,遵循自上而下的顺序执行。
- 第二:静态代码块1和静态代码块2是有先后顺序的。
- 第三:静态代码块和静态变量是有先后顺序的。
- 到目前为止,你遇到的所有java程序,有顺序要求的是哪些?
5.除了静态代码块之外,还有一种语句块叫做:实例语句块
- 除了静态代码块之外,还有一种语句块叫做:实例语句块
- 实例语句在类加载是并没有执行
- 实例语句语法?
{
java语句;
java语句;
java语句;
}
- 实例语句块在什么时候执行?
只要是构造方法执行,必然在构造方法执行之前,自动执行“实例语句块”中的代码。
实际上这也是SUN公司为java程序员准备一个特殊的时机,叫做对象构建时机。
/* file: InstanceCode.java */
public class InstanceCode{
// 入口
public static void main(String[] args) {
System.out.println("main begin");
}
// 实例语句块
{
System.out.println("实例语句块执行!");
}
// Constructor
public InstanceCode(){
System.out.println("无参数构造方法");
}
// Constructor
public InstanceCode(String name){
System.out.println("有参数构造方法");
}
}
7.判断一下程序的执行顺序(static关键字结束)
/* file: CodeOrder.java */
//判断一下程序的执行顺序
public class CodeOrder{
// 静态代码块
static{
System.out.println("A");
}
//入口
public static void main(String[] args){
System.out.println("Y");
new CodeOrder();
System.out.println("Z");
}
// 构造方法
public CodeOrder(){
System.out.println("B");
}
// 实例代码块
{
System.out.println("C");
}
//静态代码块
static {
System.out.println("X");
}
}
/*
程序执行结果:
A
X
Y
C
B
Z
*/
7.判断一下程序的执行顺序(static关键字结束)
/* file: CodeOrder.java */
//判断一下程序的执行顺序
public class CodeOrder{
// 静态代码块
static{
System.out.println("A");
}
//入口
public static void main(String[] args){
System.out.println("Y");
new CodeOrder();
System.out.println("Z");
}
// 构造方法
public CodeOrder(){
System.out.println("B");
}
// 实例代码块
{
System.out.println("C");
}
//静态代码块
static {
System.out.println("X");
}
}
/*
程序执行结果:
A
X
Y
C
B
Z
*/