第十一章 static和this关键字

1 static

1.1 static引入

static:
1、static翻译为“静态的”
2、所有static关键字修饰的都是类相关的,类级别的。
3、所有static修饰的,都是采用“类名.”的方式访问。
4、static修饰的变量:静态变量
5、static修饰的方法:静态方法

变量的分类:
变量根据声明的位置进行划分:
在方法体当中声明的变量叫做:局部变量。
在方法体外声明的变量叫做:成员变量。

成员变量又可分为:
实例变量
静态变量


class VarTest{

// 以下实例的,都是对象相关的,访问时采用“引用.”的方式访问,需要先new对象。
// 实例相关的,必须先有对象,才能访问,可能会出现空指针异常。
// 成员变量中的实例变量
int i;

// 实例方法
public void m2(){
// 局部变量
int x = 200;
}


// 以下静态的,都是类相关的,访问时采用“类名.”的方法访问,不需要new对象。
// 不需要对象的参与即可访问,没有空指针异常的发生。
// 成员变量中的静态变量
static int k;

// 静态方法
public static void m1(){
// 局部变量
int x = 100;
}
}

 

1.2 什么时候变量定义为静态变量


/*
什么时候变量声明为实例的,什么时候声明为静态的?
如果这个类型的所有对象的某个属性值都是一样的,不建议定义实例变量,浪费内存空间。建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。

*/

/*
public class StaticTest02{
public static void main(String[] args){

Chinese c1 = new Chinese("111111", "张三", "中国");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(c1.country);

Chinese c2 = new Chinese("222222", "李四", "中国");
System.out.println(c2.idCard);
System.out.println(c2.name);
System.out.println(c2.country);
}
}

// 定义一个类:中国人
class Chinese{
// 身份证号
// 每一个人的身份证号不同,所以身份证号应该是实例变量,一个对象一份。
String idCard;

// 姓名
// 姓名也是一个人一个姓名,姓名也应该是实例变量。
String name;

// 国籍
// 对于“中国人”这个类来说,国籍都是“中国”,不会随着对象的改变而改变。
// 显然国籍并不是对象级别的特征。
// 国籍属于整个类的特征,整个族的特征。
// 假设声明为实例变量,内存图是怎样的?
// 假设声明为静态变量,内存图又是怎样的呢?
String country;

// 无参
public Chiense(){

}

// 有参
public Chinese(String s1, String s2, String s3){
idCard = s1;
name = s2;
country = s3;
}
}
*/


public class StaticTest02{
public static void main(String[] args){

/*
Chinese c1 = new Chinese("111111", "张三", "中国");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(c1.country);

Chinese c2 = new Chinese("222222", "李四", "中国");
System.out.println(c2.idCard);
System.out.println(c2.name);
System.out.println(c2.country);
*/

Chinese c1 = new Chinese("111111", "张三");
// 访问中国人的国籍
// 静态变量应该使用“类名.”的方式访问
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(Chinese.country);

Chinese c2 = new Chinese("222222", "李四");
System.out.println(c2.idCard);
System.out.println(c2.name);
System.out.println(Chinese.country);

// 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;
}
}

 

 

 

 

 

1.3 静态变量的访问情况

实例的:一定需要使用“引用.”来访问

静态的:
建议使用“类名.”来访问,但使用“引用.”也行(不建议使用“引用.”)
静态的如果使用“引用.”来访问会让程序员产生困惑,程序员以为是实例变量呢。

结论:
空指针异常只有在什么情况下才会发生呢?
只有在“空引用”访问“实例”相关的时候会出现空指针异常。


public class StaticTest03{

public static void main(String[] args){
System.out.println(Chinese.country);
// 创建对象
Chinese c1 = new Chinese("111111", "张三");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(c1.country);

c1 = null;
// 分析这里会不会出现空指针异常
// 不会出现空指针异常
// 因为静态变量不需要对象的存在。
// 实际上以下的代码在运行的时候,还是:System.out.println(Chinese.country);
System.out.println(c1.country);

// 这个会出现空指针异常
// System.out.println(c1.name);
}
}

class Chinese{

// 实例变量
String idCard;
String name;

// 静态变量
static String country = "中国";

// 构造方法
public Chinese(String x, String y){
idCard = x;
name = y;
}
}

 

1.4 static关键字

static修饰的统一都是静态的,都是类相关的,不需要new对象。直接采用“类名.”的方式访问。

当一个属性是类级别的属性,所有对象的这个属性值是一样的,建议定义为静态变量。

 

1.5 实例方法的调用


public class StaticTest04{
public static void main(String[] args){

// 这是比较正规的方式,静态方法采用“类名.”
StaticTest04.doSome();

// 对象
StaticTest04 st = new StaticTest04();
// 用“引用.”访问
st.doSome();

// 空引用
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执行了");
}

}

/*
关于方法来说,什么时候定义为实例方法?什么时候定义为静态方法?
有没有参考标准。
此方法一般都是描述了一个行为,如果说该行为必须由对象去触发。那么该方法定义为实例方法。
参考标准:
当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。
我们以后开发中,大部分情况下,如果是工具类的方法一般都是静态的。

类 = 属性 + 方法
属性描述的是:状态
方法描述的是:行为动作

一个方法代表了一个动作。

什么时候方法定义为实例方法?
张三考试,得90
李四考试,得100
不同的对象参加考试结果不同。
我们可以认定“考试”这个行为。
建议将“考试”这个方法定义为实例方法。

*/

public class StaticTest05{
public static void main(String[] args){

}
}

class User{

// 实例变量,需要对象
private int id;

// 实例变量
private String name;  // 首先先分析的是,ypwhname是对象级别的,一个对象一份。

// 分析这个方法应该定义为实例方法还是静态方法呢?
// 打印用户的名字这样的一个方法。
public void printName(){
System.out.println(name);
}

public void setId(int i){
id = i;
}

public int getId(){
return id;
}
}

 

1.6 静态代码块

StaticTest06.java


/*
1、使用static关键字可以定义:静态代码块

2、什么是静态代码块,语法是什么?
static {
java语句;
java语句;
}

3、static静态代码块在什么时候执行呢?
类加载时执行,并且只执行一次。

4、注意:静态代码在类加载时执行,并且在main方法执行之前执行。

5、静态代码块一般是按照自上而下的顺序执行。

6、静态代码块有啥作用?
第一:静态代码块不是那么常用。(不是每一个类当中都有东西。)
第二:静态代码块这种语法机制实际上是SUN公司给我们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
*/

StaticTest07.java


/*
栈:方法只要执行,会压栈。
堆:new出来的对象都在堆中,垃圾回收器主要针对。
方法区:类的信息,字节码信息,代码片段。

方法的代码片段放在方法区,但是方法执行过程当中需要的内存在栈中。
*/


/*
总结:
到目前为止,你遇到的所有java程序,有顺序要求的是哪些?
第一:对于一个方法来说,方法体中的代码是有顺序的,遵循自上而下的顺序执行。
第二:静态代码块和静态代码块2是有先后顺序的。
第三:静态代码块和静态变量是有先后顺序的。
*/


public class StaticTest07{

// 静态变量在什么时候初始化?类加载时初始化。
// 静态变量存储在哪里?方法区
static int  i = 100;

// 静态代码块什么时候执行?类加载时执行。
static {
// 这里可以访问i吗?
System.out.println("i --> " + i);
}

// 实例变量
int k = 111;  // k这是是实例变量,在构造方法执行时内存空间才会开辟。

static {
// k变量可以访问吗?
// static静态代码块在类加载时执行,并且只执行一次。
// 类加载时,k变量的空间还没有开辟出来。
// System.out.println("k --> " + k);

// 这里可以访问name吗?
// 错误:非法前向引用。
// 静态代码块和静态变量都是在类加载的时候执行,时间相同,只能靠代码的顺序来决定谁先谁后。
System.out.println(name);
}

// 静态变量在静态代码块下面
static String name = "xiaohong";

// 入口(main方法执行之前实际上执行了很多代码)
public static void main(String[] args){
System.out.println("main Begin");
}
}

 

1.7 实例代码块

InstanceCode.java


/*
1、除了静态代码块之外,还有一种语句块叫做:实例语句块
2、实例语句在类加载时并没有执行。
3、实例语句语法?
{
java语句;
}
4、实例语句块在什么时候执行?
只要是构造方法执行,必然在构造方法执行之前,自动执行“实例语句块”中的代码。
实际上这也是SUN公司为程序员准备的一个特殊时机,叫做对象构建时机。

*/

public class InstanceCode{

// 入口
public static void main(String[] args){
System.out.println("main begin");
new InstanceCode();
new InstanceCode("xiaohong");
}

// 实例语句块
{
System.out.println("实例语句块执行");
}

public InstanceCode(){
System.out.println("无参构造方法");
}

public InstanceCode(String name){
System.out.println("有参构造方法");
}
}

CodeOrder.java


// 判断以下程序的执行顺序
public class CodeOrder{
// 静态代码块
static{
System.out.println("A");
}

// main方法
public static void main(String[] args){
System.out.println("main begin");
new CodeOrder();
System.out.println("main over");
}

// 构造方法
public CodeOrder(){
System.out.println("B");
}

// 实例代码块
{
System.out.pritnln("C");
}

// 静态代码块
static {
System.out.println("X");
}
}

/*
A
X
main begin
C
B
main over
*/

 

 

2 this

2.1 this的内存结构


/*
this:
1、this是一个关键字,全部小写
2、this是什么,在内存方法是怎样的?
一个对象一个this。
this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。
所以,严格意义上来说,this代表的就是“当前对象”。
this存储在堆内存当中对象的内部。
*/

public class ThisTest01{
public static void main(String[] args){

Customer c1 = new Customer("张三");
Customer c2 = new Customer("李四");
}
}

// 顾客类
public Customer{
// 属性
// 实例变量
String name;

// 构造方法
public Customer(){

}
public Customer(String a){
name = s;
}

// 顾客购物的方法
// 实例方法
public void shopping(){
System.out.println(name + "正在购物");
}
}

 

 

 

2.2 this的应用

ThisTest01.java

1、this是一个关键字,全部小写

2、this是什么,在内存方法是怎样的?
一个对象一个this。
this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。
所以,严格意义上来说,this代表的就是“当前对象”。
this存储在堆内存当中对象的内部。

3、this只能使用在实例方法中。谁调用这个实例方法,this就是谁,所以this代表的是当前对象

4"this."大部分情况下是可以省略的。

5、为什么this不能使用在静态方法中?
this代表当前对象,静态方法中不存在当前对象。


public class ThisTest01{
public static void main(String[] args){

Customer c1 = new Customer("张三");
c1.shopping();

Customer c2 = new Customer("李四");
c2.shopping();


}
}

// 顾客类
class Customer{
// 属性
// 实例变量(必须采用“引用.”的方式访问)
String name;

// 构造方法
public Customer(){

}
public Customer(String a){
name = a;
}

// 顾客购物的方法
// 实例方法
public void shopping(){
// 这里的this是谁?this是当前对象。
// c1调用shopping(), this就是c1
// c2调用shopping(), this就是c2
// "this." 是可以省略的。
// System.out.println(this.name + "正在购物");
// "this." 省略不写的话,还是默认访问“当前对象”的name。
System.out.println(name + "正在购物");
}

public static void doSome(){
// this代表的是当前对象,而静态方法的调用不需要对象,矛盾了。
// 错误:无法从静态上下文中引用非静态 变量 this
// System.out.println(this);
}

}

class Student{

// 实例变量,怎么访问?必须先new对象,通过“引用.”的方式来访问。
String name = "xiaohong";

// 静态方法
public static void m1(){
// this代表是当前对象
// 编译错误
// System.out.println(this.name);

// name是当前对象的名字
// 编译错误
// System.out.println(name);

// 除非你这样
Student s = new Student();
System.out.println(s.name);
}

// 为什么set和get方法是实例方法?
public void setName(String s){
name = s;
}
public String getName(){
return name;
}


// 什么时候方法定义为实例方法,什么时候方法定义为静态方法?
// 如果方法中直接访问了实例变量,该方法必须是实例方法。
}

ThisTest02.java


// 分析:该i变量在main方法中能不能访问?

public class ThisTest02{

// 实例变量
int i = 100;  

// 静态变量
static int k = 200;

// 静态方法
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);
}
}


2.3 this什么时候不能省略

1、this可以使用在实例方法中,不能使用在静态方法中。
2、this关键字大部分情况下可以省略,什么情况下不能省略?
在实例方法中,或者构造方法中,为了区分局部变量和实例变量,这种情况是不能省略的。


// 分析一下以下代码哪里写的不太好
public class ThisTest03{
public static void main(String[] args){

Student s1 = new Student();
s1.setNo(111);
s1.setName("张三");
System.out.println("学号: " + s1.getNo());
System.out.println("姓名: " + s1.getName());

Student s2 = new Student(222, "李四");
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;
}
*/

// 构造方法无参
public Student(){}
// 构造方法有参
public Student(int no, String name){
this.no = no;
this.name = name;
}

/*
// setter and getter方法
public void setNo(int i){  
no = i;
}
public int getNo(){
return no;
}
public void setName(String s){
name = s;
}
public String getName(){
return name;
}
*/

// setter and getter方法
public void setNo(int no){  // 就近原则
// no = no; // 这样写的话,这两个no都是局部变量no,和实例变量no没有关系。
// no是局部变量
// this.no指的是实例变量
this.no = no;  // "this." 的作用是区分局部变量和实例变量的。
}
public int getNo(){
return no;
// return this.no;
}
public void setName(String name){  // 就近原则
// name = name; // 这样写的话,这两个name都是局部变量name,和实例变量name没有关系。
this.name = name;
}
public String getName(){
return name;
// return this.name; // 严格来说,这里是有一个"this."的。只不过这个"this."是可以省略的
}

}

 

2.4 this()的使用

1、this除了可以使用在实例方法中,还可以用在构造方法中。

2、新语法:通过当前构造方法去调用另一个本类的构造方法,可以使用以下语法格式:
this(实际参数列表);
通过一个构造方法1去调用构造方法2,可以做到代码复用。
但是需要注意的是:构造方法1和构造方法2都是需要在同一个类当中。

3、this(), 这个语法的作用是什么?
代码复用。

4、注意:
this(); 这种语法只能出现在构造方法中的第一行。


public class ThisTest04{
public static void main(String[] args){

// 调用无参数构造方法
Date d1 = new Date();
d1.detail();

// 调用有参数构造方法
Date d2 = new Date(2000, 2, 15);
d2.detail();
}
}

/*
需求:
1、定义一个日期类,可以表示年月日信息。
2、需求中要求:
如果调用无参数构造方法,默认创建的日期为:1970年1月1日。
当然,除了了调用无参数的构造方法之外,也可以调用有参数的构造方法来创建日期对象。
*/
class Date{
// 年
private int year;
// 月
private int month;
// 日
private int day;

// 构造方法无参
// 调用无参数构造方法,初始化的日期是固定值。
public Date(){
// 错误:对this的调用必须是构造器中的第一个语句。
// System.out.println(11);
/*
this.year = 1970;
this.month = 1;
this.day = 1;
*/
this(1970, 1, 1);
}
// 构造方法有参
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 + "日");
}

// 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 setMonth(){
return month;
}
public void setDay(int day){
this.day = day;
}
public int getDay(){
return day;
}
}

 

2.5 this总结

1 this是一个关键字,是一个引用,保存内存地址指向自身。
2 this可以使用在实例方法中,也可以实例在构造方法中。
3 this其实在实例方法中代表的是当前对象
4 this不能使用在静态方法中。
5 "this."大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。
6 this() 这种语法只能出现在构造方法的第一和行,表示当前构造方法调用本类其它的构造方法,目的是代码复用。

 

 

3 作业

3.1 day14作业

Date.java


// 设计日期类,每个日期对象都可以描述年月日信息。

public class Date{
// 年
int year;

// 月
int month;

// 日
int day;
}

Chat.java


// 设计微信账号类,每个微信账号都有微信号、手机号、昵称等信息。

public class Chat{
// 账号
String no;
// 手机号
String phone;
// 昵称
String nickname;
}

Account.java


// 设计银行账户类,每个账户都有账号、密码、余额等信息。

public class Account{
// 账号
String actno;
// 密码
String password;
// 余额
double balance;
}

Woman.java


// 设计女人类,每个女人都有身份证号、姓名、性别、男人。
public class Woman{
// 身份证号
String idCard;
// 姓名
String name;
// 性别
static boolean sex = false;
// 女人的男人
Man man;
}

Man.java


// 设计男人类,每个男人都有身份证号、姓名、性别、女人。

public class Man{
// 身份证号
String idCard;
// 姓名
String name;
// 性别
static boolean sex = true;
// 男人的女人
// 实例变量:wowan是一个引用
Woman woman;
}

Last.java

/*
第五题:定义丈夫类Husband 和妻子类 wife,
丈夫类的属性包括:身份证号,姓名,出生日期,妻子。
妻子类的属性包括:身份证号,姓名,出生日期,丈夫。
分别给这两个类提供构造方法(无参数构造方法和有参数构造方法都要提供),
编写测试程序,创建丈夫对象,然后再创建妻子对象,丈夫对象关联妻子对象,
妻子对象关联丈夫对象,要求能够输出这个"丈夫对象"的妻子的名字,
或者能够输出这个"妻子对象"的丈夫的名字。要求能够画出程序执行过程的内存图。
并且要求在程序中演示出空指针异常的效果。

注意:
“.” 后面只有一个单词,没有小括号,表示访问的是属性。
“.” 后面有一个单词,单词后面有小括号,表示访问的是方法。
*/

public class Last{
public static void main(String[] args){

// 创建丈夫对象(丈夫还没有妻子)
// Husband h = new Husband("111111", "张三", "2000-02-22", null);
Husband h = new Husband("111111", "张三", "2000-02-22");

// 创建妻子对象(妻子还没有丈夫)
// Wife w = new Wife("222222", "李四", "2001-09-22", null);
Wife w = new Wife("222222", "李四", "2001-09-22");

// 让他俩结婚
h.wife = w;
w.husband = h;

// 输出丈夫对象的妻子名字b
// System.out.println(h.name + "的妻子是" + w.name); // 这样写体现不出丈夫和妻子的关系
// 当没有结婚的时候,出现:java.lang.NullPointerException
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){
idCard = s1;
name = s2;
birth = s3;
}

// 有参构造方法
public Husband(String s1, String s2, String s3, Wife w){
idCard = s1;
name = s2;
birth = s3;
wife = w;
}
}

// 妻子类
class Wife{
// 身份证号
String idCard;
// 姓名
String name;
// 生日
String birth;
// 丈夫
Husband husband;

// 无参构造方法
public Wife(){

}

// 有参构造方法
public Wife(String s1, String s2, String s3){
idCard = s1;
name = s2;
birth = s3;
}

// 有参构造方法
public Wife(String s1, String s2, String s3, Husband h){
idCard = s1;
name = s2;
birth = s3;
Husband h;
}
}

 

3.2 day15作业

Homework1.java


/*
请通过代码封装,实现如下需求:
编写一个类Book,代表教材:
1.具有属性:名称(title) 、页数(pageNun)
2.其中页数不能少于200页,否则输出错误信息,并赋予默认值200
3.为各属性提供赋值和取值方法
4.具有方法:detail,用来在控制台输出每本教材的名称和页数
5.编写测试类BookTest进行测试:为Book对象的属性赋予初始值,并调用Book对象的detail
*/

public class Homework1{
public static void main(String[] args){
// 创建Book对象
Book b1 = new Book("高三数学人教版", 250);
// 调用detail方法
b1.detail();

// 修改页数
b1.setPageNum(100);
b1.detail();

Book b2 = new Book();
b2.detail();
}
}

class Book{
// 名称
String title;
// 页数
private int pageNum;

// 构造方法,无参数
public Book(){
title = "未知";
pageNum = 200;
}

// 有参构造器
public Book(String s, int i){
title = s;
if(i < 200){
pageNum = 200;
System.out.println("页数不能小于200,少于200时,页数默认为200页");
}else{
pageNum = i;
}
}

// setter and getter方法
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页");
// 默认赋值200
pageNum = 200;
return;
}
// 程序执行到这里说明页数是大于等于200的。
pageNum = i;
}
public int getPageNum(){
return pageNum;
}

// 额外再提供一个detail方法
public void detail(){
System.out.println("教教名称: " + title + "; 总页数为: " + pageNum);
}

}

Homework2.java

/*
写一个名为Account的类模拟账户。
该类的属性和方法如下所示。
该类包括的属性:账户id,余额balance,年利率annualInterestRate;
包含的方法: 各属性的set和get方法。取款方法withdraw(),存款方法deposit()

写一个测试程序
(1) 创建一个customer,名字叫Jane Smith,他有一个账号为1000,余额为2000,该用户的年利率为1.23
(2) 对Jane Smith操作:
存入100元,再取出960元,再取出2000。
打印Jane Smith的基本信息
信息如下显示:
成功存入: 100
成功取出:960
余额不足,取钱失败
customer[Smith,Jane] has a account : id is 1000 annualInterestRate is 1.23% balance
*/

public class Homework2{
public static void main(String[] args){

// 先创建一个账户对象
Account a = new Account("1000", 2000, 1.23);

// 创建客户对象
// 传给构造方法“引用a”是什么意思?让Customer对象和Account对象产生关系。
// 表示这个账户是Jane Smith的。
Customer c = new Customer("Jane Smith", a);

/*
对Jane Smith操作:
存入100元,
再取出960元,
再取出2000。
*/
c.getAct().deposit(100);
c.getAct().withdraw(960);
c.getAct().withdraw(2000);

// 银行卡是不是应该有一个主人。
// 此程序最难的地方是:发现对象之间的关联,不好发现。
}
}

// 账户类
class Account{
// 账户id
private String id;
// 余额
private double balance;
// 年利率(annualInterestRate)
private double annualInterestRate;

// 构造方法
public Account(){}
public Account(String id, double balance, double annualInterestRate){
// 创建对象时需要的代码
this.id = id;
this.balance =balance;
this.annualInterestRate = annualInterestRate;
}

// 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;
}

// 存款方法
// 参数表示存多少钱
public void deposit(double money){
// this(向this指向的对象中存款)
// this.balance = this.balance + money;
// this.balance += money;
// 如果省略"this."
// balance = balance + money;
// balance += money;

// 调用方法来进行修改余额
this.setBalance(this.getBalance() + money);
// "this."可以省略不写
setBalance(getBalance() + money);

System.out.println("成功存入: " + money);
}

// 取款方法
// 调用取钱的方法时,应该传递过来一个参数,告诉该方法要取多少钱。
public void withdraw(double money){
// this(从this指向的对象中取款)
if(money > this.getBalance()){
System.out.println("余额不足,取钱失败");
return;
}
// 程序能够执行到这里,说明余额充足
this.setBalance(getBalance() - money);
System.out.println("成功取出: " + money);
}

}

// 以后都是封装,所有的类都是属性私有化,对外提供setter and getter方法
// 客户类
class Customer{
// 客户名字
private String name;
// 客户手里应该有银行账户
private Account act;

// 构造方法
public Customer(){}
public Customer(String name, Account act){
this.name = name;
this.act = act;
}

// 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;
}

}

Homework3.java


/*
(封装)已知一个类 Student 代码如下:
class student{
String nane;
int age;
String address;
String zipcode;
String mobile;
}
要求:
1、把student的属性都作为私有,并提供ge/set方法以及适当的构造方法。
2、为student类添加一个getPostAddress方法,要求返回student对象的地址和邮编。
*/

public class Homework3{
public static void main(String[] args){

Student s1 = new Student();
System.out.println(s1.getPostAddress());
// 赋值
s1.setName("zhangsan");
s1.setAge(18);
s1.setAddress("牟定");
s1.setZipcode("232223");
s1.setMobile("12348828238");
System.out.println(s1.getPostAddress());

Student s2 = new Student("李四", 19, "楚雄", "111111", "12311111111");
System.out.println(s2.getPostAddress());


}
}

class Student{
private String name;
private int age;
private String address;
private String zipcode;
private String mobile;

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;
}

// 返回地址和邮编
public String getPostAddress(){
// return "地址: " + this.address + "; 邮编: " + this.zipcode;
return "地址: " + this.getAddress() + "; 邮编: " + this.getZipcode();
}

public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int setAge(){
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;
}
}

 

 

4 总结

4.1 总结所有变量和方法怎么访问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();
}
}

// 学生类
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(getName() + "正在努力的学习");
System.out.println(this.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");
// 编译器检测到job是一个静态变量,所以这里会自动在job前添加:Student.
System.out.println("多件性质: " + job);
}

}

 

4.1 总结所有变量和方法怎么访问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();
m2();

System.out.println(i);  // System.out.println(this.i);
System.out.println(j);  // System.out.println(Review02.i);

m3();
m4();
}

public static void m3(){}

public static void m4(){}

// 问?你怎么分析这个程序?
/*
第一步:
main方法是静态的,JVM调用main方法的时候直接采用“类名.”的方式。
所以main方法中没有this。
第二步:
m1() 和 m2() 方法是实例方法,执照java语法规则来说,实例方法必须先new对象。
通过“引用.”的方式访问。
*/
public static void main(String[] args){
// 编译报错
// m1();
// m2();

m3();  // 编译器会自动识别m3()静态方法,结果是: Review02.m3();
m4();  // 编译器会自动识别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 = 1000;
System.out.println(k);
}
}

class T{
public static void t1(){

}

//
public static t2(){

}
}

 

 

ps

当调用方法时不加括号会出现如下错误:
   ThisTest04.java:11: 错误: 不是语句
                   d1.detail;

解决办法:
调用方法时应该加上括号
d1.detail();
 
 

 

posted @   路走  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示