今日内容:封装与隐藏、构造器、关键词this、package
每日一考1. 重载的方法是什么?
在同一类中,定义了相同的方法名,但不同的参数数/参数类型构成重载的方法。
2.说明Java方法中参数传输机制的具体体现?
对于基本数据类型,实参传递给形参的是数据值;
对于引用的数据类型,实参传递给形参的是地址值。(含变量的数据类型)
Person p1 = new Person();
User u1 = p1;//编译错误
3.成员变量和局部变量在声明位置、默认初始化值、有权修改符号修改和内存分配位置上有什么区别?
1)声明的位置:成员变量直接声明在类的一对大括号内;局部变脸声明在定义方法的小括号或方法体内。
2)是否有默认初始化值:成员变量有;局部变量需要显式赋值。
3)能否有权限修饰符修饰:成员变量可以由权限修饰符修饰;局部变量不能。
4)内存分配位置:成员变量在堆叠空间中分配内存;局部变量在堆叠空间中分配内存。
局部变量:方法内部、方法形参、构造器内部、构造器形参、代码块内
4.谈谈return关键词的使用
return对于具有返回值的方法,return对于没有返回值的方法,return表示该方法已经结束。
5.提供以下代码的内存分析
如下图
复习
- 匿名对象
创建的对象没有明确赋予变量名,即匿名对象
特点:匿名对象只能调用一次
应用场景:当一种方法的参数类型为class时,new作为该方法的实际参考引入新对象;由于匿名对象只能使用一次,new对象只能在该方法中使用。
- 方法的重载
“两同一不同”:相同的类别,相同的方法名;不同的参数列表(参数数字/参数类型)
注:严格按照定义判断两种方法是否重载,与方法的权限修饰符、返回值类型、形参变量名、方法体无关!
如何确定类中某种方法的调用:确定方法名称 -> 确定参数列表
面试题:方法重载和重写的区别?(经典老题)
没关系。。。。。。
throws\throw的区别,String\StringBuffer\Stringbuilder的区别,Collectioncollections的差异,final\finallyfinalize的区别
抽象与接口,wait()与sleep()的区别
- 可变数形参的方法
可变数形参 是JDK 5.0新内容
格式:数据类型 ... 变量名
如:show(String ... strs) 与 show(String[] strs) 等价 (不构成方法重载,不能同时存在)。
- 值传递机制 ☆
形参与实参:
当方法定义形状参数时,声明小括号中的参数
实参是在调用方法时实际传递给形参的数据
值传递机制:
当参数为基本数据类型时,实参赋予形参实际存储的数据值;
当参数为引用数据类型时,实参赋予形参实参存储数据的地址值。
补充-以下代码的输出结果如下:
public class ValueTransferTest {public static void main(String[] args) {String s1 = "hello";
ValueTransferTest test = new ValueTransferTest();test.change(s1);System.out.println(s1);}public void change(String s){s = "hi~~";}
}String是引用数据类型的类别,但当声明String类型的变量时,不需要newString类别,可以直接写成String s1 = "hello";
并且"hello“以char[5]的形式存储在字符串常量池中,而不是堆叠空间,并将字符串数组的第一个地址值赋予变量s1;
调用change()方法时,将实参s1作为形参s传输给s赋值hi~~”字符串数组“hi第一个地址值赋予变量s,变量s1的值仍然是字符串数组“hello第一个地址值。方法调用后,变量s出栈,输出变量s1的值,为“hello”。
1、面向对象的特征1:包装和隐藏
- 问题的引入
1)当我们创建一个类别的对象时,我们可以通过“对象。属性”来赋值对象的属性。
2)在这里,赋值操作应受到属性数据类型和存储范围的限制。此外,没有其他限制。
3)但在实际问题中,在赋值属性时,需要增加额外的限制。这种限制不能反映在属性声明中。
4)限制条件只能通过方法添加。
5)同时,用户需要避免再次使用“对象.属性”赋值属性(将属性声明为私有) private)
此时,封装性反映在属性上
- 包装的体现
私有化类属性(private),同时,提供公共服务(public)的方法来 获取 和 设置 这个属性的值。
封装性:
①属性私有化 ②不对外暴露的私有方法 ③在单例模式中,构造器的私有化 ...
3.封装和权限修饰符
1)Java规定的四种权限:
从小到大排序: private < 缺省 < protected < public
2)4种权限可用于修改 类 及 类的内部结构 :属性、方法、结构器、内部类别。具体:
修饰:只有缺省,public
修饰内部结构:private、缺省、protected、public都可以
- 总结
Java提供了四种权限修饰符,以反映调用时类和类的内部结构的可见性大小
1)私有属性不能在类外部调用:
2)私有方法不能在类外部(同一包内)调用
3)缺省 属性/方法 在 同一工程的不同包之间不能调用:
- 练习
创建程序,定义两类:Person和PersonTest。定义如下:
使用setage()设置人的合法年龄(0~130),使用setage()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 以及getage()方法,体验Java的包装。
1)在com.atguigu.在excer包中新建Person类:
package com.atguigu.excer;
public class Person {
private int age;public void setAge(int i){if(i < 0 || i > 130){// throw new RuntimeException(非法传入数据!");System.out.println(非法传入数据!");return;}age = i; // 不符合上述条件(合法引入值)}public int getAge(){return age;}
}2)在com.atguigu.在excer包中新建一个Persontest类:
package com.atguigu.excer;
public class PersonTest {public static void main(String[] args) {
Person b = new Person();b.setAge(35);int age = b.getAge();System.out.println("age: " + age);}
}
二、三类成员:构造器1。构造器的作用
1)创建对象
2)初始化对象的信息
2.说明
1)如果没有显示定义结构,系统默认提供空参结构
2)定义结构器的格式:
权限修饰符 类名(形参列表){}
3)一个类中定义的多个结构器相互构成重载
4)一旦定义了类别的结构,系统将不再提供默认的空参结构
5)一个类中至少有一个结构器
- 练习
1)在前面定义的Person类中添加结构器,并使用结构器设置所有人的age 性初始值为18。
2)修改上述问题的中类和构造器,增加name属性,使每次创建person对象的相同性 初始化对象的age属性值和name属性值。
3)写两个类别,TriAngle和TriAngleTest,其中,Triangle类声明私有底边长base和高height,并声明公共方法访问私有变量。此外,还提供必要的类结构。这些公共方法用于计算三角形的面积。
TriAngle的定义:
public class TriAngle {private double base;private double height;
public TriAngle(){}public TriAngle(double b, double h){base = b; // 底边长height = h; // 高}public void setBase(double bse){base = bse;}public double getBase(){return base;}public void setHeight(double ht){height = ht;}public double getHeight(){return height;}// 计算三角形面积public double triArea(){return base * height / 2;}
}TriAngleTest类别:
public class TriAngleTest {public static void main(String[] args) {TriAngle t = new TriAngle(3, 4);
System.out.println(三角形的底边长为:" + t.getBase());System.out.println(三角形的高度为:" + t.getHeight());System.out.println(三角形的面积为:" + t.triArea());}
}注:一般提供空参的结构器
4.总结:属性赋值过程:
1)赋值位置:
① 默认初始化
② 显式初始化
③ 构造中的初始化
④ 通过“对象、属性”或“对象、方法”赋值
2)赋值顺序:
① - ② - ③ - ④
只有默认初始化值:
显示赋值时:
使用结构器赋值时:
使用“对象.方法”或“对象.属性”赋值时:
3)注意:
①、②、③只执行一次,④任何次数都可以执行
三、使用this关键词
- this可用于修改:属性、方法、结构器
- this修饰属性及方法:
理解为this 当前对象 或 目前正在创建的对象
2.1 在类的方法中
> 我们可以用“我们可以用”this.属性”或“this.方法”调用 当前对象 属性或方法;
> 通常选择省略“通常选择省略”this.”
> 特殊情况(方法形参和类属性重名),必须显示使用“this.变量的方法表明变量是属性而不是形参
该方法的形参和类属性重名2.2 在类结构器中
>我们可以用“我们可以用”this.属性”或“this.方法”调用 目前正在创建的对象 属性或方法;
>通常选择省略“通常选择省略”this.”
>特殊情况(方法形参和类属性重名),必须显示使用“this.变量的方法表明变量是属性而不是形参
- 调用结构器的this
① 可显示在类结构器中 “this(形参列表) 方式,调用 本类中 指定的 其他构造器
② 在结构器中,不能通过“this(形参列表)以自己的方式调用
③ 如果一个类中有n个结构器,最多使用n-1个结构器 “this(形参列表)
④ 规定:“this(形参列表) 在构造器的第一行必须声明
⑤ 最多只能声明一个构造器的内部 “this(形参列表) 调用其它结构器
该类别的结构器可以调用该类别的其他结构器4. 练习
添加必要的结构器,综合应用结构器的重载,this关键词。
1)创建Boy类,关键代码
2)创建Girl类,关键代码
3)创建BoyGirltest类,测试运行结果
四、两个实验实验1:Account_Customer
要求:
1)写一个名字 Account 类模拟账户。该类的属性和方法如下图所示。该类包含的属性:帐户 id,余额 balance,年利率 annualInterestRate;包含方法:访问器方法(getter 和 setter方法),取款方法 withdraw(),存款方式 deposit()。
public class Account {private int id; // 账号private double balance; // 余额private double annualInterestRate; // 年利率
public Account() {}public Account(int id, double balance, double annualInterestRate) {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;}// publiciccicic提款方法 void withdraw (double amount){if(balance < amount){System.out.println(用户余额<提款数额,取款失败!");}else{this.balance -= amount;System.out.println(“成功取款” + amount + "元,“用户余额为:” + this.balance);}}// publiciccc存款方法 void deposit (double amount){this.balance += amount;System.out.println(“成功存入” + amount + "元,“用户余额为:” + this.balance);}
}2)创建 Customer 类。
public class Customer {private String firstName;private String lastName;private Account account;
public Customer() {}public Customer(String f,String l){this.firstName = f;this.lastName = l;}public String getFirstName(){return firstName;}public String getLastName(){return lastName;}public void setAccount(Account account){this.account = account;}public Account getAccount(){return this.account;}
}3)写一个测试程序。
创建一个 Customer ,名字叫 Jane Smith, 他有一个账号 1000,余额为 2000 元, 年利率为 1.23% 的账户。
对 Jane Smith 操作。存入 100 元,再取出 960 元。再取出 2000 元。打印出 Jane Smith 基本信息。
public class Test {public static void main(String[] args) {Customer cus = new Customer("Jane", "Smith");Account acc = new Account(1000, 2000, 0.0123);cus.setAccount(acc);
// 存入 100 元,再取出 960 元。再取出 2000 元。cus.getAccount().deposit(100);cus.getAccount().withdraw(960);cus.getAccount().withdraw(2000);// 打印出 Jane Smith System的基本信息.out.println("Customer [" + cus.getLastName() + ", " + cus.getFirstName() + "] has an account: id is "+ cus.getAccount().getId() + ", annualInterestRate is " + cus.getAccount().getAnnualInterestRate() * 100 +"%, balance is " + cus.getAccount().getBalance());}
}
实验2:Account_Customer_Bank
要求:
1)按以下要求 UML 创建相应的类别,并提供必要的结构
在提款方法 withdraw()如果没有,需要判断用户余额是否能满足提款金额的要求, 应给出提示。deposit()方法表示存款。
public class Account {private double balance;
public Account(double init_balance){this.balance = init_balance; // 账户的初始余额}public double getBalance(){return balance;}// 存款public void deposit(double amt){if(amt > 0){balance += amt;System.out.println(成功存款);}}// 取款public void withdraw(double amt){if(amt > balance){System.out.println(”取款失败!");}else{balance -= amt;System.out.println(“成功取款” + amt + "元");}}
}2)按以下要求 UML 创建相应的类别,并提供必要的结构
public class Customer {private String firstName;private String lastName;private Account account; // 请注意,account属性是account类型,使用次属性需要neww
public Customer(){}public Customer(String f, String l){this.firstName = f;this.lastName = l;}public String getFirstName(){return firstName;}public String getLastName(){return lastName;}public Account getAccount(){return account;}public void setAccount(Account acct){this.account = acct;}
}3)按以下要求 UML 创建相应的类别,并提供必要的结构
addCustomer 该方法必须根据参数(姓名、姓名)构建新的方法 Customer 对象,然后把 它放到 customer 在数组中。还必须把 numberOfCustomer 属性的值加 1。
getNumOfCustomers 方法返回 numberofCustomers 属性值。
getCustomer 方法返回和给出 index 与参数相关的客户。
public class Bank {private Customer[] customers; // 存储多个客户的数组private int numberOfCustomer; // 记录客户数量
public Bank(){// 声明一个长度为10的Customer类型的数组,用户存储客户数据customers = new Customer[10];}// 添加客户publiciccc添加客户 void addCustomer(String f, String l){Customer cus = new Customer(f, l);if(numberOfCustomer < customers.length){
//customers[numberOfCustomer] = cus;//numberOfCustomer ++;// 或者customersss[numberOfCustomer ++] = cus;}else{System.out.println(添加用户失败!);}}
// publicc获取客户数量 int getNumOfCustomer(){return this.numberOfCustomer;}// 在指定位置获取客户public Customer getCustomer(int index){
//return customers[index];// 可能出现的问题:1)数组未初始化 2)指针越界,也就是说,index值大于等于数组长度 3)index的值大于实际客户// 更严谨的写法:if(index >= 0 && index < numberOfCustomer){return customers[index];}return null;}}4)创建 BankTest 类,进行测试。
public class BankTest {public static void main(String[] args) {// 创建BankBankBank bank = new Bank();
// 添加客户1bank.addCustomer("Jane", "Smith");// 客户1 添加帐户bank.getCustomer(0).setAccount(new Account(2000));// 客户1账户操作bank.getCustomer(0).getAccount().withdraw(500); // 取款500// 查看客户1余额doublele balance = bank.getCustomer(0).getAccount().getBalance();System.out.println("客户" + bank.getCustomer(0).getFirstName() + “账户余额为:” + balance);System.out.println(**********************);// 添加客户2bank.addCustomer("Lily", "Yang");bank.getCustomer(1).setAccount(new Account(1000));System.out.println(”银行客户数量为:" + bank.getNumOfCustomer());// 添加多个客户,输出账户信息String[] firstName = new String[]{"Alice", "Brown", "Cindy"};String[] lastName = new String[]{"Green", "White", "Black"};for(int i = 0; i < 3; i++){bank.addCustomer(firstName[i], lastName[i]);bank.getCustomer(i + 2).setAccount(new Account(1000));}System.out.println("客户\t\t余额”;for(int i=0; i<bank.getNumOfCustomer(); i++){System.out.println(bank.getCustomer(i).getFirstName() + " " + bank.getCustomer(i).getLastName() +"\t\t" + bank.getCustomer(i).getAccount().getBalance());}}
}输出结果:
五、关键字package、使用import1.关键字package
1)为更好地实现项目中级管理,提供包装概念
2)使用package声明 类 或 接口 在源文件首行声明所属包
3)包,属于标识符,遵循标识符的命名规则和规范(xxxyyyzzz),“见名知义”
4)包名中的 “.” 表示一层文件目录
补充:同一个包下,不能同名命名 类 或 接口
不同的包下,不能命名同名 类 或 接口
2.import 使用关键词
1)在源文件中显示的使用 import 导入指定包下的类别和接口
2)import结构声明 包与类的声明之间
3)如果需要导入多个结构,可以并列写出来
4)可以使用 “xxx.*导入xxx包下的所有结构的方法
5)如果使用的类别或接口是java.lang包下的定义可以省略import结构(r如String、System)
6)如果当前package定义了使用的类别或接口,则可以省略import结构
7)如果在源文件中使用不同包下的同名类,至少需要一个包 全类名 的方式显示
8)使用“xxx.*“xxx包下的所有类别或接口(不包括子包)都可以导入。如果使用xxx包下的子包中的结构,仍然需要显式导入
9)import static :导入指定 类或接口中 静态结构(不用于导入或接口):属性、方法 作者:naien https://www.tulingxueyuan.cn/d/file/p/20230607/xufw1g3jotg 出处:bilibili
