中南林业科技大学Java实验报告六:类的特性

简介: 中南林业科技大学Java实验报告六:类的特性

实验6:类的特性

6.1 实验目的

  1. 掌握类的私有成员和共有成员的定义;
  2. 掌握类的私有成员的访问方法;
  3. 理解类的构造方法的作用和执行过程;
  4. 掌握类的构造方法的定义和关键词this的使用;
  5. 类的静态变量;
  6. 掌握方法的重载。

6.2 实验内容

由实验一到实验三构建的完整Bamboo类,后面实验中用到的核心代码会单独提出来:

public class Bamboo {
    /**
     * 竹子名字
     */
    private String name;
    /**
     * 竹子年龄
     */
    private int age;
    /**
     * 高度
     */
    private float height;
    /**
     * 直径
     */
    private double diameter;
    /**
     * 设置不能超过的最大年龄
     */
    public final static int MAX_AGE = 20;
    /**
     * 类变量
     */
    public static String temp;
    /**
     * 无参构造器
     */
    public Bamboo() {
        System.out.println("无参构造器被调用");
    }
    /**
     * 全参构造器
     *
     * @param name     名字
     * @param age      年龄
     * @param height   高度
     * @param diameter 直径
     */
    public Bamboo(String name, int age, float height, double diameter) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.diameter = diameter;
        System.out.println("全参构造器被调用");
    }
    /**
     * 拷贝构造器
     *
     * @param bamboo 被拷贝的对象
     */
    public Bamboo(Bamboo bamboo) {
        this(bamboo.getName(), bamboo.getAge(), bamboo.getHeight(), bamboo.diameter);
        System.out.println("拷贝构造器被调用");
    }
    /**
     * 静态方法对实例变量和类变量进行赋值
     */
    public static void staticAssignment(){
        temp = "静态方法赋值的静态变量";
        //静态方法是在类加载时期生成的,实例变量是在类对象创建时期生成的
        //根据先后关系,我们不能直接在静态变量中赋值
        //因此在这里我们选择先创建一个对象再赋值
        Bamboo bamboo = new Bamboo();
        bamboo.name = "静态方法中创建的对象的名字";
        System.out.println("静态赋值方法中的实例变量赋值:" + bamboo.name);
    }
    /**
     * 实例方法对实例变量和类变量进行赋值
     */
    public void instanceAssignment(){
        this.name = "实例方法赋值的名字";
        temp = "实例方法赋值的静态变量";
    }
    public double volume() {
        return Math.PI * diameter / 2 * diameter / 2 * height;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        if (age > MAX_AGE) {
            System.out.println("生长年限错误");
        } else {
            this.age = age;
            System.out.println("姓名:" + this.name + " 年龄:" + this.age);
        }
    }
    public float getHeight() {
        return height;
    }
    public void setHeight(float height) {
        this.height = height;
    }
    public double getDiameter() {
        return diameter;
    }
    public void setDiameter(double diameter) {
        this.diameter = diameter;
    }
}

6.2.1 编写一个Java程序,在程序中将实验5的Bamboo(竹子)类,的成员变量age改为私有成员变量,分别编写age的set和get方法,在main方法中新建该类的对象,设置name和age,如果所设置的年龄大于20,则输出”生长年限错误”,否则输出name和age;

【前提引入】

成员变量age改为私有成员变量,并通过get和set方法进行操作,这里就体现了Java这门纯面向对象OOP语言的一个特性:封装

那这里就好好提提封装:

  • 介绍
    封装就是把抽象除的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作才能对数据进行操作
  • 好处
  1. 隐藏实现细节
  2. 可以对数据进行验证,保证安全合理性
  • 封装实现步骤
  1. 将属性进行私有化 private
  2. 提供一个公共的 set 方法,用于对属性判断并赋值
  3. 提供一个公共的 get 方法,用于获取属性的值

【Bamboo类相关核心代码】

/**
     * 竹子名字
     */
    private String name;
    /**
     * 竹子年龄
     */
    private int age;
    /**
     * 设置不能超过的最大年龄
     */
    public final static int MAX_AGE = 20;
    /**
     * 无参构造器
     */
    public Bamboo() {
        System.out.println("无参构造器被调用");
    }
    public void setAge(int age) {
        if(age > MAX_AGE){
            System.out.println("生长年限错误");
        }else {
            this.age = age;
            System.out.println("姓名:" + this.name + " 年龄:" + this.age);
        }
    }

【运行流程】

年龄正常情况:

public static void main(String[] args) {
        Bamboo bamboo = new Bamboo();
        bamboo.setName("正常年龄的小竹子");
        bamboo.setAge(16);
    }

年龄不正常情况:

public static void main(String[] args) {
        Bamboo bamboo = new Bamboo();
        bamboo.setName("不正常年龄的小竹子");
        bamboo.setAge(25);
    }

6.2.2 为Bamboo类添加三个构造方法:其中无参构造方法为输出“Bamboo()构造方法被调用”;以及带有与所有成员变量参数个数和类型相同的构造方法;参数为Bamboo类自身的拷贝构造方法,该法采用this关键字调用第2个构造方法(具体构建参照PPT)。同时在每个构造方法中要输出“XXX构造方法被调用”。最后在main方法中分别调用三种构造方法创建类的对象。

【前提引入】

1️⃣ 构造方法又叫构造器,是类的一种特殊方法,它的主要作用是完成对新对象的初始化

[访问修饰符] 方法名(形参列表){
    方法体;
}

🌿 说明:

  1. 构造器的修饰符可以默认
  2. 构造器没有返回值
  3. 方法名和类名必须一样
  4. 构造器的调用,是系统自动完成的(new 时)

🌿 细节说明:

  1. 一个类可以有多个构造器,即构造器重载
  2. 如果程序员没有自定义类的构造器,那么系统会自动给类生成一个默认的无参构造器,也叫默认构造器💬 这里我们用javap反编译指令演示一下
  • 定义一个HelloWorld类,我们就来一个空类,免麻烦
class HelloWorld{
}
  • 使用 javac编译指令生成字节码二进制文件 HelloWorld.class

  • 使用 javap反编译指令 查看代码,就可以看到生成的无参构造器了(红色框框)

  1. 一旦程序员定义了自己的构造器,默认的无参构造器就被覆盖了,就不能再使用默认的无参构造器了,除非程序员自己显示的定义一下

2️⃣ 讲到构造器,就又可以谈谈与涉及到构造器的对象创建流程

  1. 类加载:方法区中加载类信息(只会加载一次)
  2. 在堆中分配空间(地址)
  3. 完成对象初始化
  1. 默认初始化
  2. 显示初始化
  3. 构造器初始化
  1. 将对象在堆中的地址返回给栈中的对象引用

【Bamboo类相关核心代码】

/**
     * 无参构造器
    */
    public Bamboo() {
        System.out.println("无参构造器被调用");
    }
  /**
     * 全参构造器
     *
     * @param name     名字
     * @param age      年龄
     * @param height   高度
     * @param diameter 直径
     */
    public Bamboo(String name, int age, float height, double diameter) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.diameter = diameter;
        System.out.println("全参构造器被调用");
    }
    /**
     * 拷贝构造器
     *
     * @param bamboo 被拷贝的对象
     */
    public Bamboo(Bamboo bamboo) {
        this(bamboo.getName(), bamboo.getAge(), bamboo.getHeight(), bamboo.diameter);
        System.out.println("拷贝构造器被调用");
    }

【运行流程】

public static void main(String[] args) {
        //调用无参构造器
        Bamboo bamboo1 = new Bamboo();
        //调用全参构造器
        Bamboo bamboo2 = new Bamboo("小竹子", 18, 5.0f, 0.5);
        //调用全参构造器和拷贝构造器
        Bamboo bamboo3 = new Bamboo(bamboo2);
    }

6.2.3 在Bamboo类中增加一个类变量,新建一个无参的静态方法对实例变量和类变量进行赋值,新建一个无参的对象方法对实例变量和类变量进行赋值,在main方法中分别调用上面两个方法,并分别显示其值(无需对Bamboo类中的所有实例变量进行赋值)。

【前提引入】

1️⃣ 类变量

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,去到的都是相同的值,同样任何一个类的对象去修改它时,修改的也是同一个变量。

🌿 定义类变量

访问修饰符 static 数据类型 变量名;

🌿 访问类变量

类名.变量名 //推荐
对象名.变量名

2️⃣ 类方法

当方法中不涉及到任何和对象相关的成员,则可以将方法设计为静态方法,提高开发效率。

在程序实际开发中,往往会将一些通用的方法,设计成静态方法,这样就不需要创建对象就可以使用了,比如对数组排序,完成某个计算任务等

🌿 定义类方法

访问修饰符 static 返回值数据类型 方法名(形参列表){
}

🌿 访问类方法

类名.方法名(实参列表); //推荐
对象名.方法名(实参列表);

3️⃣ 注意事项

  • 类方法,类变量和普通方法都是随着类的加载而加载,将结构信息存储在方法去。类方法中无this参数,普通方法中含有。而普通属性(也叫成员属性)是随着对象的创建而创建,随着对象的销毁而销毁。
  • 类方法中只能访问当前本类的类方法或静态变量,普通成员方法即可以访问非静态成员,也可以访问静态成员。

其实也很理解为什么类方法不能访问当前本类的成员属性,因为类方法是在类加载时期就生成了,而成员属性是在对象创建时才生成。所以你想想,如果类加载时期在类方法中有了成员属性,但对象是在类加载之后才可以生成,这不很矛盾吗,这个成员属性该属于哪个对象呢?类加载时期对象还没生成呢!

【Bamboo类相关核心代码】

/**
     * 竹子名字
     */
    private String name;
    /**
     * 类变量
     */
    public static String temp;
    /**
     * 静态方法对实例变量和类变量进行赋值
     */
    public static void staticAssignment(){
        temp = "静态方法赋值的静态变量";
        //静态方法是在类加载时期生成的,实例变量是在类对象创建时期生成的
        //根据先后关系,我们不能直接在静态变量中赋值
        //因此在这里我们选择先创建一个对象再赋值
        Bamboo bamboo = new Bamboo();
        bamboo.name = "静态方法中创建的对象的姓名";
    }
    /**
     * 实例方法对实例变量和类变量进行赋值
     */
    public void instanceAssignment(){
        this.name = "实例方法赋值的名字";
        temp = "实例方法赋值的静态变量";
    }

【运行流程】

public static void main(String[] args) {
        Bamboo bamboo = new Bamboo();
        bamboo.instanceAssignment();
        System.out.println("实例方法 —— name:" + bamboo.getName() + " temp:" + Bamboo.temp);
        System.out.println("=========================================");
        bamboo.staticAssignment();
        System.out.println("实例方法 —— temp:" + Bamboo.temp);
    }

6.2.4 编写一个Java程序,构造一个类,分别用方法的重载计算长方体体积,圆柱体和球体的体积,并在main方法中设置和输出结果。

【前提引入】

谈谈 方法重载

1️⃣ 基本介绍

Java中允许一个类中多个同名方法的存在,但要求形参列表不一致。

2️⃣ 重载的好处

  • 减轻了记名的麻烦
  • 减轻了起名的麻烦

3️⃣ 注意事项

  • 方法名:必须相同
  • 形参列表:必须不相同——形参类型或个数或顺序至少有一个不同,参数名相不相同无所谓,即方法重载与参数名无关
  • 返回类型:无要求,如参数名一样,可相同可不同

【构建的类代码】

public class Util {
    /**
     * 计算长方体的体积
     *
     * @param length 长
     * @param width  宽
     * @param height 高
     * @return 长方体体积
     */
    public static double cal(double length, double width, double height) {
        return length * width * height;
    }
    /**
     * 计算圆柱体的体积
     *
     * @param r      半径
     * @param height 高
     * @return 圆柱体体积
     */
    public static double cal(double r, double height) {
        return Math.PI * r * r * height;
    }
    /**
     * 计算球体的体积
     *
     * @param r 半径
     * @return 球体体积
     */
    public static double cal(double r) {
        return Math.PI * r * r * r * 4 / 3;
    }
}

【运行流程】

public static void main(String[] args) {
    //求长2,宽3,高4的长方体体积
    System.out.println("长方体体积:" + Util.cal(2, 3, 4));
    //求半径2,高3的圆柱体体积
    System.out.println("圆柱体体积:" + Util.cal(2, 3));
    //求半径为2的球体的体积
    System.out.println("球体体积:" + Util.cal(2));
}


相关文章
|
1天前
|
安全 Java 数据安全/隐私保护
Java一分钟之-Java反射机制:动态操作类与对象
【5月更文挑战第12天】本文介绍了Java反射机制的基本用法,包括获取Class对象、创建对象、访问字段和调用方法。同时,讨论了常见的问题和易错点,如忽略访问权限检查、未捕获异常以及性能损耗,并提供了相应的避免策略。理解反射的工作原理和合理使用有助于提升代码灵活性,但需注意其带来的安全风险和性能影响。
15 4
|
1天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的深度解析
【5月更文挑战第12天】本文将深入探讨Java 8中的两个重要新特性:Lambda表达式和Stream API。我们将从基本概念入手,逐步深入到实际应用场景,帮助读者更好地理解和掌握这两个新特性,提高Java编程效率。
11 2
|
1天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
38 3
|
3天前
|
Java
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
|
3天前
|
存储 安全 Java
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
|
3天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
9 0
|
1天前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
15 5
|
1天前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
1天前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
10 3
|
1天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
51 2