1.面向对象特征之一:封装和隐藏
1.问题的引入:
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现。我们只能通过方法进行限制条件的添加。同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private)(此时,针对于属性就体现了封装性。)
2.封装性的体现
我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
3.封装性的体现,需要权限修饰符来配合。
1.Java规定的4种权限(从小到大排列): private、缺省、protected . public
2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类 修饰类的话,只能使用:缺省、public
总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小
2.面向对象特征之二:继承性
1.继承性的好处(why)
1.减少了代码的冗余,提高了代码的复用性
2.便于功能的扩展
3.为之后多态性的使用,提供了前提
2.继承性的格式: class A extends B{}(extends:延展、扩展)
A:子类、派生类、subclass
B:父类、超类、基类、superclass
1.体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展(子类和父类的关系,不同于子集和集合的关系。)
3.Java中关于继承性的规定:
1.—个类可以被多个子类继承。
2.Java中类的单继承性:一个类只能有一个父类。
3.子父类是相对的概念
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
4.Object
1.如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
2.所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3.意味着,所有的java类具有java.lang.Object类声明的功能。
5.方法的重写(override / overwrite)
1.重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
3.重写的规定:
方法的声明:权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
//方法体
}
约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法
1.子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
2.子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况:子类不能重写父类中声明为private权限的方法
3.返回值类型:
1.父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
2.父类被重写的方法的返回值类型是A(引用数据类型)类型,则子类重写的方法的返回值类型可以是A(引用数据类型)类或A(引用数据类型)类的子类
3.父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
4.子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
注意:子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写)。要么都声明为static的(不是重写)。
3.面向对象特征之三:多态性
1.理解多态性:可以理解为一个事物的多种形态。
2.何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3.多态的使用(虚拟方法谓用)
1.有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边。
4.多态性的使用刖提:
1.类的继承关系
2.方法的重写
5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
4.super关键字的使用
1.Super理解为:父类的
2.super可以用来调用:属性、方法、构造器
3.super的使用:调用属性和方法
1.我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
2.特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
3.3.3特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
4.super的使用:调用构造器
1.我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
2."super(形参列表)"的使用,必须声明在子类构造器的首行!
3.我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现。
4.在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列理)",则默认调用的是父类中空参的构造器: super()
5.在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器
5.子类对象实例化过程
1.从结果上来看:(继承性)
1.子类继承父类以后,就获取了父类中声明的属性或方法
2.创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
2.从过程上来看:
1.当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,... 直到调用了java . lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
6.instanceof关键字的使用
使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回flse,不进行向下转型。
1.a instanceof A:判断对象a是否是类A的实例,如果是,返回true;如果不是,返回false。
2.如果a instanceof A返回true,则a instanceof B也返回true.其中,类B是类A的父类。
7.Object类的使用(java.lang.Object)
1.Object类是所有Java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
3.Object类中的功能(属性、方法)就具有通用性。
1.属性:无
2.方法:equals() / toString() / getclass( ) / hashcode() / clone() / finalize()
wait() 、notify()、notifyAll()
Object类中toString()的使用:
1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
2.像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString( )时,返回"实体内容"信息
3.自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
4.Object类只声明了一个空参的构造器
8.单元测试方法的使用(eclipse中,如在idea中请点击下方连接操作)
Java中的JUnit单元测试
步骤:
1.选中当前工程 – 右键选择: build path – add libraries – JUnit 4 –下一步
2.创建Java类,进行单元测试。
此时的Java类要求:
1.此类是public的
2.此类提供公共的无参的构造器
3.此类中声明单元测试方法。
此时的单元测试方法:方法的权限是public,没有返回值,没有形参
4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入: import org.junit.Test;
5.声明好单元测试方法以后,就可以在方法体内测试相关的代码。
6.写完代码以后,左键双击单元测试方法名,右键:run as – JUnit Test
说明:
1.如果执行结果没有任何异常:绿条
2.如果执行结果出现异常:红条
9.包装类的使用
1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
2.掌握的:基本数据类型、包装类、String三者之间的相互转换
练习1(继承性)
Mankind类
package com.wy.exer;
/**
* @author wy
* @date 2021/11/13 - 19:08
*/
/**
* 定义一个Mankind类,包括
* 成员变量int sex和int salary,
* 方法void manOrWoman():根据sex的值显示"man"(sex==1)或者"woman"(sex==0)
* 方法void employeed():根据salary的值显示"no job"(salary==0)或者“job"(salary!=0).
*/
public class ManKind {
private int sex;//性别
private int salary;//薪资
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manORWoman(){
if (sex == 1){
System.out.println("man");
}else if (sex == 0){
System.out.println("woman");
}
}
public void employeed(){
// if (salary == 0){
// System.out.println("no job");
// }else {
// System.out.println("job");
// }
//或
String jobInfo = (salary == 0) ? "no job" : "job";
System.out.println(jobInfo);
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
Kids类
package com.wy.exer;
/**
* @author wy
* @date 2021/11/13 - 19:21
*/
/**
* 定义类Kids继承Mankind,并包括成员变量int yearsold,
* 方法printAge()打印yearsOld的值。
*/
public class Kids extends ManKind {
private int yearsOld;
public Kids(){
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge(){
System.out.println("I am " + yearsOld + " years old.");
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
}
KidsTest类
package com.wy.exer;
/**
* @author wy
* @date 2021/11/13 - 19:31
*/
/**
* 定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。
*/
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manORWoman();
}
}
练习2(继承性和super)
Account类
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 10:08
*/
public class Account {
private int id;//账号
private double balance;//余额
private double annualInterestRate;//年利率
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;
}
//返回月利率
public double getMonthlyInterest(){
return annualInterestRate / 12;
}
public void withdraw(double amount){
if (balance >= amount){
balance -= amount;
}else {
System.out.println("余额不足");
}
}
public void deposit(double amount){
if (amount > 0){
balance += amount;
}
}
}
AccountTest类
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 10:16
*/
/**
* 写一个用户程序测试Account类。在用户程序中,
* 创建一个账号为1122、余额为20000、年利率4.5%的Account对象。
* 使用withdraw方法提款30000元,并打印余额。
* 再使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率。
*/
public class AccountTest {
public static void main(String[] args) {
Account acct = new Account(1122,20000,0.045);
acct.withdraw(30000);
System.out.println("您的账户余额为: " + acct.getBalance());
acct.withdraw(2500);
System.out.println("您的账户余额为: " + acct.getBalance());
acct.deposit(3000);
System.out.println("您的账户余额为: " + acct.getBalance());
System.out.println("您的账户月利率为: " + (acct.getMonthlyInterest() * 100) + "%");
}
}
CheckAccount类
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 10:24
*/
/**
* 创建Account类的一个子类CheckAccount代表可透支的账户,
* 该账户中定义一个属性overdraft代表可透支限额。
* CheckAccount类中重写withdraw方法,其算法如下:
* 如果(取款金额 < 账户余额),
* 可直接取款
* 如果(取款金额 > 账户余额),计算需要透支的额度
* 判断可透支额overdraft是否足够支付本次透支需要,如果可以
* 将账户余额修改为0,冲减可透支金额
* 如果不可以
* 提示用户超过可透支额的限
*/
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;
}
@Override
public void withdraw(double amount) {
if (getBalance() >= amount){//余额足够
//方式一
// setBalance(getBalance() - amount);
//方式二
super.withdraw(amount);
}else if (overdraft >= (amount - getBalance())){//透支额度够
overdraft -= (amount - getBalance());
setBalance(0);
}else {
System.out.println("超过可透支限额");
}
}
public double getOverdraft() {
return overdraft;
}
public void setOverdraft(double overdraft) {
this.overdraft = overdraft;
}
}
CheckAccountTest类
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 10:38
*/
/**
* 写一个用户程序测试CheckAccount类。
* 在用户程序中,创建一个账号为1122、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象。
* 使用withdraw方法提款5000元,并打印账户余额和可透支额。
* 再使用withdraw方法提款18000元,并打印账户余额和可透支额。
* 再使用withdraw方法提款3000元,并打印账户余额和可透支额。
*/
public class CheckAccountTest {
public static void main(String[] args) {
CheckAccount acct = new CheckAccount(1122,20000,0.045,5000);
acct.withdraw(5000);
System.out.println("您的账户余额为: " + acct.getBalance() + " ,您的可透支额度为: " + acct.getOverdraft());
acct.withdraw(18000);
System.out.println("您的账户余额为: " + acct.getBalance() + " ,您的可透支额度为: " + acct.getOverdraft());
acct.withdraw(3000);
System.out.println("您的账户余额为: " + acct.getBalance() + " ,您的可透支额度为: " + acct.getOverdraft());
}
}
练习3(多态性)
GeometricObject类(父类)
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 19:27
*/
public class GeometricObject {
protected String color;
protected double weight;
public GeometricObject(String color, double weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double findArea(){
return 0.0;
}
}
Circle类(子类)
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 19:31
*/
public class Circle extends GeometricObject{
private double radius;
public Circle(String color, double weight,double radius) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double findArea() {
return Math.PI * radius * radius;
}
}
MyRectangle类(子类)
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 19:34
*/
public class MyRectangle extends GeometricObject {
private double width;
private double height;
public MyRectangle(String color, double weight,double width,double height) {
super(color, weight);
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public double findArea() {
return width * height;
}
}
GeometricTest类(测试类)
package com.wy.exer1;
/**
* @author wy
* @date 2021/11/14 - 19:37
*/
/**
* 定义一个测试类GeometricTest.
* 编写equalsArea方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术)
* 编写displayGeometricObject方法显示对象的面积(注意方法的参数类型。利用动态非定技术)。
*/
public class GeometricTest {
public static void main(String[] args) {
GeometricTest test = new GeometricTest();
Circle c1 = new Circle("white",1.0,2.3);
test.displayGeometricObject(c1);
Circle c2 = new Circle("white",1.0,3.3);
test.displayGeometricObject(c2);
boolean isEquals = test.equalsArea(c1, c2);
System.out.println("c1和c2的面积是否相等: " + isEquals);
}
public void displayGeometricObject(GeometricObject o){
System.out.println("面积为: " + o.findArea());
}
//测试两个对象的面积是否相等
public boolean equalsArea(GeometricObject o1,GeometricObject o2){
return o1.findArea() == o2.findArea();
}
}
练习4(包装类)
package com.wy.java1;
/**
* @author wy
* @date 2021/11/14 - 21:36
*/
import java.util.Scanner;
import java.util.Vector;
/**
* 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
* 提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。
* 而向量类java.util.Vector可以根据需要动态伸缩。
*
* 创建Vector对象: Vector v=new Vector();
* 给向量添加元素: v.addElement(Object obj);//obj必须是对象
* 取出向量中的元素:Object obj=v.elementAt(0);
* 注意第一个元素的下标是0,返回值是Object类型的。
* 计算向量的长度: v.size();
* 若与最高分相差10分内:A等;20分内:B等;
* 30分内:C等;其它:D等
*/
public class ScoreTest {
public static void main(String[] args) {
//1.实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
//2.创建Vector对象,相当于数组
Vector v = new Vector();
//3.for(;;)或者while(true)添加数据
int maxScore = 0;
for (;;){
System.out.println("请输入学生成绩(以负数代表输入结束): ");
int score = scan.nextInt();
//3.2当输入是负数时,停止添加
if (score < 0){
break;
}
if (score > 100){
System.out.println("输入的数据非法,请重新输入: ");
continue;
}
//3.1添加操作
// Integer isScore = new Integer(score);
v.addElement(score);
//4.获取成绩最大值
if (maxScore < score){
maxScore = score;
}
}
//5.得到每个学生的等级
char level;
for (int i = 0;i < v.size();i++){
Object obj = v.elementAt(i);
// Integer isScore = (Integer)obj;
// int score = isScore.intValue();
int score = (int)obj;
if ((maxScore - score) <= 10){
level = 'A';
}else if ((maxScore - score) <= 20){
level = 'B';
}else if ((maxScore - score) <= 30){
level = 'C';
}else {
level = 'D';
}
System.out.println("student-" + i + " score is " + score + ",grade is " + level);
}
}
}