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