一、再谈四种访问权限修饰符
在讲解面向对象的三大特征之一的封装性时,引入了权限修饰符的概念。权限从小到大顺序为:private、缺省、protected、public。当时由于没有引入继承性的概念,没有测试protected的适用范围。
具体的修饰范围:
现在我们已经引入过面向对象的第二大特征:继承性。可以对protected权限进行测试。
首先定义一个Order类,提供以下不同修饰权限的属性及方法。可见①用private修饰符修饰的属性方法只能在类自身内部调用。
package com.java2;
public class Order {
private int orderPrivate;
int orderDefalut;
protected int orderProtected;
public int orderPublic;
private void methodPrivate(){
orderPrivate = 1;
orderDefalut = 2;
orderProtected = 3;
orderPublic = 4;
}
void methodDefalut(){
orderPrivate = 1;
orderDefalut = 2;
orderProtected = 3;
orderPublic = 4;
}
protected void methodProtected(){
orderPrivate = 1;
orderDefalut = 2;
orderProtected = 3;
orderPublic = 4;
}
public void methoodPublic(){
orderPrivate = 1;
orderDefalut = 2;
orderProtected = 3;
orderPublic = 4;
}
}
在同一个包下创建OrderTest 测试类。可见②可以编译通过的有缺省、protected及public修饰符。
package com.java2;
public class OrderTest {
public static void main(String[] args) {
Order o = new Order();
o.orderDefalut = 1;
o.orderProtected = 2;
o.orderPublic = 3;
o.methodDefalut();
o.methodProtected();
o.methoodPublic();
}
}
其次再同一个项目中,另一个包下建立测试类OrderTest 继承上面的第一个Order类,可见③在同一个项目中不同包的子类可以调用protected和public权限修饰符。
package com.java3;
import com.java2.Order;
public class OrderTest extends Order {
public void method(){
methodProtected();
methoodPublic();
orderProtected = 1;
orderPublic = 2;
}
}
最后,在同一个项目,不同包中建立一个没有继承性关系的测试类OrderTest,可见④可以调用的只有使用public权限修饰符修饰的属性及方法。
package com.java4;
import com.java2.Order;
public class OrderTest {
public static void main(String[] args) {
Order o = new Order();
o.orderPublic = 2;
o.methoodPublic();
}
}
权限修饰符是面向对象的重要组成部分,通过以上测试代码可以清晰的了解到在不同的类中权限修饰符的使用情况。
二、关键字super
1、super 关键字可以理解为:父类的
2、可以用来调用的结构:属性、方法、构造器
3、super调用属性、方法:
3.1、我们可以在子类的方法或构造器中,显式的使用"super.属性"或"super.方法"的方式,在子类中调用父类的属性或方法。通常情况下,隐藏"super."关键字。
3.2、当子类和父类中定义了重名的属性时,就必须使用"super.属性"或"super.方法"的方式,来表明当前调用的是父类的属性和方法。
3.3、特殊情况:当子类重写了父类的方法时,如果想调用父类中被重写的方法,则必须显式的使用"super.方法"的方式,来明确调用父类中被重写的方法。
4、super调用构造器:
4.1、我们可以在子类的构造器中显式的使用"super(形参列表)"的方式来调用父类中定义的指定的构造器。
4.2、如果在子类的构造器中显式的使用"super(形参列表)",必须声明在首行。
4.3、在构造器中"super(形参列表)"和"this(形参列表)"只能二一,不能同时出现。
4.4、在构造器中没显式的使用"super(形参列表)"和"this(形参列表)",那么默认调用父类中形参列表为空的构造器:super()
4.5、在类的多个构造器中,至少一个构造器使用了"super(形参列表)"的方式调用了父类的构造器。
5、经典例题(尚硅谷java基础部分super关键字实验)
5.1、写一个名为 Account 的类模拟账户。该类的属性和方法如下图所示。该类包括的属性: 账号 id,余额 balance,年利率 annualInterestRate;包含的方法:访问器方法(getter 和 setter 方法),返回月利率的方法 getMonthlyInterest(),取款方法 withdraw(),存款方法 deposit()。
写一个用户程序测试 Account 类。在用户程序中,创建一个账号为 1122、余额为 20000、 年利率4.5%的Account对象。使用withdraw方法提款30000元,并打印余额。再使用withdraw方法提款 2500元,使用deposit方法存款3000元,然后打印余额和月利率。
提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不 能,应给出提示。 运行结果如图所示:
Account类如下:
public class Account {
private int id;
private double balance;
private double annualInterestRate;
public Account(int id, double balance, double annualInterestRate) {
super();
this.id = id;
this.balance = balance;
this.annualInterestRate = annualInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnualInterestRate() {
return annualInterestRate;
}
public void setAnnualInterestRate(double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
//月利率(%)=年利率(%)÷12
public double getMonthlyInterest(){
return annualInterestRate/12;
}
//取款方法
public void withdraw (double amount){
if(amount <= balance){
balance -= amount;
// System.out.println("取款成功,取出"+amount+"元");
}else{
System.out.println("余额不足!");
}
}
//存款方法
public void deposit (double amount){
if(amount>0){
balance += amount;
// System.out.println("存款成功,共存入"+amount+"元");
}else{
System.out.println("存款失败,请存入正确钱数");
}
}
}
测试类Test如下:
public class Test {
public static void main(String[] args) {
Account a1 = new Account(1122, 20000, 0.045);
a1.withdraw(30000);
System.out.println("您的账户余额为:"+a1.getBalance());
a1.withdraw(2500);
a1.deposit(3000);
System.out.println("您的账户余额为:"+a1.getBalance());
double monthlyInterest = a1.getMonthlyInterest();
System.out.println("月利率为:"+monthlyInterest);
}
}
测试结果如下:
5.2、创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft 代表可透支限额。在CheckAccount类中重写withdraw方法,其算法如下:
如果(取款金额账户余额),计算需要透支的额度 判断可透支额 overdraft 是否足够支付本次透支需要,如果可以 将账户余额修改为0,冲减可透支金额。如果不可以,提示用户超过可透支额的限额
要求:写一个用户程序测试 CheckAccount 类。在用户程序中,创建一个账号为 1122、余 额为 20000、年利率 4.5%,可透支限额为 5000 元的 CheckAccount 对象。 使用 withdraw 方法提款 5000 元,并打印账户余额和可透支额。再使用 withdraw 方法提款 18000 元,并打印账户余额和可透支额。 再使用 withdraw 方法提款 3000 元,并打印账户余额和可透支额。
提示:(1)子类 CheckAccount 的构造方法需要将从父类继承的 3 个属性和子类自己的属性全 部初始化。(2)父类Account的属性balance被设置为private,但在子类CheckAccount的withdraw方法中需要修改它的值,因此应修改父类的 balance 属性,定义其为 protected。 运行结果如下图所示
CheckAccount类设计如下:
public class CheckAccount extends Account {
private double overdraft;
public CheckAccount(int id, double balance, double annualInterestRate,double overdraft) {
super(id, balance, annualInterestRate);
this.overdraft = overdraft;
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
public void withdraw(double amount){
if(amount<=getBalance()){
super.withdraw(amount);
// setBalance(getBalance()-amount);
}else{
if(overdraft>=amount-getBalance()){
overdraft -= (amount-getBalance());
setBalance(0);
}else{
System.out.println("超过可透支限额!");
}
}
}
}
测试类CheckAccountTest 如下:
public class CheckAccountTest {
public static void main(String[] args) {
CheckAccount c1 = new CheckAccount(1122, 20000, 0.045, 5000);
c1.withdraw(5000);
System.out.println("您的账户余额:"+c1.getBalance());
System.out.println("您的可透支额:"+c1.getOverdraft());
c1.withdraw(18000);
System.out.println("您的账户余额:"+c1.getBalance());
System.out.println("您的可透支额:"+c1.getOverdraft());
c1.withdraw(3000);
System.out.println("您的账户余额:"+c1.getBalance());
System.out.println("您的可透支额:"+c1.getOverdraft());
}
}
测试结果: