AI 摘要
AI
正在生成摘要...
本文内容可能已过时或不再适用,请结合实际情况谨慎参考。

一、实验内容

实验目的:

掌握类的定义和对象的创建。

1. 运行教材第三章中例 3-1 到例 3-8。

例 3-1:求两个数的最大值。

JAVA
public class MaxValue {
    // 自定义成员方法:接收两个整数,返回最大值
    public int doMaxValue(int a, int b) {
        // 三元运算符:条件成立取前者,不成立取后者
        return a > b ? a : b;
    }

    public static void main(String[] args) {
        MaxValue m = new MaxValue();
        // 调用自定义方法,传入参数 3 和 5
        int max = m.doMaxValue(3, 5);
        System.out.println("这两个数的最大值是:" + max);
    }
}

运行结果:

PLAINTEXT
这两个数的最大值是:5

图片

例 3-2:求输出数的最大值

JAVA
// 演示 Java 方法重载:同类中方法名相同,参数列表不同
public class OverloadMaxValue {
    // 重载方法 1:一个 int 参数
    public void doMaxValue(int a) {
        System.out.println(a);
    }

    // 重载方法 2:两个 int 参数,用三元运算符返回最大值
    public int doMaxValue(int a, int b) {
        return a > b ? a : b;
    }

    public static void main(String[] args) {
        OverloadMaxValue m = new OverloadMaxValue();

        // 自动匹配调用 单个参数 的重载方法
        m.doMaxValue(30);

        // 自动匹配调用 两个参数 的重载方法并打印结果
        System.out.println(m.doMaxValue(30, 40));
    }
}

运行结果:

PLAINTEXT
30
40

图片

例 3-3:定义一个学生类,创建学生对象,给学生对象赋值,并调用学生上课的方法。

JAVA
class Student {
    // 成员变量(属性)
    String no;   // 学号
    String name; // 姓名
    int age;     // 年龄

    // 成员方法(行为):学生上课
    public void goToClass() {
        System.out.println(name + "学生去上课!");
    }
}

public class Test {
    public static void main(String[] args) {
        // 1. 创建 Student 对象(实例化)
        Student stu = new Student();

        // 2. 为对象属性赋值
        stu.no = "soft001";
        stu.name = "张三";
        stu.age = 20;

        // 3. 调用对象的成员方法
        stu.goToClass();
    }
}

运行结果:

PLAINTEXT
张三学生去上课!

图片

例 3-4:this 关键字的实例。

JAVA
// 演示 this 关键字:区分成员变量和局部变量
public class Student {
    String name;

    // 构造方法:创建对象时自动调用,用于初始化属性
    // 参数 name 是局部变量,与成员变量重名
    public Student(String name) {
        // this.成员变量 = 局部变量
        // this 代表当前对象,用来区分重名变量
        this.name = name;
    }

    public static void main(String[] args) {
        // 创建对象,自动调用构造方法
        Student stu = new Student("soft");
        // 输出成员变量值
        System.out.println("学生姓名:" + stu.name);
    }
}

运行结果:

PLAINTEXT
学生姓名:soft

图片

例 3-5:重新定义学生的类。

JAVA
// 演示构造方法重载 + this() 调用本类构造方法
public class Student {
    String name;

    // 带参数构造方法:接收姓名并赋值
    public Student(String name) {
        // this 代表当前对象,给成员变量赋值
        this.name = name;
    }

    // 无参构造方法
    public Student() {
        // this(...) 调用本类带参构造方法
        // 必须写在构造方法第一行
        this("soft");
    }

    public static void main(String[] args) {
        Student stu = new Student();
        System.out.println(stu.name);
    }
}

运行结果:

PLAINTEXT
soft

图片

例 3-6:包的创建实例。

JAVA
// 包声明:必须放在代码第一行(注释除外)
package li_3_6;

public class Student {
    String name;

    public Student(String name) {
        this.name = name;
    }
}

图片

例 3-7:内部类实例。

JAVA
// 外部类
class OuterClass {
    // 外部类私有静态变量
    private static String university = "xxxx";
    // 外部类私有实例变量
    private String name;
    private int age;

    // 外部类构造方法:初始化成员变量
    public OuterClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 成员内部类(非静态内部类)
    public class InnerClass {
        // 内部类成员变量
        private String school = "soft";

        // 内部类方法:访问外部类所有成员
        public void print() {
            // 访问外部类静态成员
            System.out.println(OuterClass.university);
            // 访问外部类实例成员
            System.out.println(OuterClass.this.name);
            System.out.println(OuterClass.this.age);
            // 访问内部类自己的成员
            System.out.println(school);
        }
    }
}

public class InnerClassTest {
    public static void main(String[] args) {
        // 1. 先创建外部类对象
        OuterClass outer = new OuterClass("bks", 29);
        // 2. 通过外部类对象创建内部类对象(固定语法)
        OuterClass.InnerClass innerClass = outer.new InnerClass();
        // 3. 调用内部类方法
        innerClass.print();
    }
}

运行结果:

PLAINTEXT
xxxx
bks
29
soft

图片

例 3-8:静态的内部类举例。

JAVA
// 外部类
class OuterClass {
    // 外部类静态成员变量
    private static String university = "xxxx";
    // 外部类实例成员变量
    private String name;
    private int age;

    // 外部类构造方法
    public OuterClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 静态内部类:使用 static 修饰
    public static class InnerClass {
        // 静态内部类的成员变量
        private String school = "soft";

        // 内部类方法
        public void print() {
            // 静态内部类可以直接访问外部类静态成员
            System.out.println(OuterClass.university);
            // 访问内部类自己的成员
            System.out.println(school);
        }
    }
}

public class InnerClassStaticTest {
    public static void main(String[] args) {
        // 静态内部类直接创建,不需要外部类对象
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
        // 调用方法
        innerClass.print();
    }
}

运行结果:

PLAINTEXT
xxxx
soft

图片

一、非静态内部类(普通内部类)

  • 必须先创建外部类对象,才能创建它;
  • 能直接访问外部类所有成员(静态、非静态都可以);
  • 里面不能写 static 变量、static 方法。

二、静态内部类(static 修饰的内部类)

  • 不用创建外部类对象,能直接单独 new;
  • 只能直接访问外部类的 static 成员;想访问外部普通成员,必须手动 new 外部类对象;
  • 内部随便写普通变量、static 变量、static 方法都允许。

三、考试标准简答(直接写答案)

  • 非静态内部类依赖外部类实例存在,有指向外部类对象的引用,可访问外部类全部成员,类内部不允许定义静态成员;
  • 静态内部类独立于外部类实例,仅可直接访问外部类静态成员,类内部可定义静态、非静态成员。

2. 创建一个名为 Rectangle 的类,用来表示一个矩形,该类包含长、宽两个属性,包含一个求面积(getArea())和一个求周长(getPerimeter())的方法,创建对象并测试 getArea() 和 getPerimeter() 两个方法。

(1)定义 Rectangle 类

JAVA
// 矩形类:定义属性、构造方法、求面积/周长的功能
public class Rectangle {
    // 成员变量:长和宽
    double length;
    double width;

    // 无参构造方法
    public Rectangle() {

    }

    // 有参构造方法:创建对象时直接初始化长和宽
    public Rectangle(double length, double width) {
        // this 区分成员变量和参数
        this.length = length;
        this.width = width;
    }

    // 计算面积
    public double getArea() {
        return length * width;
    }

    // 计算周长
    public double getPerimeter() {
        return 2 * (length + width);
    }
}

(2)定义 TestRectangle 测试类

JAVA
import java.util.Scanner;

// 测试类:演示两种创建矩形对象的方式
public class TestRectangle {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 方式一:无参构造创建对象,再手动赋值
        System.out.println("===== 无参构造方式 =====");
        Rectangle rect1 = new Rectangle();
        System.out.print("请输入矩形的长:");
        rect1.length = scanner.nextDouble();
        System.out.print("请输入矩形的宽:");
        rect1.width = scanner.nextDouble();

        System.out.println("矩形面积:" + rect1.getArea());
        System.out.println("矩形周长:" + rect1.getPerimeter());

        // 方式二:有参构造创建对象,直接传参初始化
        System.out.println("\n===== 有参构造方式 =====");
        System.out.print("请输入矩形的长:");
        double len = scanner.nextDouble();
        System.out.print("请输入矩形的宽:");
        double wid = scanner.nextDouble();

        Rectangle rect2 = new Rectangle(len, wid);
        System.out.println("矩形面积:" + rect2.getArea());
        System.out.println("矩形周长:" + rect2.getPerimeter());

        scanner.close();
    }
}

运行结果:

PLAINTEXT
===== 无参构造方式 =====
请输入矩形的长:15
请输入矩形的宽:15
矩形面积:225.0
矩形周长:60.0

===== 有参构造方式 =====
请输入矩形的长:15
请输入矩形的宽:15
矩形面积:225.0
矩形周长:60.0

图片

二、课后习题

第三章:类和对象

第三章 一、填空题:
  1. 类的定义由类头和 类体 两部分组成。
  2. 是组成 Java 程序的基本要素,封装了一类对象的状态和方法。
  3. 类的实现包括两部分:类声明和 类体
  4. 类体有两部分构成:一部分是 变量 的定义,另一部分是方法的定义。
  5. 在类体中,变量定义部分所定义的变量称为类的 成员变量
  6. 成员变量在整个类内都有效,局部 变量只在定义它的方法内有效。
  7. 用修饰符 static 说明的成员变量是类变量。
  8. 变量的名字与成员变量的名字相同,则成员变量被 隐藏,该成员变量在这个方法内暂时失效。
  9. Java 中成员变量又分为实例成员变量和 静态成员变量(类变量)
  10. 用修饰符 static 说明的成员变量是 静态成员变量(类变量)
  11. 局部变量的名字与成员变量的名字相同,若想在该方法内使用成员变量,必须使用关键字 this
  12. 方法定义包括两部分:方法的声明(方法头) 和方法体。
  13. 在 Java 中,当一个方法不需要返回数据时返回类型必须是 void
  14. Java 中类的方法分为 实例方法 和类方法。
  15. 在类方法中只能调用类变量和类方法,不能调用 实例 方法。
第三章 二、选择题:
  1. 在编写实现文件读写功能的 Java 程序时,需要在程序的开头写上语句(C)。
    (A)import java.applet.*;(Applet 相关包)
    (B)import java.awt.*;(图形界面相关包)
    (C)import java.io.*;(文件读写需要使用 IO 包,正确)
    (D)import java.awt.event.*;(事件处理相关包)

  2. 有一个类 A,以下为其构造函数的声明,其中正确的是(B)。
    (A)void A(int x){...}(构造函数不能有返回值类型,错误)
    (B)A(int x){...}(与类名同名、无返回值类型,正确)
    (C)a(int x){...}(构造函数名必须和类名完全一致,错误)
    (D)void a(int x){...}(有返回值类型,且方法名与类名不一致,错误)

  3. 下列方法定义中,正确的是(D)。
    (A)int x( int a, b ) { return (a - b); }(形参 b 未声明数据类型,错误)
    (B)double x( int a, int b) { int w; w = a - b; }(返回值类型为 double,但方法体无 return 语句,错误)
    (C)double x( a, b ) { return b; }(形参 a、b 未声明数据类型,错误)
    (D)int x( int a, int b) { return a - b; }(形参声明完整,返回值类型与 return 语句匹配,正确)

  4. 下列类定义中,不正确的是(C)。
    (A)class x { .... }(普通类定义,合法)
    (B)class x extends y { .... }(类继承定义,合法)
    (C)static class x implements y1,y2 { .... }(外部类不能用 static 修饰,只有静态内部类才可以用 static 修饰,错误)
    (D)public class x extends Applet { .... }(公共类继承 Applet,合法)

  5. 对于下列代码:

JAVA
public class Parent {
    public int addValue(int a, int b) {
        int s;
        s = a + b;
        return s;
    }
}

class Child extends Parent {
}

下述(CD)方法可以加入类 Child?

(A) int addValue(int a, int b){// do something...}(错误,同签名试图重写,无修饰符(包权限)比父类public权限更严格,Java 禁止重写时缩小访问权限,编译报错,不可加入)
(B) public void addValue(int a, int b){// do something...}(错误,参数列表未变,仅修改返回值,既不满足重写返回值要求,也不构成重载,编译报错,不可加入)
(C) public int addValue(int a){// do something...}(正确,方法名相同、参数个数不同,构成方法重载,语法合法,可加入)
(D) public int addValue(int a, int b){// do something...}(正确,方法签名、权限、返回值均与父类匹配,是合法方法重写,可加入)

方法签名 = 方法名 + 参数列表(个数、类型、顺序)。返回值不属于签名的一部分!

子类可以重写或者重载父类的方法

  • 重写要求:子类重写父类同签名方法,返回值必须兼容(int/Integer),不能直接改成 void ,权限不能缩小,否则编译器直接报语法错误,和你大括号里打印什么毫无关系。
  1. (与上面选择题的第 1 题重复!!!省略)

  2. 以下关于构造函数的描述错误的是(A)。
    (A) 构造函数的返回类型只能是 void 型(错误,构造函数没有返回值类型,也不能写 void)
    (B) 构造函数是类的一种特殊函数,它的方法名必须与类名相同(正确)
    (C) 构造函数的主要作用是完成对类的对象的初始化工作(正确)
    (D) 一般在创建新对象时,系统会自动调用构造函数(正确)

  3. 关于修饰符 static ,以下叙述错误的是(D)。
    (A) static 方法不可被覆盖(正确,静态方法不参与多态,不能被重写)
    (B) static 可以用来修饰类(正确,Java 中可以定义静态内部类)
    (C) static 方法不可以直接访问非静态的方法,否则编译出错(正确,静态方法中没有隐式 this,无法直接访问非静态成员)
    (D) static 方法只能访问类变量或方法参数,不可直接访问成员变量(错误,静态方法也可以访问局部变量(静态方法内部,完全可以自己定义局部变量并使用),不只是类变量和方法参数)

  4. 给出如下代码:

JAVA
class Test {
    //定义成员 a
    public static void fun() {
        // some code...
    }
}

要在函数 fun() 中直接访问 a ,以下成员变量 a 定义正确的是(B)。

(A) public int a(错误,非静态成员变量,不能被静态方法直接访问)
(B) static int a(正确,静态成员变量,可以被静态方法直接访问)
(C) int a(错误,非静态成员变量,不能被静态方法直接访问)
(D) protected int a(错误,非静态成员变量,不能被静态方法直接访问)

  1. 编译并运行以下程序,以下描述哪个选项是正确的(C)。
JAVA
class ATestOfToString {
    protected String toString(){
        return super.toString();
    }
}

(A) 编译通过运行无异常(错误)
(B) 编译通过但运行时出错(错误)
(C) 行 2 出错,不能成功编译(正确,方法重写时,子类方法的访问权限不能比父类更严格。Object 类的 toString() 方法是 public 的,这里用 protected 修饰会编译报错)
(D) 不能成功编译,行 3 出错(错误,错误在第 2 行的方法声明)

第三章 三、输出结果题:

阅读下面的程序,程序保存为 Test.java。

JAVA
public class Test {
    short mValue;

    public static void main(String[] args) {
        int a = 32;
        int b = 56;
        Test os = new Test(a + b);
        os.Show();
    }

    protected Test(short aValue) {
        mValue = aValue;
    }

    public void Show() {
        System.out.println(mValue);
    }
}

上面的程序编译是否成功?如果编译出错,指出哪行出错,并说明理由;如果编译正确,运行结果是什么?

答案:

编译错误,错误出现在第 7 行 Test os = new Test(a+b);

变量 a 和 b 均为 int 类型,因此 a+b 的运算结果也是 int 类型。而构造方法 protected Test(short aValue) 要求传入 short 类型的参数。在 Java 中,高数据类型(int)无法自动转换为低数据类型(short),必须进行强制类型转换,否则编译器会报错。

第三章 四、问答题:
  1. 什么是对象?什么是类?对象与类的关系是什么?
答案:
  • 对象是现实世界中某一类事物的具体实例,包含属性(状态)和行为(方法),万物皆可为对象。
  • 类是对一组具有相同属性和行为的对象的抽象描述,是创建对象的模板。
  • 关系:类是对象的抽象,对象是类的实例化;类是抽象概念,对象是具体实体;一个类可以实例化出多个对象。
  1. 类的定义中包括哪些基本信息?
答案:
  • 类头:[修饰符] class 类名 [extends 父类名] [implements 接口列表]
  • 类体:
    • 属性(成员变量)定义:描述对象的状态
    • 方法定义:描述对象的行为,包括构造方法和普通方法。
  1. 如何运行被打包后的字节码文件?
答案:

java 主类名(通过 JVM 解释执行字节码文件)

  1. 类变量与实例变量的区别有哪些?
答案:
  • 类变量(静态变量,static 修饰):属于整个类,被所有对象共享;一个对象修改其值后,所有对象访问到的都是修改后的值。
  • 实例变量(非静态变量):属于每个对象私有,每个对象都有独立的副本;一个对象修改其值,不影响其他对象的同名实例变量(比如人的年龄 age)。
  1. 类方法与实例方法的区别有哪些?
答案:
  • 类方法(静态方法,static 修饰):属于整个类,不依赖对象;只能访问类变量和其他类方法,不能直接访问实例变量和实例方法;可通过类名.方法名()或对象.方法名()调用;不能被重写。
  • 实例方法(非静态方法):属于对象,必须通过对象调用;既可以访问类变量、类方法,也可以访问实例变量和实例方法;可以被重写。
  1. 什么叫构造函数重载?
答案:

在同一个类中,定义多个方法名与类名完全相同,但参数列表(参数个数、类型或顺序)不同的构造方法,就构成了构造函数重载。作用是提供多种方式创建对象,方便对象初始化。

  1. 什么是方法,及方法的作用有哪些?
答案:
  • 方法是定义在类中、具有特定功能的代码块,描述对象的行为。
  • 作用:封装一段重复执行的逻辑,提高代码复用率;让代码结构更清晰,便于维护和修改;实现特定的功能,完成数据的处理和返回。
  1. Java 中引入包的优点是什么?
答案:
  • 解决命名冲突:不同包中的类可以同名,避免重名问题;
  • 组织和管理类:将相关的类和接口按功能分组,方便查找和管理;
  • 提供访问控制:包配合访问修饰符,可以实现类和成员的封装与权限控制;
  • 支持模块化开发:不同功能模块可以放在不同的包中,便于项目分工和维护。
  1. 如何将需要的外部类引入程序中?如何引用包中的某个类?如何引用整个包?
答案:

在 Java 中通过 import 语句引入外部类。

JAVA
// 引用包中的某个类:
import 包名.类名;
// 例如:import java.util.Scanner;
JAVA
// 引用整个包中的所有类:
import 包名.*;
// 例如:import java.util.*;

也可以不写 import,直接在代码中使用类的全限定名:包名.类名,例如:java.util.Scanner sc = new java.util.Scanner(System.in);

第三章 五、编程题:

第一题:

编写一个完整的 Java Application 程序,包括:①复数类 Complex;②主类 Test。将每组测试数据相加并显示结果,三组测试的复数为:1 + 2i 和 1 - 2i;1 + 2i 和 3 + 4i;1 + 2i 和 -1 + 2i。其中,复数类 Complex 必须满足如下要求:

(1) 复数类 Complex 的属性

  • realPart:int 型,代表复数的实部。
  • imaginPart:int 型,代表复数的虚部。

(2) 复数类 Complex 的方法

  • Complex():构造函数,将复数的实部和虚部都置 0。
  • Complex(int r,int i):构造函数,将复数的实部初始化为 r,将虚部初始化为 i。
  • Complex complexAdd(Complex a):将当前复数对象与形参复数对象 a 相加,所得的结果仍是一个复数对象,返回给此方法的调用者。
  • public String toString():把当前复数对象的实部、虚部组合成 “a + bi” 的字符串形式;若实部为 0,虚部不为 0,则返回 “bi”;若虚部为 0,则返回 “a”。
答案:
JAVA
// 定义复数类 Complex
class Complex {
    int realPart;       // 实部
    int imaginPart;     // 虚部

    // 无参构造方法,实部虚部初始化为 0
    Complex() {
        realPart = 0;
        imaginPart = 0;
    }

    // 带参构造方法,初始化实部和虚部
    Complex(int r, int i) {
        realPart = r;
        imaginPart = i;
    }

    // 复数加法:当前复数 + 参数复数,返回新复数
    Complex complexAdd(Complex a) {
        int r = this.realPart + a.realPart;
        int i = this.imaginPart + a.imaginPart;
        return new Complex(r, i);
    }

    // 格式化输出复数字符串,重写 Object 类的 toString 方法
    @Override
    public String toString() {
        if (realPart == 0 && imaginPart != 0) {
            return imaginPart + "i";
        } else if (imaginPart == 0) {
            return realPart + "";
        } else {
            return realPart + "+" + imaginPart + "i";
        }
    }
}

public class Test {
    public static void main(String[] args) {
        // 第一组:1+2i 和 1-2i
        Complex c1 = new Complex(1, 2);
        Complex c2 = new Complex(1, -2);
        System.out.println(c1 + " + " + c2 + " = " + c1.complexAdd(c2));

        // 第二组:1+2i 和 3+4i
        Complex c3 = new Complex(1, 2);
        Complex c4 = new Complex(3, 4);
        System.out.println(c3 + " + " + c4 + " = " + c3.complexAdd(c4));

        // 第三组:1+2i 和 -1+2i
        Complex c5 = new Complex(1, 2);
        Complex c6 = new Complex(-1, 2);
        System.out.println(c5 + " + " + c6 + " = " + c5.complexAdd(c6));
    }
}

运行结果:

PLAINTEXT
1+2i + 1+-2i = 2
1+2i + 3+4i = 4+6i
1+2i + -1+2i = 4i

第二题:

创建一个名为 Rectangle 的类来表示一个使用宽度和高度来改变量的矩形,矩形的宽度和高度由构造方法来确定。为 Rectangle 类创建下列方法:

(1)getArea() 返回矩形的面积,要求长和高的范围为 0~50。

(2)getPerimeter() 返回矩形的周长。

(3)Draw 使用星号 (*) 作为描绘字符画出该矩形(假设宽度和高度为整数)。

(4)在另一个类 TestRectangle 中编写 main() 方法来测试 Rectangle 类。

答案:
JAVA
// 矩形类Rectangle
class Rectangle {
    int width;   // 矩形宽度
    int height;  // 矩形高度

    // 构造方法,给宽、高赋值
    Rectangle(int w, int h) {
        width = w;
        height = h;
    }

    // 求面积,宽高限制0~50
    public int getArea() {
        // 超出范围按0处理
        if (width < 0 || width > 50 || height < 0 || height > 50) {
            return 0;
        }
        return width * height;
    }

    // 求周长
    public int getPerimeter() {
        if (width < 0 || width > 50 || height < 0 || height > 50) {
            return 0;
        }
        return 2 * (width + height);
    }

    // 用*打印矩形
    public void Draw() {
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

public class TestRectangle {
    public static void main(String[] args) {
        // 实例化一个宽 4、高 3 的矩形
        Rectangle r = new Rectangle(4, 3);
        System.out.println("面积:" + r.getArea());
        System.out.println("周长:" + r.getPerimeter());
        System.out.println("矩形图形:");
        r.Draw();
    }
}

运行结果:

PLAINTEXT
面积:12
周长:14
矩形图形:
****
****
****

评论