zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【JavaSE】07-面向对象(中)

JavaSE 面向对象 07
2023-09-11 14:19:28 时间

七、面向对象(中)

7.1 继承性

7.1.1 继承性的涵义

( 1 \mathbf{1} 1) 继承性 (inheritance) 定义

​ 个人理解就是把不同子类中共有的属性和方法抽取出来,定义成一个父类。这样,子类可以通过继承父类,获得父类所有的属性和方法 (包括private的属性和方法),减少代码的冗余,并可以在子类中单独定义自己独有的属性和方法。

image-20220224142553266

( 2 \mathbf{2} 2) 继承性的好处

① 减少了代码的冗余,提高了代码的复用性。

② 便于功能的扩展。

③ 为之后多态性的使用,提供了前提。

7.1.2 继承性的格式

class A extends B{
	
}

其中, A是子类、派生类、subclass。B是父类、超类、基类、superclass。

( 1 \mathbf{1} 1) 说明

① 一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

② 特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只有因为封装性的影响,使得子类不能直接调用父类的结构而已。

( 2 \mathbf{2} 2) 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。

7.1.3 继承性的规则

( 1 \mathbf{1} 1) 一个类可以被多个子类继承。

( 2 \mathbf{2} 2) Java中类的单继承性:一个类只能有一个父类。

image-20220224142632581

( 3 \mathbf{3} 3) 子父类是相对的概念。

image-20220224142705112

( 4 \mathbf{4} 4) 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类。

( 5 \mathbf{5} 5) 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。

7.1.4 Objec类简介

( 1 \mathbf{1} 1) Object类是Java里所有类最原始的父类。意味着,所有的java类具有java.lang.Object类声明的功能。

( 2 \mathbf{2} 2) 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类。

7.1.5 继承性练习

题目1

image-20220224145805080

① ManKind类:

public class ManKind {
    private int sex;
    private int salary;

    public ManKind() {

    }

    public ManKind(int sex, int salary) {
        this();
        this.sex = sex;
        this.salary = salary;
    }

    public void manOrWoman() {
        switch (sex) {
            case 1:
                System.out.println("man");
                break;
            case 2:
                System.out.println("woman");
                break;
            default:
                System.out.println("Not a mankind!");
                break;
        }
    }

    public void employeed() {
        if (salary != 0) {
            System.out.println("job");
            return;
        } else if (salary == 0) {
            System.out.println("No job");
            return;
        }
        System.out.println("Incur debts");
    }

    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类:继承ManKind类

public class Kids extends ManKind {
    private int yearsOld;

    public Kids() {

    }

    public Kids(int yearsOld) {
        this();
        this.yearsOld = yearsOld;
    }

    public Kids(int sex, int salary, int yearsOld) {
        super(sex, salary);
        this.yearsOld = yearsOld;
    }

    public void printAge() {
        System.out.println("年龄为:" + yearsOld);
    }

    public int getYearsOld() {
        return yearsOld;
    }

    public void setYearsOld(int yearsOld) {
        this.yearsOld = yearsOld;
    }
}

③ 测试

public class KidsTest {
    public static void main(String[] args) {
        Kids someKid = new Kids();
        someKid.setSex(1);
        someKid.setSalary(0);
        someKid.setYearsOld(8);

        someKid.printAge();
        someKid.manOrWoman();
        someKid.employeed();
    }
}

输出:

年龄为:8
man
No job

题目2

image-20220225082901020

① Circle类:

public class Circle {
    private double radius;

    public Circle() {
        radius = 1;
    }

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    public double findArea() {
        return Math.PI * radius * radius;
    }
}

② Cylinder类:

public class Cylinder extends Circle {//继承了Circle类的所有属性和方法
    private double length;

    public Cylinder() {
        length = 1;
    }

    public Cylinder(double length) {
        this.length = length;
    }

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double findVolume() {
        return findArea() * length;
    }
}

③ 测试:

public class CylinderTest {
    public static void main(String[] args) {
        Cylinder cylinder = new Cylinder(5);
        System.out.println("初始底边半径为:" + cylinder.getRadius());//继承了Circle类构造器中把radius设为1
        cylinder.setRadius(4);
        System.out.println("现底边半径为:" + cylinder.getRadius());

        double area = cylinder.findArea();
        System.out.println("圆柱底面积为:" + area);

        double volume = cylinder.findVolume();
        System.out.println("圆柱体积为:" + volume);
    }
}

输出:

初始底边半径为:1.0
现底边半径为:4.0
圆柱底面积为:50.26548245743669
圆柱体积为:251.32741228718345

7.2 方法的重写

7.2.1 重写的概念

( 1 \mathbf{1} 1) 定义

在子类中可以根据需要对从父类中继承来的方法进行改造,也称
为方法的重置、覆盖 。在程序执行时,子类的方法将覆盖父类的方法。

( 2 \mathbf{2} 2) 要求

① 子类重写的方法必须和父类被重写的方法具有相同的方法名称参数列表

② 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型。

  • 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void

  • 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类

  • 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)

③ 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限。

④ 子类不能重写父类中声明为 private 权限的方法。

⑤ 子类方法抛出的异常不能大于父类被重写方法的异常。

( 3 \mathbf{3} 3) 注意

子类与父类中同名同参数的方法必须同时声明为非 static 的 即为 重写 )),或者同时声明 为static 的 不是 重写 。因为 static 方法是属于类的,子类无法覆盖父类的方法。

7.2.2 重写练习

题目1

重写继承性练习2中Cylinder类中的findArea()方法为求表面积。

① Circle类

public class Circle {
    private double radius;

    public Circle() {
        radius = 1.0;
    }

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    public double findArea() {
        return Math.PI * radius * radius;
    }
}

② Cylinder类

public class Cylinder extends Circle {//继承了Circle类的所有属性和方法
    private double length;

    public Cylinder() {
        length = 1.0;
    }

    public Cylinder(double length) {
        this.length = length;
    }

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double findVolume() {
        return Math.PI * getRadius() * getRadius() * length;
    }

    @Override
    public double findArea() {
        return 2 * Math.PI * getRadius() * getRadius() + 2 * Math.PI * getRadius() * length;
    }
}

③ 测试

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

        Cylinder cylinder = new Cylinder(5);
        System.out.println("初始底边半径为:" + cylinder.getRadius());//继承了Circle类构造器中把radius设为1
        cylinder.setRadius(4);
        System.out.println("现底边半径为:" + cylinder.getRadius());

        double bottleArea = cylinder.findArea();
        System.out.println("圆柱底面积为:" + bottleArea);

        double volume = cylinder.findVolume();
        System.out.println("圆柱体积为:" + volume);

        double area = cylinder.findArea();
        System.out.println("圆柱表面积为:" + area);
    }
}

④ 输出

初始底边半径为:1.0
现底边半径为:4.0
圆柱底面积为:226.1946710584651
圆柱体积为:251.32741228718345
圆柱表面积为:226.1946710584651

7.3 四种访问权限修饰符

7.3.1 回顾

image-20220226091821888

( 1 \mathbf{1} 1) 主要领会 “protected” 权限修饰符的作用。

7.4 关键字:super

7.4.1 super的涵义

( 1 \mathbf{1} 1) 在 Java 类中使用 super 来调用父类中的指定操作:

  • ① super 可用于访问父类中定义的属性

    ② super 可用于调用父类中定义的成员方法

    ③ super 可用于在子类构造器中调用父类的构造器

( 2 \mathbf{2} 2) 注意

  • ① 尤其当子父类出现同名成员时,可以用 super 表明调用的是父类中的成员。

    ② super 的追溯不仅限于直接父类。

    ③ super 和 this 的用法相像, this 代表本类对象的引用, super 代表父类的内存空间的标识。

7.4.2 super调用构造器

( 1 \mathbf{1} 1) 我们可以在子类的构造器中显式的使用 “super(形参列表)” 的方式,调用父类中声明的指定的构造器。

( 2 \mathbf{2} 2) "super(形参列表)"的使用,必须声明在子类构造器的首行!

( 3 \mathbf{3} 3) 我们在类的构造器中,针对于 “this(形参列表)” 或 “super(形参列表)” 只能二选一,不能同时出现。

( 4 \mathbf{4} 4) 在构造器的首行,没有显式的声明 “this(形参列表)” 或 “super(形参列表)”,则默认调用的是父类中空参的构造器:super()

( 5 \mathbf{5} 5) 在类的多个构造器中,至少有一个类的构造器中使用了 “super(形参列表)”,调用父类中的构造器。

7.5 子类对象实例化过程

7.5.1 全过程

( 1 \mathbf{1} 1) 从结果上来看:(继承性)

  • 子类继承父类以后,就获取了父类中声明的属性或方法。

    创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。

( 2 \mathbf{2} 2) 从过程上来看:

  • 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类中空参的构造器为止。

    • 正因为加载过所有的父类的结构,所以才可以看到内存中有

    • 父类中的结构,子类对象才可以考虑进行调用。

( 3 \mathbf{3} 3) 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

7.6 多态性

7.6.1 多态性的涵义

( 1 \mathbf{1} 1) 理解多态性:可以理解为一个事物的多种形态。

( 2 \mathbf{2} 2) 何为多态性:

  • 父类的引用指向子类的对象(或子类的对象赋给父类的引用)

( 3 \mathbf{3} 3) 多态的使用:虚拟方法调用

Person p1 = new Man();

其中,Man类是Person类的子类。有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

  • 总结:编译,看左边;运行,看右边。

( 4 \mathbf{4} 4) 多态性的使用前提

  • 类的继承关系

  • 方法的重写

( 5 \mathbf{5} 5) 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)。

7.6.2 多态性的好处

( 1 \mathbf{1} 1) 省去了类中过多重载方法的定义。

7.6.3 操作符:instanceof

( 1 \mathbf{1} 1) 格式:

x instanceof A;
  • 检验 x 是否为类 A 的对象(实例),返回值为 boolean 型。

( 2 \mathbf{2} 2) 多态性有个问题:

  • 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

  • 那如何才能调用子类特有的属性和方法?

    向下转型:使用强制类型转换符。

image-20220226162523798

  • Person p1 = new Man();
    //强制类型转换(向下转型)
    Man m1 = (Man) p1;
    

    其中,Person类是Man类的父类。属于多态性。

  • 但是,这样强制转换,可能出现ClassCastException的异常。

  • 因此,操作符 instanceof顺势而生。

( 3 \mathbf{3} 3) 使用情境

为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。

( 4 \mathbf{4} 4) 如果 a instanceof A返回true,则 a instanceof B也返回true.

其中,类B是类A的父类。

( 5 \mathbf{5} 5)

  • 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法

系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边。

  • 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,

这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边。

7.6.4 多态性练习

题目1

image-20220226195808119

( 1 \mathbf{1} 1) 左列

class Person {
    protected String name = "person";
    protected int age = 50;

    public String getInfo() {
        return "Name: " + name + " n" + "age: " + age;
    }
}

class Student extends Person {
    protected String school = "pku";

    public String getInfo() {
        return "Name: " + name + "\nage : " + age + "\nschool : " + school;
    }
}

class Graduate extends Student {
    public String major = "IT";

    public String getInfo() {
        return "name: " + name + "\nage : " + age + "\nschool : " + school + "\nmajor :" + major;
    }
}

( 2 \mathbf{2} 2) 右列

public class InstanceTest {

    public static void main(String[] args) {
        InstanceTest t = new InstanceTest();
        t.method(new Student());
    }

    public void method(Person e) {
        System.out.println(e.getInfo());
		
        //注意:此处要把小的子类放在最上面
        if (e instanceof Graduate) {
            System.out.println("a graduate student");
            System.out.println("a student");
            System.out.println("a person");
        } else if (e instanceof Student) {
            System.out.println("a student");
            System.out.println("a person");
        } else {
            System.out.println("a person");
        }
    }
}

输出结果:

Name: person
age : 50
school : pku
a student
a person

题目2

image-20220226200244473

( 1 \mathbf{1} 1) GeometricObject类

public class GeometricObject {
    protected String color;
    protected double weight;

    public GeometricObject() {
    }

    public GeometricObject(String color, double weight) {
        super();
        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;
    }
}

( 2 \mathbf{2} 2) Circle类

public class Circle extends GeometricObject {
    private double radius;

    public Circle(double radius) {
        this.radius = 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;
    }
}

( 3 \mathbf{3} 3) MyRectangle类

public class MyRectangle extends GeometricObject {
    private double width;
    private double height;

    public MyRectangle(double width, double height) {
        this.width = width;
        this.height = 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;
    }
}

( 4 \mathbf{4} 4) 测试

public class GeometricTest {

    public static void main(String[] args) {

        GeometricTest t = new GeometricTest();
        Circle c = new Circle(3);
        MyRectangle r = new MyRectangle(6, 4);

        if (t.equalsArea(c, r)) {
            System.out.println("两个图形面积相等。");
        } else {
            System.out.println("两个图形面积不相等。");
        }

        t.displayGeometricObject(c);
        t.displayGeometricObject(r);
    }

    public boolean equalsArea(GeometricObject g1, GeometricObject g2) {
        return g1.findArea() == g2.findArea();
    }

    public void displayGeometricObject(GeometricObject g) {
        if (g instanceof Circle) {
            System.out.println("圆形");
        } else {
            System.out.println("长方形");
        }
        System.out.println("面积为:" + g.findArea());
    }
}

输出结果:

两个图形面积不相等。
圆形
面积为:28.274333882308138
长方形
面积为:24.0

题目3

//考查多态的笔试题目:
public class InterviewTest1 {

    public static void main(String[] args) {
        Base1 base = new Sub1();
        base.add(1, 2, 3);

        Sub1 s = (Sub1) base;
        s.add(1, 2, 3);//
    }
}

class Base1 {
    public void add(int a, int... arr) {
        System.out.println("base1");
    }
}

class Sub1 extends Base1 {

    public void add(int a, int[] arr) {
        System.out.println("sub_1");
    }

    public void add(int a, int b, int c) {
        System.out.println("sub_2");
    }

}

( 1 \mathbf{1} 1) 在同一个类中,int… arr和int[] arr被认为是同一个形参。

( 2 \mathbf{2} 2) 子类Sub1中,只有第一个方法是重写了父类Base1中的,因为它们2个的形参列表都是有2个形参,而第二个方法有3个形参。

( 3 \mathbf{3} 3) 当强转成Sub1类时,优先调用形参个数确定的方法,即第二个方法。

7.7 Object类的使用

7.7.1 Object类的涵义

( 1 \mathbf{1} 1) Object 类是所有 Java 类的根父类。

( 2 \mathbf{2} 2) 如果在类的声明中未使用 extends 关键字指明其父类,则默认父 类为 java.lang.Object 类。

( 3 \mathbf{3} 3) Object 类只声明了一个空参的构造器。

7.7.2 Object类的方法

( 1 \mathbf{1} 1) == 和 equals() 区别

  • 运算符 ==
  • 可以使用在基本数据类型变量和引用数据类型变量中。
  • 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)。
  • 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同。即两个引用是否指向同一个对象实体。
  • == 符号使用时,必须保证符号左右两边的变量类型一致。
  • equals() 方法
  • 是一个方法,而非运算符。

  • 只能适用于引用数据类型。

  • Object类中equals()的定义:

  • public boolean equals(Object obj) {
    	return (this == obj);
    }
    
  • 说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体。

  • 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

( 2 \mathbf{2} 2) 重写equals() 方法

  • 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写。

  • 重写的原则:比较两个对象的实体内容是否相同。

  • 注意:equals()方法可以按Alt+Insert快捷插入。

例子:重写Kids类的equals()方法

我的首次代码:

@Override
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof Kids) {
        Kids anotherKids = (Kids) anObject;
        if (this.sex != anotherKids.sex || this.salary != anotherKids.salary || this.yearsOld != anotherKids.yearsOld) {
            return false;
        }
        return true;
    }
    return false;
}

优化版本代码:

@Override
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof Kids) {
        Kids anotherKids = (Kids) anObject;
        return this.sex == anotherKids.sex && this.salary == anotherKids.salary && this.yearsOld == anotherKids.yearsOld;
    }
    return false;
}

测试:

Kids kid1 = new Kids(1, 0, 12);
Kids kid2 = new Kids(1, 0, 12);
Kids kid3 = new Kids(0, 1, 13);

System.out.println(kid3.equals(kid1));
System.out.println(kid1.equals(kid2));

输出结果:

false
true

注意:

如果对比的属性中有String这种引用数据类型的,就不能用 == (因为会对比地址值),只能用 .equals() 方法。

( 3 \mathbf{3} 3) toString() 方法

  • 它是Object类中的一个方法。

  • 当没有重写时,对对象进行.toString()方法就是获取对象的地址值:

  • Customer cust1 = new Customer("Tom",21);
    System.out.println(cust1.toString());
    System.out.println(cust1);
    
  • 输出结果:

  • com.atguigu.java1.Customer@15db9742
    com.atguigu.java1.Customer@15db9742
    

② 我们可以进行重写.toString()方法,使它能输出我们自定义类的属性。可以按Alt+Insert快捷插入。

7.7.3 Object类的练习

题目1

编写Order类,有int型的orderId,String型的orderName,
相应的getter()和setter()方法,两个参数的构造器,
重写父类的equals()方法:public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等

① Order类

public class Order {
    private int orderID;
    private String orderName;

    public Order() {
    }

    public Order(int orderID, String orderName) {
        this.orderID = orderID;
        this.orderName = orderName;
    }

    public int getOrderID() {
        return orderID;
    }

    public void setOrderID(int orderID) {
        this.orderID = orderID;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return orderID == order.orderID && Objects.equals(orderName, order.orderName);
    }
}

测试:

public class OrderTest {
    public static void main(String[] args) {
        Order o1 = new Order(12, "Van");
        Order o2 = new Order(12, "Van");
        Order o3= new Order(32, "Van");

        System.out.println(o1.equals(o2));
        System.out.println(o1.equals(o3));
    }
}

输出:

true
false


题目2:

image-20220228193140521

① 父类GeometricObject

public class GeometricObject {
    protected String color;
    protected double weight;

    public GeometricObject() {
        color = "white";
        weight = 1.0;
    }

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

② 子类Circle

public class Circle extends GeometricObject {
    private double radius;

    public Circle() {
        super();
        radius = 1.0;
    }

    public Circle(double radius) {
        super();
        this.radius = 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;
    }

    public double findArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Circle circle = (Circle) o;
        return Double.compare(circle.radius, radius) == 0;
    }

    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }
}

③测试

public class CircleTest {
    public static void main(String[] args) {
        Circle c1 = new Circle(2.3);
        Circle c2 = new Circle("white", 2.0, 2.0);

        boolean isColor = c1.getColor().equals(c2.getColor());
        System.out.println("颜色是否相等:" + isColor);

        System.out.println("半径是否相等:" + c1.equals(c2));

        System.out.println(c1.toString());
        System.out.println(c2.toString());
    }
}

输出结果:

颜色是否相等:true
半径是否相等:false
Circle{radius=2.3}
Circle{radius=2.0}

7.8 包装类的使用

7.8.1 包装类的涵义

( 1 \mathbf{1} 1) 基本数据类型如 int、double、char、short等不是类,不能很好地体现面向对象的思想。包装类就是把这些基本数据类型封装成对应的类,并提供方法,让基本数据类型也纳入面向对象的范畴。

( 2 \mathbf{2} 2) 基本数据类型以及对应的包装类:

image-20220301100608006

7.8.2 基本数据类型与包装类间的转换

( 1 \mathbf{1} 1) int型转换成Integer类:

@Test
public void testInt(){
    int num1 = 10;
    Integer int1 = new Integer(num1);
    System.out.println(int1.toString());

    Integer int2= new Integer("123");
    System.out.println(int2.toString());
}

输出结果:

10
123

( 2 \mathbf{2} 2) Float类:

@Test
public void testFloat() {
    Float f1 = new Float(12.3);
    Float f2 = new Float("13.5");
    System.out.println(f1);
    System.out.println(f2);
}

输出:

12.3
13.5

( 3 \mathbf{3} 3) Boolean类

@Test
    public void testBoolean() {
        Boolean b1 = new Boolean(true);
        Boolean b2 = new Boolean("true");
        Boolean b3 = new Boolean("TrUe");

        Boolean b4 = new Boolean("true123");
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);
        System.out.println(b4);
    }

输出:

true
true
true
false

( 4 \mathbf{4} 4) Integer包装类转换成int基本数据类型:

@Test
public void test2() {
    Integer int1 = new Integer(12);
    int i1 = int1.intValue();
    System.out.println(i1 + 2);
}

输出:

14

7.8.3 自动装箱与拆箱

( 1 \mathbf{1} 1) 自动装箱

public void method(Object o) {
	System.out.println(o);
}

@Test
public void test3() {
    int num = 10;
    //此处自动转换成包装类了
    method(num);
}

输出:

10
	//自动装箱:基本数据类型 --->包装类
	int num2 = 10;
	Integer in1 = num2;//自动装箱
		
	boolean b1 = true;
	Boolean b2 = b1;//自动装箱
	
	//自动拆箱:包装类--->基本数据类型
	System.out.println(in1.toString());
	
	int num3 = in1;//自动拆箱

7.8.4 基本数据类型、包装类与String类间的转换

( 1 \mathbf{1} 1) String类型 —>基本数据类型、包装类:调用包装类的parseXxx(String s)

@Test
    public void test5(){
        String str1 = "123";
        //错误的情况:
//    int num1 = (int)str1;
//    Integer in1 = (Integer)str1;
        //可能会报NumberFormatException
        int num2 = Integer.parseInt(str1);
        System.out.println(num2 + 1);

        String str2 = "true1";
        boolean b1 = Boolean.parseBoolean(str2);
        System.out.println(b1);
    }

输出:

124
false

( 2 \mathbf{2} 2) 基本数据类型、包装类—>String类型:调用String重载的valueOf(Xxx xxx):

@Test
public void test4(){
		
	int num1 = 10;
	//方式1:连接运算
	String str1 = num1 + "";
	//方式2:调用String的valueOf(Xxx xxx)
	float f1 = 12.3f;
	String str2 = String.valueOf(f1);//"12.3"
	
	Double d1 = new Double(12.4);
	String str3 = String.valueOf(d1);
	System.out.println(str2);
	System.out.println(str3);//"12.4"
	
}

7.8.4 包装类练习

题目1

@Test
public void test6() {
    //为什么下面两道程序输出的结果不一致?
    Object o1 = true ? new Integer(1) : new Double(2.0);//自动提升
    System.out.println(o1);//我一开始觉得是个地址值,但是Integer包装类有自动拆箱

    Object o2;
    if (true) {
        o2 = new Integer(1);
    } else {
        o2 = new Double(2.0);
    }
    System.out.println(o2);
}

输出结果:

1.0
1

( 1 \mathbf{1} 1) 原因:

条件语句? 执行语句1 : 执行语句2;
  • 要求执行语句1和执行语句2的类型都必须相同。因此,Integer类被自动提升成更高级的Double类。

  • 又因为包装类的自动拆箱机制,输出的就是1.0 。

  • 而 if…else 语句则不存在上述要求,只存在包装类的自动拆箱机制。因此输出的是1 。

题目2:

@Test
public void test7() {
    Integer i = new Integer(1);
    Integer j = new Integer(1);
    System.out.println(i == j);// == 是对比引用数据类型的地址值,因此是false

    Integer m = 1;//自动装箱机制
    Integer n = 1;
    System.out.println(m == n);//为什么是true ?

    Integer x = 128;//自动装箱机制
    Integer y = 128;
    System.out.println(x == y);// 为什么又是false?
}

输出:

false
true
false

( 1 \mathbf{1} 1) 原因:

  • Integer内部定义了IntegerCache结构,IntegerCache中定义了数组Integer[]。
  • 此数组保存了从 -128~127 范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在 -128~127 范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率。
  • 第2部分从此数组中取值,存放的地址是一样的。因此是true。
  • 当第3部分自动装箱为128时,超出了 -128~127 的范围,因此就相当于情况一,重新分别建了一个对象,两个对象的地址值不相同。

题目3:Vector类的使用

image-20220301143006954

public class VectorTest {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Vector v = new Vector();
        System.out.print("请输入学生成绩(输入负数结束):");

        boolean isEnd = true;
        while (isEnd) {
            Integer int1 = scanner.nextInt();
            if (int1 > 100) {
                System.out.println("输入的数据非法,请重新输入!");
            } else if (int1 >= 0) {
                v.addElement(int1);
            } else {
                isEnd = false;
            }
        }

        System.out.println("输入的成绩为:");
        for (int i = 0; i < v.size(); i++) {
            System.out.print(v.elementAt(i) + "\t");
        }
        System.out.println();

        int max = 0;
        for (int i = 0; i < v.size(); i++) {
            Integer int2 = (Integer) v.elementAt(i);
            int i2 = int2;
            if (int2 > max) {
                max = int2;
            }
        }
        System.out.print("最高分:" + max);
        System.out.println();


        for (int i = 0; i < v.size(); i++) {
            Integer int3 = (Integer) v.elementAt(i);
            int s = max - int3;
            if (s >= 0 && s < 10) {
                System.out.println("成绩" + int3 + "为等级:A");
            } else if (s < 20) {
                System.out.println("成绩" + int3 + "为等级:B");
            } else if (s < 30) {
                System.out.println("成绩" + int3 + "为等级:C");
            } else {
                System.out.println("成绩" + int3 + "为等级:D");
            }
        }
    }
}