一、方法的签名和重载
- 方法签名:方法名+依次参数类型。注意:返回值不属于方法签名。方法签名是一个方法在一个类中的唯一标识;
- 同一个类中方法可以重名,但是签名不可以重复。一个类中如果定义了名字相同,但是签名不同的方法,就叫做方法的重载;
- 代码示例:
public class MerchandiseV2Overload {
public String name;
public String id;
public int count;
public double soldPrice;
public double purchasePrice;
public void init(String name, String id, int count, double soldPrice, double purchasePrice) {
this.name = name;
this.id = id;
this.count = count;
this.soldPrice = soldPrice;
this.purchasePrice = purchasePrice;
}
public void describe() {
System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
+ "。商品进价是" + purchasePrice + "。商品库存量是" + count +
"。销售一个的毛利润是" + (soldPrice - purchasePrice));
}
public double calculateProfit() {
double profit = soldPrice - purchasePrice;
// if(profit <= 0){
// return 0;
// }
return profit;
}
// >> TODO 重载的方法可以调用别的重载方法,当然也可以调用别的不重载的方法。
// >> TODO 实际上,像这种补充一些缺省的参数值,然后调用重载的方法,是重载的一个重要的使用场景。
// >> TODO 在这里我们举的例子就是这样的,但是不是语法要求一定要这样。重载的方法的方法体内代码可以随便写,
// TODO 可以不调用别的重载方法
public double buy() {
return buy(1);
}
public double buy(int count) { return buy(count, false);
}
// TODO 最后都补充好参数,调用参数最全的一个方法
public double buy(int count, boolean isVIP) {
if (this.count < count) {
return -1;
}
this.count -= count;
double totalCost = count * soldPrice;
if (isVIP) {
return totalCost * 0.95;
} else {
return totalCost;
}
}
}
二、重载的参数匹配规则
- 无论是否重载参数类型可以不完全匹配的规则是"实参数可以自动类型转换成形参类型";
- 重载的特殊之处是,参数满足自动自动类型转换的方法有好几个,重载的规则是选择最"近"的去调用;
三、构造方法:构造实例的方法
1、构造方法
- 构造方法(constructor)的方法名必须与类名一样,而且构造方法没有返回值。这样的方法才是构造方法;
- 构造方法可以有参数,规则和语法与普通方法一样。使用时,参数传递给new语句后的括号里面;
- 如果没有显示的添加一个构造方法,java会给每个类都会默认带一个无参数的构造方法;
- 如果我们自己添加类构造方法,java就不会再添加无参数的构造方法。这时候就不能直接new一个对象不传递参数了;
- 所以我们一直都在使用构造方法,这也是为什么创建对象的时候类名后面必须有一个括号的原因;
- 构造方法无法被点操作符调用或者在普通方法里调用,只能通过new语句在创建对象的时候,间接调用;
public class MerchandiseV2WithConstructor {
public String name;
public String id;
public int count;
public double soldPrice;
public double purchasePrice;
public MerchandiseV2WithConstructor(String name, String id, int count, double soldPrice, double purchasePrice) {
this.name = name;
this.id = id;
this.count = count;
this.soldPrice = soldPrice;
this.purchasePrice = purchasePrice;
}
// ......
}
2、构造方法的重载和互相调用
和方法的重载是一致的,定义多个同名不同参的构造方法
构造方法在互相调用时,使用this()
public class MerchandiseV2 {
public String name;
public String id;
// 构造方法执行前,会执行给局部变量赋初始值的操作
// 所有的代码都必须在方法里,那么这种给成员变赋初始值的代码在哪个方法里?怎么看不到呢?
// 构造方法在内部变成了<init>方法。
public int count = 999;
public double soldPrice;
public double purchasePrice;
// 构造方法(constructor)的重载和普通方法一样
public MerchandiseV2(String name, String id, int count, double soldPrice, double purchasePrice) {
this.name = name;
this.id = id;
this.count = count;
this.soldPrice = soldPrice;
this.purchasePrice = purchasePrice;
// soldPrice = 9/0;
}
// 在构造方法里才能调用重载的构造方法。语法为this(实参列表)
// 构造方法不能自己调用自己,这会是一个死循环
// 在调用重载的构造方法时,不可以使用成员变量。因为用语意上讲,这个对象还没有被初始化完成,处于中间状态。
// 在构造方法里才能调用重载的构造方法时,必须是方法的第一行。后面可以继续有代码
public MerchandiseV2(String name, String id, int count, double soldPrice) {
// double purPrice = soldPrice * 0.8;
// this(name, id, count, soldPrice, purchasePrice);
this(name, id, count, soldPrice, soldPrice * 0.8);
// double purPrice = soldPrice * 0.8;
}
//因为我们添加了构造方法之后,Java就不会再添加无参数的构造方法。如果需要的话,我们可以自己添加这样的构造方法
public MerchandiseV2() {
this("无名", "000", 0, 1, 1.1);
}
public void describe() {
System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
+ "。商品进价是" + purchasePrice + "。商品库存量是" + count +
"。销售一个的毛利润是" + (soldPrice - purchasePrice));
}
public double calculateProfit() {
double profit = soldPrice - purchasePrice;
return profit;
}
public double buy(int count) {
if (this.count < count) {
return -1;
}
return this.count -= count;
}
}
四、静态变量
- 静态变量使用static修饰符
- 静态变量如果不赋值,Java也会给它赋予其类型的初始值
- 静态变量一般使用全大写加下划线分割
- 使用import static来引入一个静态变量,就可以直接用变量名访问了
- import static 也可以使用通配符*来引入一个类里所有静态变量
// 被public修饰的静态变量,所有的代码都可以使用它
public static double DOUBLE_GRADE = 0.99;
// 没有public修饰的静态变量,只有当前包的代码可以使用它
static int INT_GRAGE = 10;
package com.geekbang;
import com.geekbang.supermarket.MerchandiseV2WithStaticVariable;
import static com.geekbang.supermarket.MerchandiseV2WithStaticVariable.*;
public class MerchandiseV2DescAppMain {
public static void main(String[] args) {
MerchandiseV2WithStaticVariable merchandise = new MerchandiseV2WithStaticVariable
("书桌", "DESK9527", 40, 999.9, 500);
merchandise.describe();
// 使用import static来引入一个静态变量,就可以直接用静态变量名访问了
// import static也可以使用通配符*来引入一个类里所有静态变量
System.out.println(DISCOUNT_FOR_VIP);
}
}
五、静态方法
- 静态方法(也叫类方法)的特点:只能使用参数和静态变量。换言之,就是没有this自引用的方法;
- 静态方法和静态变量一样,使用static修饰符;
- 静态方法可以访问静态变量,包括自己类的静态变量和在访问控制符允许的别的类的静态变量;
- 除了没有this,静态方法的定义和成员方法一样,也有方法名、返回值和参数;
- 静态方法没有this自引用,它不属于某个实例,调用的时候也无需引用,直接用类名调用,所以它也不能直接访问成员变量;
- 在静态方法里边,也可以自己创建对象,或者通过参数获得对象的引用,进而调用方法和访问成员变量;
- 静态方法只是没有this自引用的方法而已;
package com.geekbang.supermarket;
public class MerchandiseV2 {
public String name;
public String id;
public int count;
public double soldPrice;
public double purchasePrice;
// >> TODO 静态变量使用 static 修饰符
public static double DISCOUNT_FOR_VIP = 0.95;
// >> TODO 静态方法使用static修饰符。
public static double getVIPDiscount() {
// >> TODO 静态方法可以访问静态变量,包括自己类的静态变量和在访问控制符允许的别的类的静态变量
return DISCOUNT_FOR_VIP;
}
public static double getDiscountOnDiscount(LittleSuperMarket littleSuperMarket) {
double activityDiscount = littleSuperMarket.activityDiscount;
return DISCOUNT_FOR_VIP * activityDiscount;
}
}
静态方法的重载和成员方法(实例方法)一样。
六、static代码块和static变量初始化
- 使用某个静态变量的代码块必须在静态变量后边;
- 静态代码块中可以有任意合法的代码;
- 静态代码块可以有多个,从上到下顺序执行;
package com.geekbang.supermarket;
public class DiscountMgr {
public static void main(String[] args) {
System.out.println("最终main 方法中使用的SVIP_DISCOUNT是" + SVIP_DISCOUNT);
}
public static double BASE_DISCOUNT;
public static double VIP_DISCOUNT;
// >> TODO 使用某个静态变量的代码块必须在静态变量后面
// >> TODO (但是仅仅赋值没有限制,很妖的语法哈,有些语法就应该在学会的第一时间忘掉它)
public static double SVIP_DISCOUNT;
static {
BASE_DISCOUNT = 0.99;
VIP_DISCOUNT = 0.85;
SVIP_DISCOUNT = 0.75;
// >> TODO 静态代码块里当然可以有任意的合法代码
System.out.println("静态代码块1里的SVIP_DISCOUNT" + SVIP_DISCOUNT);
}
// >> TODO 其实给静态变量赋值也是放在代码块里的,static代码块可以有多个,是从上向下顺序执行的。
// TODO 可以认为这些代码都被组织到了一个clinit方法里
static {
SVIP_DISCOUNT = 0.1;
System.out.println("静态代码块2里的SVIP_DISCOUNT" + SVIP_DISCOUNT);
}
}
七、方法和属性的可见性修饰符
- 可见性修饰符用在类、成员方法、构造方法、静态方法和属性上,其可见性的范围是一样的;
- public:全局可见
- 缺省:当前包可见
- private:当前类可见
- 访问修饰符:不只是为了限制不让人使用,更为了有规矩才成方圆。成员变量应该是private的,不需要让外部使用的方法应该都是private的;