static关键字和this关键字
🏀static关键字
🥅static关键字理解
❤️static:
1、static翻译为“静态”
2、所有static关键字修饰的都是类相关的,类级别的。
3、所有static修饰的,都是采用“类名.”的方式访问。
4、static修饰的变量:静态变量
5、static修饰的方法:静态方法
❤️ 变量的分类:
⭐️变量根据声明的位置进行划分:
(1)在方法体当中声明的变量叫做:局部变量。
(2)在方法体外声明的变量叫做:成员变量。
⭐️成员变量又可以分为:
实例变量
静态变量
class VarTest{ //1. 以下实例的,都是对象相关的,访问时采用“引用.”的方式访问。需要先new对象。 // 实例相关的,必须先有对象,才能访问,可能会出现空指针异常。 int i; // 成员变量中的实例变量 public void m2(){ // 实例方法 // 局部变量 int x = 200; } //2. 以下静态的,都是类相关的,访问时采用“类名.”的方式访问。不需要new对象。 // 不需要对象的参与即可访问。没有空指针异常的发生。 static int k;// 成员变量中的静态变量 // 静态方法 public static void m1(){ // 局部变量 int m = 100; } }
🥅什么时候使用static关键字
❤️什么时候变量声明为实例的,什么时候声明为静态的?
⭐️如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费内存空间。建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。
⭐️一个对象一份的是实例变量。
⭐️所有对象一份的是静态变量。
❤️例1:不使用static
public class StaticTest02{ public static void main(String[] args){ //1.创建一个c1对象 Chinese c1 = new Chinese("123145****456456","张三","中国"); System.out.println(c1.idCard); System.out.println(c1.name); System.out.println(c1.country); //2.创建一个c2对象 Chinese c2 = new Chinese("7897897896748564","李四","中国"); System.out.println(c2.idCard); System.out.println(c2.name); System.out.println(c2.country); } } //3. 定义一个类:中国人 class Chinese{ // 每一个人的身份证号不同,所以身份证号应该是实例变量,一个对象一份。 String idCard; // 姓名也是一个人一个姓名,姓名也应该是实例变量。 String name; // 对于“中国人”这个类来说,国籍都是“中国”,不会随着对象的改变而改变。 // 显然国籍并不是对象级别的特征。 // 国籍属于整个类的特征。整个族的特征。 // 假设声明为实例变量,内存图是怎样的? // 假设声明为静态变量,内存图又是怎样的? String country; // 无参数构造方法 public Chinese(){ } // 有参数构造方法 public Chinese(String s1,String s2, String s3){ idCard = s1; name = s2; country = s3; } }
⭐️内存图
编辑
❤️例2:使用static
⭐️加static的变量叫做静态变量
(1)静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了。
(2)静态变量存储在方法区。⭐️不加static的变量叫做实例变量
(1)实例变量在new创建对象,实例变量的空间就开出来了。
(2)实例变量存储在堆区。⭐️记住一句话:静态变量在方法区,在类加载时初始化!
public class StaticTest02{ public static void main(String[] args){ // 访问中国人的国籍 // 静态变量应该使用类名.的方式访问 System.out.println(Chinese.country); Chinese c1 = new Chinese("123145****456456","张三"); System.out.println(c1.idCard); System.out.println(c1.name); Chinese c2 = new Chinese("7897897896748564","李四"); 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; } }
⭐️内存图
java中一共有三大变量:
(1)静态变量:定义在类体中,用static修饰,属于类级别的;存储在方法区
(2)实例变量:定义在类体中,不用static修饰,属于对象级别的;存储在堆区
(3)局部变量:定义在方法体中,存储在栈区
编辑
🥅空引用访问静态不会空指针
⭐️实例的:一定需要使用“引用.”来访问。
⭐️静态的:建议使用“类名.”来访问,但使用“引用.”也行(不建议使用"引用.")。
⭐️结论:空指针异常只有在“空引用”访问“实例”相关的,都会出现空指针异常。使用“引用.”访问“静态”不会出现空指针异常。
public class StaticTest03{ public static void main(String[] args){ //1. 通过"类名."的方式访问静态变量 System.out.println(Chinese.country); // 创建对象 Chinese c1 = new Chinese("1111111", "张三"); System.out.println(c1.idCard); // 1111111 System.out.println(c1.name); // 张三 //2. 通过"引用."的方式访问静态变量也是可以的 System.out.println(c1.country); // 中国 //3. c1是空引用,访问实例变量会空指针异常!访问静态变量不会空指针异常! c1 = null; //访问静态变量不会出现空指针异常。 // 因为静态变量不需要对象的存在。 // 实际上以下的代码在运行的时候,还是:System.out.println(Chinese.country); System.out.println(c1.country);// 实际上运行时会把c1替换成Chinese //4. 这个会出现空指针异常,因为name是实例变量。 //System.out.println(c1.name); } } class Chinese{ // 实例变量 String idCard; String name; // 静态变量 static String country = "中国"; //构造方法 public Chinese(String x, String y){ idCard = x; name = y; } }
🥅关于实例方法的调用
⭐️static修饰的统一都是静态的,都是类相关的,不需要new对象。直接采用“类名.”访问。
⭐️当一个属性是类级别的属性,所有对象的这个属性的值是一样的,建议定义为静态变量。
❤️例1
public class StaticTest04{ public static void main(String[] args){ //1. 对于静态变量:这是比较正规的方式,静态方法采用“类名.” StaticTest04.doSome(); //2. 对于实例变量,先new对象;用“引用.”访问 StaticTest04 st = new StaticTest04(); st.doSome(); //3. 空引用 st = null; // 对于静态变量,不会出现空指针异常 st.doSome(); // 这个代码在最终执行的时候还是会转变为:StaticTest04.doSome(); // 实例方法doOther() // 对象级别的方法(先new对象,通过“引用.”来访问) //错误: 无法从静态上下文中引用非静态 方法 doOther() //StaticTest04.doOther(); StaticTest04 st2 = new StaticTest04(); st2.doOther(); // 空引用 st2 = null; // 空引用调用实例方***出现什么问题?空指针异常。 //st2.doOther(); } //1. 静态方法(静态方法不需要new对象,直接使用“类名.”来访问) // 但是也可以使用“引用.”来访问,不建议用。(因为其他程序员会感到困惑。) public static void doSome(){ System.out.println("静态方法doSome()执行了!"); } //2. 实例方法(实例相关的都需要new对象,使用"引用."来访问。) public void doOther(){ System.out.println("实例方法doOther执行了!"); } }
⭐️总结:
从第一天开始讲解HelloWorld到目前为止,一个类当中一共就写过这些东西。
类{
实例相关的都是需要new对象的,通过"引用."访问。
实例变量;
实例方法;静态相关的都是采用“类名.”访问。也可以使用“引用.”,只不过不建议。
静态变量;
静态方法;
}
❤️例2
⭐️关于方法来说,什么时候定义为实例方法?什么时候定义为静态方法?
参考标准:当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。此方法一般都是描述了一个行为,如果说该行为必须由对象去触发。那么该方法定义为实例方法⭐️我们以后开发中,大部分情况下,如果是工具类的话,工具类当中的方法一般都是静态的。(静态方法有一个优点,是不需要new对象,直接采用类名调用,极其方便。工具类就是为了方便,所以工具类中的方法一般都是static的。)
⭐️类 = 属性 + 方法
(1)属性描述的是:状态
(2)方法描述的是:行为动作
⭐️一个方法代表了一个动作。什么时候方法定义为实例方法?例如:
张三考试,得分90,李四考试,得分100;不同的对象参加考试的结果不同。我们可以认定“考试”这个行为是与对象相关的行为。建议将“考试”这个方法定义为实例方法。
public class StaticTest05{ public static void main(String[] args){ //1.getID是实例方法,必须先new对象 User u = new User(); System.out.println(u.getId()); //0 //2.名字name是实例变量,必须先new对象 User x = new User(); x.printName1(); } } //实例变量访问的语法机制是什么? //语法:引用.实例变量名 class User{ // 实例变量,需要对象 private int id; // 实例变量 private String name; // 首先先分析的是,这个name是对象级别的,一个对象一份。 // 打印用户的名字这样的一个方法。 public void printName1(){ System.out.println(name); } public void setId(int i){// 不能加static,加static就和对象没关系了 id = i; //id是实例变量,上面必须是实例方法才行 } public int getId(){// 不能加static return id; } }
🥅静态代码块
⭐️使用static关键字可以定义:静态代码块
⭐️什么是静态代码块,语法是什么?static { java语句; java语句; }![]()
⭐️static静态代码块在什么时候执行呢?
静态代码块有这样的特征/特点:类加载时执行;并且只执行一次。⭐️注意:静态代码块在类加载时执行,并且在main方法执行之前执行。
⭐️静态代码块一般是按照自上而下的顺序执行。
⭐️静态代码块有啥作用,有什么用?
第一:静态代码块不是那么常用。(不是每一个类当中都要写的东西。)
第二:静态代码块这种语法机制实际上是SUN公司给我们java程序员的一个特殊的时刻/时机;这个时机叫做:类加载时机。
第三:具体的业务:我们编写的程序中,只要是类加载了,请记录一下类加载的日志信息(在哪年哪月哪日几时几分几秒,哪个类加载到JVM当中了)。
第四:思考这些记录日志的代码写到哪里呢? 写到静态代码块当中。
❤️例1
public class StaticTest06{ //1. 静态代码块(特殊的时机:类加载时机。) static { System.out.println("A"); } //2. 一个类当中可以编写多个静态代码块 static { System.out.println("B"); } //3. 程序入口 public static void main(String[] args){ System.out.println("Hello World!"); } //4. main方法后再编写一个静态代码块 static{ System.out.println("C"); } } //5. 执行结果 A B C Hello World!
栈:方法只要执行,会压栈。(局部变量)
堆:new出来的对象都在堆中。垃圾回收器主要针对堆中的数据。(实例变量)
方法区:类的信息,字节码信息,代码片段。(静态变量)
总结:方法的代码片段放在方法区,但是方法执行过程当中需要的内存在栈中。补充:静态代码块可以访问静态变量;
静态代码块和静态变量都在类加载的时候执行,时间相同,只能靠代码的顺序来决定谁先谁后
public class StaticTest07{ //1. 静态变量在什么时候初始化?类加载时初始化。 // 静态变量存储在哪里?方法区 static int i = 100; //2. 静态代码块什么时候执行?类加载时执行。 //只要是代码一定存放在代码区 //--------------静态代码块可以访问静态变量! static { System.out.println("i = " + i); // 这里可以访问i } // ----------------实例变量 int k = 111; // k变量是实例变量,在new构造方法执行时内存空间才会开辟。 static { // static静态代码块在类加载时执行,并且只执行一次。 // 类加载时,k变量空间还没有开辟出来呢。 //错误: 无法从静态上下文中引用非静态 变量 k //System.out.println("k = " + k); } //3. static{ //------------------这里可以访问name吗? //错误: 非法前向引用 //静态代码块和静态变量都在类加载的时候执行,时间相同,只能靠代码的顺序来决定谁先谁后。 //System.out.println("name = " + name); } // 静态变量在静态代码块下面。 static String name = "zhangsan"; //入口(main方法执行之前实际上执行了很多代码) public static void main(String[] args){ System.out.println("main begin"); System.out.println("main over"); } }
⭐️总结:到目前为止,你遇到的所有java程序,有顺序要求的是哪些?
第一:对于一个方法来说,方法体中的代码是有顺序的,遵循自上而下的顺序执行。
第二:静态代码块1和静态代码块2是有先后顺序的。
第三:静态代码块和静态变量是有先后顺序的。
🥅实例代码块
⭐️除了静态代码块之外,还有一种语句块叫做:实例语句块
⭐️实例语句在类加载是并没有执行。
⭐️实例语句语法?{ java语句; java语句; java语句; }只要是构造方法执行,必然在构造方法执行之前,自动执行“实例语句块”中的代码;每次都会执行。
实际上这也是SUN公司为java程序员准备一个特殊的时机,叫做对象构建时机。
⭐️当几个方法有相同的代码,就可以把他们提取出来放到实列语句块里!减少代码冗余!❤️例1
public class InstanceCode{ //入口 public static void main(String[] args){ System.out.println("main begin"); new InstanceCode(); new InstanceCode(); new InstanceCode("abc"); new InstanceCode("xyz"); } //实例语句块 { System.out.println("实例语句块执行!"); } // Constructor public InstanceCode(){ System.out.println("无参数构造方法"); } // Constructor public InstanceCode(String name){ System.out.println("有参数的构造方法"); } } //执行结果 main begin 实例语句块执行! 无参数构造方法 实例语句块执行! 无参数构造方法 实例语句块执行! 有参数的构造方法 实例语句块执行! 有参数的构造方法![]()
❤️例2:判断代码执行的顺序
public class CodeOrder{ //1. 静态代码块 static{ System.out.println("A"); } //2. 程序入口 // A X Y C B Z public static void main(String[] args){ System.out.println("Y"); new CodeOrder(); System.out.println("Z"); } //3. 构造方法 public CodeOrder(){ System.out.println("B"); } //4. 实例语句块 { System.out.println("C"); } //5. 静态代码块 static { System.out.println("X"); } }![]()
总结执行顺序:静态代码块---》main方法入口---》实列语句块---》new对象(构造方法)
🏀this关键字
🥅this的内存结构
⭐️this是一个关键字,全部小写。
⭐️this是什么,在内存方面是怎样的?
(1) 一个对象一个this。
(2)this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。
(3)严格意义上来说,this代表的就是“当前对象”;this存储在堆内存当中对象的内部。⭐️this只能使用在实例方法中。谁调用这个实例方法,this就是谁。
所以this代表的是:当前对象。⭐️“this.”大部分情况下是可以省略的。
⭐️为什么this不能使用在静态方法(static)中?
this代表当前对象,静态方法中不存在当前对象。❤️例1
public class ThisTest01{ public static void main(String[] args){ //创建一个对象,并初始化为"张三" Customer c1 = new Customer("张三"); c1.shopping(); //创建另一个对象,并初始化为"李四" Customer c2 = new Customer("李四"); c2.shopping(); //static静态方法用类名调用,不需要this Customer.doSome(); } } // 顾客类 class Customer{ //1. 属性 // 实例变量(必须采用“引用.”的方式访问) String name; // 构造方法,用来创建对象和给变量初始化的 public Customer(){ //无参构造方法 } public Customer(String s){ //有参构造方法 name = s; } //3. 顾客购物的方法 // 实例方法 public void shopping(){ // 这里的this是谁?this是当前对象。 // c1调用shopping(),this是c1 // c2调用shopping(),this是c2 //System.out.println(this.name + "正在购物!"); // this. 是可以省略的。 // this. 省略的话,还是默认访问“当前对象”的name。 //实例变量我们必须用“引用.”来访问;这里实际上省略了this. System.out.println(name + "正在购物!"); } //3. 静态方法 public static void doSome(){ // this代表的是当前对象,而静态方法的调用不需要对象。矛盾了。 // 错误: 无法从静态上下文中引用非静态 变量 this //System.out.println(this); } } // ------------------------------补充: class Student{ // 实例变量,怎么访问?必须先new对象,通过“引用.”来访问。 String name = "zhangsan"; // 静态方法 public static void m1(){ //System.out.println(name); // this代表的是当前对象----------这还没有创建对象 // System.out.println(this.name); // 除非你这样------创建对象 Student s = new Student(); System.out.println(s.name); } // 为什么set和get方法是实例方法? public void setName(String s){ name = s; } public String getName(){ return name;//省略了this.实际上是this.name } // 又回到上午的问题了?什么时候方法定义为实例方法,什么时候定义为静态方法? // 如果方法中直接访问了实例变量,该方法必须是实例方法。 }![]()
⭐️内存图
编辑
❤️例2
public class ThisTest02{ //1. 实例变量,必须先new对象才能访问,采用“引用.” int i = 100; //2. 静态变量,使用"类名."就可以访问;且类名可以省略 static int k = 111; // 静态方法 public static void main(String[] args){ // 错误: 无法从静态上下文中引用非静态 变量 i // System.out.println(i); // 怎么样访问i ThisTest02 tt = new ThisTest02(); System.out.println(tt.i); // 静态变量用“类名.”访问。 System.out.println(ThisTest02.k); // 类名. 能省略 System.out.println(k); } }![]()
🥅this什么时候不能省
❤️例1
⭐️this可以使用在实例方法中,不能使用在静态方法中。
⭐️this关键字大部分情况下可以省略,什么时候不能省略呢?
在实例方法中,或者构造方法中,为了区分局部变量和实例变量,这种情况下:this. 是不能省略的。public class ThisTest03{ public static void main(String[] args){ //创建对象,调用无参构造方法 Student s = new Student(); s.setNo(111); s.setName("张三"); System.out.println("学号:" + s.getNo()); System.out.println("姓名:" + s.getName()); //创建对象,调用有参构造方法 Student s2 = new Student(2222, "李四"); System.out.println("学号:" + s2.getNo()); System.out.println("姓名:" + s2.getName()); } } // 学生类 class Student{ private int no; private String name; //构造方法无参 public Student(){ } //构造方法有参,思考一下下面的代码弊端?方法中的形参没有实际意义,不能增强可读性 public Student(int i, String s){ no = i; name = s; } /* //为了增强可读性,进行修改;但是此时又会出现问题 //根据就近原则,下面的no和name都是局部变量,和实例变量没关系! public Student(int no, String name){ //都是这里的no和name no = no; name = name; } */ // 再次更改上面的构造方法也增强以下可读性 public Student(int no, String name){ this.no = no; this.name = name; //此时加上this.就可以区分局部变量和实例变量!且不能省略! } // setter and getter方法---------也可以进行更改 public void setNo(int i){ no = i; } public int getNo(){ return no; // 这里也有this.但是可以省略!this.no当前对象的no! //return this.no; } public void setName(String name){ this.name = name; } public String getName(){ return name; } } }![]()
🥅this()的用法
⭐️this除了可以使用在实例方法中,还可以用在构造方法(无参构造调用有参构造)中。
⭐️新语法:通过当前的构造方法去调用另一个本类的构造方法,可以使用以下语法格式:
this(实际参数列表);通过一个构造方法1去调用构造方法2,可以做到代码复用。
但需要注意的是:“构造方法1”和“构造方法2” 都是在同一个类当中。最常用的就是无参构造调用有参构造!⭐️this() 这个语法作用是什么? 代码复用。
⭐️死记硬背:对于this()的调用只能出现在构造方法的第一行。❤️例1
/* 需求: 1、定义一个日期类,可以表示年月日信息。 2、需求中要求: 如果调用无参数构造方法,默认创建的日期为:1970年1月1日。 当然,除了调用无参数构造方法之外,也可以调用有参数的构造方法来创建日期对象。 */ public class ThisTest04{ public static void main(String[] args){ // 调用无参数构造方法 Date d1 = new Date(); d1.detail(); // 调用有参数构造方法 Date d2 = new Date(2008, 8, 8); d2.detail(); } } class Date{ // 以后写代码都要封装,属性私有化,对外提供setter and getter private int year; private int month; private int day; // 构造方法无参 // 调用无参数构造方法,初始化的日期是固定值。 public Date(){ System.out.println(11);//错误: 对this()的调用必须是构造器中的第一个语句 /* this.year = 1970; this.month = 1; this.day = 1; */ this(1970, 1, 1); //this只能出现在第一行!利用this从一个构造方法调用另一个构造方法;进行代码复用 } // 构造方法有参数 public Date(int year, int month, int day){ this.year = year; this.month = month; this.day = day; } // 提供一个可以打印日期的方法 public void detail(){ //System.out.println(year + "年" + month + "月" + day + "日"); System.out.println(this.year + "年" + this.month + "月" + this.day + "日"); } //setter and getter public void setYear(int year){ // 设立关卡(有时间可以设立关卡) this.year = year; } public int getYear(){ return year; } public void setMonth(int month){ // 设立关卡(有时间可以设立关卡) this.month = month; } public int getMonth(){ return month; } public void setDay(int day){ // 设立关卡(有时间可以设立关卡) this.day = day; } public int getDay(){ return day; } }![]()
❤️this小总结
⭐️this是一个关键字,是一个引用,保存内存地址指向自身。
⭐️this可以使用在实例方法中,也可以使用在构造方法中。
⭐️this出现在实例方法中其实代表的是当前对象。
⭐️this不能使用在静态方法中。
⭐️this. 大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。
⭐️this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的构造方法,目的是代码复用。
🥅小试牛刀
❤️例1
(1)定义丈夫类 Husband 和妻子类 Wife,
丈夫类的属性包括:身份证号,姓名,出生日期,妻子。
妻子类的属性包括:身份证号,姓名,出生日期,丈夫。
(2)分别给这两个类提供构造方法(无参数构造方法和有参数构造方法都要提供),
编写测试程序,创建丈夫对象,然后再创建妻子对象,丈夫对象关联妻子对象,妻子对象关联丈夫对象,
要求能够输出这个“丈夫对象”的妻子的名字,或者能够输出这个“妻子对象”的丈夫的名字。并且要求在程序中演示出空指针异常的效果。public class Test{ public static void main(String[] args){ //创建丈夫对象---调用有参构造方法 Husband h = new Husband("123456","张三","1999-1-14",null); /*//第二种---------调用另一种有参构造方法也行 Husband h = new Husband("123456","张三","1999-1-14"); */ //创建妻子对象--调用有参构造方法 Wife w = new Wife("456789","李四","2000-6-04",null);//这里null也可以换成h,在这里就把妻子和丈夫关联上 //让两者产生关联 h.wife = w; w.husband = h; //打印 System.out.println(h.name+"妻子是"+h.wife.name); System.out.println(w.name+"丈夫是"+w.husband.name); } } //---------------创建丈夫类 class Husband{ String idCard; String name; String birth; Wife wife; //无参构造方法 public Husband(){ } //第一种----------有参构造方法 public Husband(String s1,String s2,String s3,Wife w){ idCard = s1; name = s2; birth = s3; wife = w; } /* //第二种----------有参构造方法 public Husband(String s1,String s2,String s3){//最后一个不写,默认赋值上null idCard = s1; name = s2; birth = s3; } */ } //---------------创建妻子类 class Wife{ String idCard; String name; String birth; Husband husband; //无参构造方法 public Wife(){ } //有参构造方法 public Wife(String s1,String s2,String s3,Husband h){ idCard = s1; name = s2; birth = s3; husband = h; } }![]()
❤️例2
请通过代码封装,实现如下需求:
编写一个类Book,代表教材:
1.具有属性:名称(title)、页数(pageNum)
2.其中页数不能少于200页,否则输出错误信息,并赋予默认值200
3.为各属性提供赋值和取值方法
4.具有方法:detail,用来在控制台输出每本教材的名称和页数
5.编写测试类BookTest进行测试:为Book对象的属性赋予初始值,并调用Book对象的detail方法,看看输出是否正确public class Test01{ public static void main(String[] args){ //创建对象 Book b = new Book("高等数学",180);//页数不够200页 b.detail();//打印测试 Book b1 = new Book("大学物理",250);//页数够200页 b1.detail();//打印测试 //更改数据 b1.setPageNum(100);//页数不够200页 b1.detail();//打印测试 b1.setPageNum(300);//页数够200页 b1.detail();//打印测试 //打印结果 /* 页数不够200页,不够200页,默认赋值为200页 教材名称:高等数学, 教材页数:200 教材名称:大学物理, 教材页数:250 页数不够200页,默认赋值为200页 教材名称:大学物理, 教材页数:200 教材名称:大学物理, 教材页数:300 */ } } //Book类 class Book{ //1. 变量私有化 private String title; private int pageNum; //2. 构造方法 public Book(){// 无法构造方法 } public Book(String s,int i){// 有参构造方法 title = s; if(i<200){ System.out.println("页数不够200页,不够200页,默认赋值为200页"); pageNum = 200; }else{ pageNum = i; } } //3. set和get接口 public void setTitle(String s){ title = s; } public String getTitle(){ return title; } public void setPageNum(int i){ if(i<200){ System.out.println("页数不够200页,默认赋值为200页"); pageNum = 200; return; } pageNum = i; } public int getPageNum(){ return pageNum; } //4. 测试接口detail public void detail(){ System.out.println("教材名称:"+title+", 教材页数:"+pageNum);//这里实际省略了this. } }![]()
编辑
❤️例3
写一个名为Account的类模拟账户。该类的属性和方法如下所示:
(1)该类包括的属性:账户id,余额balance,年利率annualInterestRate;
(2)包含的方法:各属性的set和get方法。取款方法withdraw(),存款方法deposit()写一个测试程序
(1)创建一个Customer,名字叫Jane Smith,他有一个账号为1000,余额为2000,年利率为1.23%的账户
(2)对Jane Smith操作:
存入100元,再取出960元,再取出2000。
打印Jane Smith的基本信息
信息如下显示:
成功存入:100
成功取出:960
余额不足,取钱失败public class Homework2{ public static void main(String[] args){ // 先创建一个账户对象Account Account a = new Account("1000", 2000, 1.23); // 创建客户对象 // 传给构造方法a是让Customer对象和Account对象产生关系。 Customer c = new Customer("Jane Smith", a); /*进行测试操作 对Jane Smith操作: 存入100元, 再取出960元, 再取出2000。 */ c.getAct().deposit(100); c.getAct().withdraw(960); c.getAct().withdraw(2000); } } // 以后都是封装,所有的类都是属性私有化,对外提供setter and getter方法。 //1. 创建客户类Customer class Customer{ // 客户名字 private String name; // 客户手里应该有银行账户 private Account act; //2. 构造方法 public Customer(){ } public Customer(String name, Account act){ this.name = name; this.act = act; } //3. setter and getter方法 // 为什么要写set和get,用得着吗?用不着你也得写,因为这是“封装”规定的。 public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setAct(Account act){ this.act = act; } public Account getAct(){ return act; } } //1. 账户类Account class Account{ private String id; private double balance; private double annualInterestRate; //2. 构造方法 public Account(){// 无参构造 } public Account(String id, double balance, double annualInterestRate){ // 有参构造 // 创建对象时需要的代码。 this.id = id; this.balance = balance; this.annualInterestRate = annualInterestRate; } //3. setter and getter public void setId(String id){ // 对象创建完之后,想修改id属性调用此方法。 this.id = id; } public String getId(){ return id; } // 实例方法(需要“引用.”来调用。) public void setBalance(double balance){ //修改余额的方法。 this.balance = balance; } public double getBalance(){ return balance; } public void setAnnualInterestRate(double annualInterestRate){ this.annualInterestRate = annualInterestRate; } public double getAnnualInterestRate(){ return annualInterestRate; } //4. 存款、取款方法 // 参数表示存多少钱。 public void deposit(double money){ // 第一种 this.balance += money;//this.可省 // 第二种:调用方法来进行修改余额 this.setBalance(this.getBalance() + money);//this.可省 System.out.println("成功存入:" + money); } // 调用取钱的方法时,应该传递过来一个参数,告诉该方法要取多少钱 public void withdraw(double money){ // this(从this指向的对象中取款) if(money > this.getBalance()){ System.out.println("余额不足,取钱失败"); return; } // 程序能够执行到此处说明余额充足 this.setBalance(this.getBalance() - money); System.out.println("成功取出:" + money); } }![]()
❤️例4
public class Test03{ public static void main(String[] args){ //第一种方法 // 调用无参构造方法 Student s1 = new Student(); // 赋值 s1.setName("张三"); s1.setAge(20); s1.setAddress("北京朝阳区"); s1.setZipcode("122222"); s1.setMobile("12235224214"); //打印 System.out.println("姓名:"+s1.getName() + "," + s1.getPostAddress()); //第二种方法 //调用有参构造方法 Student s2 = new Student("李四",18,"深圳宝安区","111111","456456456456465"); //打印 System.out.println("姓名:"+s2.getName() + "," + s2.getPostAddress()); } } //1. 创建Student类-----封装 class Student{ private String name; private int age; private String address; private String zipcode; private String mobile; //2. 构造方法 public Student(){ } public Student(String name, int age, String address, String zipcode, String mobile){ this.name = name; this.age = age; this.address = address; this.zipcode = zipcode; this.mobile = mobile; } //4. getPostAddress方法 public String getPostAddress(){ return "地址:"+this.getAddress() + ",邮编:"+this.getZipcode(); //或者 return "地址:" + this.address + ",邮编:" + this.zipcode; } //3. set和get接口 public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public int getAge(){ return age; } public void setAddress(String address){ this.address = address; } public String getAddress(){ return address; } public void setZipcode(String zipcode){ this.zipcode = zipcode; } public String getZipcode(){ return zipcode; } public void setMobile(String mobile){ this.mobile = mobile; } public String getMobile(){ return mobile; } }![]()
🏀总结
❤️例1
到目前为止一个类当中可以出现的: 类体{ 实例变量; 实例方法; 静态变量; 静态方法; 构造方法; 静态代码块; 实例语句块; 方法(){ // 局部变量 int i = 100; } }
public class Review{ // 类 // 类加载机制中,是这样的:在程序执行之前,凡是需要加载的类全部加载到JVM当中。 // 先完成加载才会执行main方法。 static{ System.out.println("Review类加载时执行!"); } // 入口 // 静态方法 public static void main(String[] args){ // 局部变量 int i = 100; // 完成一个对象的一连串动作。 // 一个学生在教室先学习,学习完成之后去餐厅吃饭。 Student s1 = new Student(); // 先学习,所有调用学习这个实例方法。 s1.study(); Student s2 = new Student(); } } // 学生类 class Student{ static{ System.out.println("Student类加载时执行!"); } // 学号 private int no; // 实例变量 // 姓名 private String name; // 学生有静态变量吗? // 类级别的属性 static String job = "学习"; { System.out.println("实例语句块,构造方法执行一次,这里就执行一次!"); } // 构造方法 public Student(){ // 假设调用无参数的构造方法,默认创建的学生学号是100,名字是zhangsan this(100, "zhangsan"); // this() 在这里也使用了。 } public Student(int no, String name){ this.no = no; // 这里使用了this this.name = name; } // 封装 // setter and getter方法 public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setNo(int no){ this.no = no; } public int getNo(){ return no; } // 提供两个实例方法 public void study(){ // 私有的是可以在本类中访问的。在其它类中必须使用set和get方法。 //System.out.println(this.name + "正在努力的学习!"); //System.out.println(name + "正在努力的学习!"); // 在实例方法中调用本类其它的实例方法。 System.out.println(this.getName() + "正在努力的学习!"); //System.out.println(getName() + "正在努力的学习!"); // 方法执行到此处表示学习完成了,去吃饭。 //this.eat(); // this.可以省略 // 编译器检测到eat()方法是实例方***自动在eat()方法前添加 this. eat(); } public void eat(){ // 实例方法 System.out.println(this.getName() + "在餐厅吃饭呢!!!"); // 调用静态m1()方法 // 静态方法使用“类名.”的方式访问 // Student.m1(); // 类名. 可以省略吗?可以。 // java编译器会自动在m1()方法之前添加“类名.”,因为检测到m1()方法是一个静态方法。 m1(); } // 提供两个静态方法 public static void m1(){ System.out.println("Student's m1 method execute!"); // 调用m2()方法 //Student.m2(); m2(); } public static void m2(){ System.out.println("Student's m2 method execute!"); System.out.println("工作性质:" + job); // 编译器检测到job是一个静态变量,所以这里会自动在job前添加:Student. //System.out.println("工作性质:" + Student.job); } }![]()
❤️例2
/* 程序再怎么变化,万变不离其宗,有一个固定的规律: 所有的实例相关的都是先创建对象,通过“引用.”来访问。 所有的静态相关的都是直接采用“类名.”来访问。 大结论: 只要负责调用的方法a和被调用的方法b在同一个类当中: this. 可以省略 类名. 可以省略 */ public class Review02{ int i = 100; static int j = 1000; public void m1(){ // 访问其他类的静态方法 T.t1(); // 访问其他类的实例方法 T t = new T(); t.t2(); } public void m2(){} // 实例方法 public void x(){ // 这个方法是实例方法,执行这个方法的过程中,当前对象是存在的。对象调用这个方法 m1(); //可以的,默认会加上this. m2(); m3(); m4(); System.out.println(i); // System.out.println(this.i); System.out.println(j); // System.out.println(Review02.i); } public static void m3(){} public static void m4(){} // 问?你怎么分析这个程序? /* 第一步: main方法是静态的,JVM调用main方法的时候直接采用的是“类名.”的方式。 所以main方法中没有this。 第二步: m1() 和 m2() 方法是实例方法,按照java语法规则来说,实例方法必须先 new对象,通过“引用.”的方式访问。 */ public static void main(String[] args){ // 编译报错。 //m1(); //默认加上this.但是是static方法,不行 //m2(); m3(); // 编译器会自动识别m3()静态方法,结果是:Review02.m3(); m4(); // Review02.m4(); //System.out.println(i); // 报错 System.out.println(j); // 可以 // 想访问m1() m2()还有i,你在static方法中只能自己new Review02 r = new Review02(); System.out.println(r.i); r.m1(); r.m2(); // 局部变量,局部变量访问的时候是不需要“xxx.”的 int k = 10000; System.out.println(k); } } class T{ // 静态方法 public static void t1(){ } //实例方法 public void t2(){ } }![]()