中南林业科技大学Java实验报告八:包与接口

简介: 中南林业科技大学Java实验报告八:包与接口

实验8:包与接口

8.1 实验目的

  • 了解多个目录下,多个类并存且由类同名的情况下对程序运行的影响
  • 掌握Java程序中包的定义以及使用方法
  • 掌握接口定义的语法格式、成员变量的定义、成员方法的定义
  • 掌握接口实现的语法格式
  • 掌握接口的使用和Java语言中利用接口实现多重继承

8.2 实验内容

实验指导中的代码直接插到这里来了

8.2.1 编写两个Java程序,在Tree.java中,显示“我是一棵树”,在Bamboo.java中,显示“我是一棵竹子”。(实验需在命令行中进行编译)

8.2.1.1 将Tree.java和Bamboo.java放与同一文件夹下

【前提引入】

1️⃣ 如果代码中含有中文并且是在windows的cmd命令行进行javac编译指令的执行,如果直接使用javac Tree.java是会报错:不可映射的字符集编码。

  1. 这是因为我们的代码文件Tree.java是使用的unicode字符集的UTF-8编码,则存储方式(编码)就为UTF-8。
  2. 但是如果在cmd命令行执行javac编码指令,那么首先是需要读取 Tree.java 文件信息的,但是Windows操作系统默认使用 GBK 字符集,这对程序员就很不友好,导致在对 Tree.java 读取时是使用GBK的解码方式。
  3. 即Tree.java存储时是 UTF-8 编码,而读取时是 GBK 解码,因此造成了乱码问题。
  4. 但是如果 Tree.java 中不含有中文,我们使用 javac Tree.java 是没有问题的,因为** Unicode字符集和GBK字符集是完全兼容 ASCII字符集的。**

📍 解决方案:

  1. 在写Tree.java文件时指定字符集为GBK。但是windows11是没有该功能了似乎。
  2. 使用 sublime,notepad 等编译软件,可以指定编码方式为GBK。
  3. 修改windows默认的字符集编码为UTF-8。
  4. 在cmd控制台写命令时指定解码方式为UTF-8,如:javac -encoding utf8 Tree.java。(推荐)

2️⃣ 对下面的代码显示的结果分析:

Tree.java 和 Bamboo.java 文件中都含有 Living 类,因此我们如果这样执行:

  1. 编译Tree.java文件:javac -encoding utf8 Tree.java。这样就会在 package-interface文件夹中 生成 Tree.class 和 Living.class 两个字节码二进制文件。
  2. 编译Bamboo.java文件:javac -encoding utf8 Bamboo.java。这样就会生成在 package-interface文件夹中 Bamboo.class 和 Living.class 两个字节码二进制文件。
  3. Living.class命名冲突问题:由于编译 Tree.java 和 Bamboo.java 时都会生成 Living.java 文件,并且会生成在同一级目录package-interface文件夹下,这必然会冲突。那会发生声明呢?即在编译 Bamboo.java 时生成的 Living.class 会发现 package-interface 文件夹下已经有了 Tree.java编译生成的 Living.class,那么就会覆盖掉有 Tree.java编译生成的 Living.class,在 package-interface 文件下就只有由 Bamboo.java 编译生成的 Living.class 字节码二进制文件了。

【核心代码】

🌿 Tree.java

public class Tree
{
     public static void main(String[] args){
       Living tree=new Living ();
       tree.say();
      }
}
class Living
{
   public void say(){
       System.out.println("我是一棵树");
   }
}

🌿 Bamboo.java

public class Bamboo
{
     public static void main(String[] args)
     {
       Living bamboo =new Living ();
       bamboo.say();
      }
}
class Living
{
   public void say()
   {
       System.out.println("我是一棵竹子");
    }
}

【运行流程】

  1. 将Tree.java和Bamboo.java放与同一文件夹下。

  2. 编译Tree.java,运行Tree,观察提示结果。

  3. 编译Bammboo.java,运行Bammboo,观察提示结果。

  4. 运行Tree,观察提示结果

8.2.1.2 将Tree.java和Bamboo.java放与不同文件夹下

【前提引入】

1️⃣ 如果将两个Living类分别放在两个文件夹Tree和Bamboo中,这样在编译这两个 Living.java 的时候由于在不同文件下生成 Living.class 字节码二进制文件,肯定就不会造成命名冲突,也就不会造成覆盖问题。

📦 谈一谈包

  • 包的三大作用
  1. 目的是区分相同名字的类
  2. 当类很多的时候,能够很好的管理类
  3. 控制访问范围
  • 基础语法
/* 
  声明包:package 关键字 打包名称
  声明当前类所在的包
*/
package com.bamboo //声明当前类是在com包下的子包bamboo下
/*
  引用包:import 关键字 打包名称
  引用某个类
*/
import java.util.Scanner; //引用到 java包下 的 util包 中的 Scanner类文件
import java.net.* //引用java包下 的 net包 中的 所有类文件
  • 本质
    实际上就是创建不同的 文件夹/目录 来保存类文件
  • 注意事项
  1. package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只能有一句package。
  2. import指令位置放在package下面,在类定义上面,可以有多句且没有顺序要求。

【核心代码】

  • Tree文件夹下的Living.java
package Tree; //当前在Tree包中
public class Living
{
   public void say()
   {
       System.out.println("我是一棵树");
    }
}
  • Bamboo文件夹下的Living.java
package Bamboo; //声明当前在 Bamboo包下
public class Living
{
   public void say()
   {
       System.out.println("我是一个小竹子");
    }
}
  • package-interface文件夹下的Tree.java
import Tree.Living; //引用在Tree包下的Living类
public class Tree
{
     public static void main(String[] args)
     {
       Living tree=new Living ();
       tree.say();
      }
}
  • package-interface文件夹下的Bambo.java
import Bamboo.Living; //找Bamboo包下的Living类
public class Bamboo
{
     public static void main(String[] args)
     {
       Living bamboo=new Living ();
       bamboo.say();
      }
}

【运行流程】

  1. 将两个Living类分别放在两个文件夹Tree和Bamboo中,Tree.java和Bamboo.java放在根目录(文件夹Tree和Bamboo的上一级目录下)



  2. 编译Tree.java和Living.java,运行Tree,观察提示结果。
#依次执行以下代码
javac -encoding utf8 Tree\Living.java
javac -encoding utf8 Tree.java
java Tree
  1. 编译Bamboo.java和Living.java,运行Bamboo,观察提示结果。
#依次执行以下代码
javac -encoding utf8 Bamboo\Living.java
javac -encoding utf8 Bamboo.java
java Bamboo
  1. 再次运行Tree,查看结果。

8.2.2 编写一个Java程序,在程序中定义一个接口Bulid,定义一个类Tree实现接口,在Tree类中实现Bulid的接口。

【前提引入-接口简介】

  • 基本介绍
    接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些这些方法写出来。
  • 基本语法
interface 接口名{
  //属性
    //方法(抽象方法,默认实现方法,静态方法)
}
class 类名 implements 接口名{
    //自己属性
    //自己方法
    //必须实现的抽象接口方法
}
  • 注意事项
  1. 接口不能被实例化,必须由类去实现它
  2. 接口所有的方法是 public 方法,接口中抽象方法可以不用 abstract 修饰,因为在javac编译生成 字节码二进制文件 时会认为是抽象方法加上 abstract 关键字。我们在这里可以用 javac反编译指令进行查看:

  3. 接口中的属性,只能是 final 的,而且必须是 public static final 修饰符,则在定义的时候必须初始化或者使用静态代码块进行初始化。
  • 实现接口 vs 继承类
  1. 接口和继承解决的问题不同:
  • 继承的主要价值:解决diamante复用性和可维护性的问题
  • 接口的主要价值:设计,设计好各种规范(方法),让其它类去实现这些方法。

实现接口是 对 java单继承机制 的一种很好的补充。

  1. 接口比继承更灵活
    继承是满足 is-a 关系,而接口只需要满足 like-a 关系。
  2. 接口在一定程度上实现 代码解耦(接口规范化+动态绑定机制)

【核心代码】

  1. Build类
public interface Build {
    public final static double PI = 3.14;
    /**
     * 切面积
     */
    public void area();
    /**
     * 体积
     */
    public void volume();
    /**
     * 用途
     */
    public void use();
}
  1. Tree类
public class Tree implements Build {
    /**
     * 树的半径(单位:m)
     */
    private double r;
    /**
     * 树的高度(单位:m)
     */
    private double h;
    public Tree(double r, double h) {
        this.r = r;
        this.h = h;
    }
    @Override
    public void area() {
        System.out.println("切面积是:" + PI * r * r);
    }
    @Override
    public void volume() {
        System.out.println("体积是:" + PI * r * r * h);
    }
    @Override
    public void use() {
        System.out.println("我的小树用来造我们的小家");
    }
}
  1. Test类
public class Test {
    public static void main(String[] args) {
        Tree tree = new Tree(0.5, 5);
        tree.area();
        tree.volume();
        tree.use();
    }
}

【运行流程】

8.2.3 定义个类Plant,修改(2)声明Tree类继承Plant类,同时实现的Bulid接口内容不变。

【前提引入】

继承不多解释,主要谈谈 super 关键字

  • 基本介绍
    super代表对父类(可以不是直接父类,也可以是超类)的引用,用于访问父类的属性、方法、构造器。
  • 基本语法
  1. 可以访问父类的属性:super.属性名,但不能访问父类的 private属性。
  2. 可以访问父类的方法:super.方法名(实参列表),但不能访问父类的 private方法。
  3. 能访问父类的构造器:super(实参列表),完成父类的初始化工作,只能放在构造器的第一句,且只能出现一句。
  • 注意事项:默认情况下构造器中都会隐式存在super(),调用父类的无参构造器。我们举个例子,看下如下代码:
public class Animal {
    String name;
    /**
     * 这是有参构造器,
     * 因此如果没有声明无参构造器,那么该类中不会存在无参构造器
     */
    public Animal(String name) {
        this.name = name;
    }
}
class Dog extends  Animal{
    public Dog(){
    }
}
  • 这段代码会是错的,因为我们在调用Dog类的无参构造器中会默认存在一句super(),但是父类 Animal类 中并不存在无参构造器,因此发生错误,修改:
public class Animal {
    String name;
    /**
     * 这是有参构造器,
     * 因此如果没有声明无参构造器,那么该类中不会存在无参构造器
     */
    public Animal(String name) {
        this.name = name;
    }
}
class Dog extends  Animal{
    public Dog(String name){
        //如果显示的声明了 super调用,那么默认的 super() 就不会存在在代码中了
        super(name);
    }
}

【核心代码】

  1. 创建Plant类
public class Plant {
    private String name;
    private int age;
    public Plant(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void introduce() {
        System.out.println("我是一颗生长了 " + age + " 年的 " + name + " 树");
    }
}
  1. 修改Tree类
public class Tree extends Plant implements Build {
    /**
     * 树的半径(单位:m)
     */
    private double r;
    /**
     * 树的高度(单位:m)
     */
    private double h;
    public Tree(double r, double h, String name, int age) {
        //父类构造器初始化
        super(name, age);
        this.r = r;
        this.h = h;
    }
    @Override
    public void introduce() {
        //调用父类的 introduce 方法
        super.introduce();
    }
    @Override
    public void area() {
        System.out.println("切面积是:" + PI * r * r);
    }
    @Override
    public void volume() {
        System.out.println("体积是:" + PI * r * r * h);
    }
    @Override
    public void use() {
        System.out.println("我的小树用来造我们的小家");
    }
}
  1. 修改Test类
public class Test {
    public static void main(String[] args) {
        Tree tree = new Tree(0.5, 5,"逐浪",18);
        tree.introduce();
    }
}

【运行流程】


相关文章
|
4月前
|
消息中间件 缓存 前端开发
从资损百万到零事故:Java 接口幂等设计的艺术与实践
在分布式系统中,重复请求常引发严重资损,如支付双扣、库存超卖等问题,其根源在于接口缺乏幂等性设计。本文通过真实案例揭示幂等性的重要性,并详解8种主流解决方案,涵盖唯一请求ID、乐观锁、悲观锁、状态机等,帮助开发者构建稳定系统,保障业务一致性。无论你是架构师还是开发工程师,都能从中获得实战指导,有效规避重复调用带来的风险。
298 2
|
4月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
6月前
|
资源调度 安全 Java
Java 大数据在智能教育在线实验室设备管理与实验资源优化配置中的应用实践
本文探讨Java大数据技术在智能教育在线实验室设备管理与资源优化中的应用。通过统一接入异构设备、构建四层实时处理管道及安全防护双体系,显著提升设备利用率与实验效率。某“双一流”高校实践显示,设备利用率从41%升至89%,等待时间缩短78%。该方案降低管理成本,为教育数字化转型提供技术支持。
166 1
|
3月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
144 11
|
2月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
210 1
|
8月前
|
消息中间件 算法 安全
JUC并发—1.Java集合包底层源码剖析
本文主要对JDK中的集合包源码进行了剖析。
|
4月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
271 23
|
4月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
248 12
|
6月前
|
消息中间件 机器学习/深度学习 Java
java 最新技术驱动的智能教育在线实验室设备管理与实验资源优化实操指南
这是一份基于最新技术的智能教育在线实验室设备管理与实验资源优化的实操指南,涵盖系统搭建、核心功能实现及优化策略。采用Flink实时处理、Kafka消息队列、Elasticsearch搜索分析和Redis缓存等技术栈,结合强化学习动态优化资源调度。指南详细描述了开发环境准备、基础组件部署、数据采集与处理、模型训练、API服务集成及性能调优步骤,支持高并发设备接入与低延迟处理,满足教育机构数字化转型需求。代码已提供下载链接,助力快速构建智能化实验室管理系统。
177 44