中南林业科技大学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放与同一文件夹下。

    image-20221011212027116

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

    image-20221101163723844

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

    image-20221101162554167

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

    image-20221101164042794

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的上一级目录下)

    image-20221101170902471

    image-20221101170951248

    image-20221101170929781

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

    #依次执行以下代码
    javac -encoding utf8 Tree\Living.java
    
    javac -encoding utf8 Tree.java
    
    java Tree
    

    image-20221108134625741

  3. 编译Bamboo.java和Living.java,运行Bamboo,观察提示结果。

    #依次执行以下代码
    javac -encoding utf8 Bamboo\Living.java
    
    javac -encoding utf8 Bamboo.java
    
    java Bamboo
    

    image-20221108134747170

  4. 再次运行Tree,查看结果。

    image-20221101171419313

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

【前提引入-接口简介】

  • 基本介绍

    接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些这些方法写出来。

  • 基本语法

    interface 接口名{
    	//属性
        //方法(抽象方法,默认实现方法,静态方法)
    }
    
    class 类名 implements 接口名{
        //自己属性
        //自己方法
        
        //必须实现的抽象接口方法
    }
    
  • 注意事项

    1. 接口不能被实例化,必须由类去实现它

    2. 接口所有的方法是 public 方法,接口中抽象方法可以不用 abstract 修饰,因为在javac编译生成 字节码二进制文件 时会认为是抽象方法加上 abstract 关键字。我们在这里可以用 javac反编译指令进行查看:

      image-20221106121013182

    3. 接口中的属性,只能是 final 的,而且必须是 public static final 修饰符,则在定义的时候必须初始化或者使用静态代码块进行初始化。

  • 实现接口 vs 继承类

    1. 接口和继承解决的问题不同:

      • 继承的主要价值:解决diamante复用性和可维护性的问题
      • 接口的主要价值:设计,设计好各种规范(方法),让其它类去实现这些方法。

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

    2. 接口比继承更灵活

      继承是满足 is-a 关系,而接口只需要满足 like-a 关系。

    3. 接口在一定程度上实现 代码解耦(接口规范化+动态绑定机制)

【核心代码】

  1. Build类

    public interface Build {
        public final static double PI = 3.14;
    
        /**
         * 切面积
         */
        public void area();
    
        /**
         * 体积
         */
        public void volume();
    
        /**
         * 用途
         */
        public void use();
    }
    
  2. 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("我的小树用来造我们的小家");
        }
    }
    
  3. Test类

    public class Test {
        public static void main(String[] args) {
            Tree tree = new Tree(0.5, 5);
            tree.area();
            tree.volume();
            tree.use();
        }
    }
    

【运行流程】

image-20221101172846057

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 + " 树");
        }
    }
    
  2. 修改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("我的小树用来造我们的小家");
        }
    }
    
  3. 修改Test类

    public class Test {
        public static void main(String[] args) {
            Tree tree = new Tree(0.5, 5,"逐浪",18);
            tree.introduce();
        }
    }
    

【运行流程】

image-20221101173506058

包与接口实验报告 实验 包与接口 【实验目的】 1. 了解Java 中包(package)、接口(interface)的作用。 2. 掌握包、接口设计方法。 【实验要求】 1. 了解Java 系统包的结构。 2. 掌握创建自定义包的方法。 3. 掌握使用系统接口的技术和创建自定义接口的方法。 【实验步骤】 一.了解并使用Java 的系统包 1. API 包、接口、异常处理的作用 包是类和接口的集合。利用包可以把常用的类或功能相似的类放在一个包中。Java 语言提供系统包,其中包含了大量的类,可以在编写Java 程序时直接引用它们。为便于管理和使用它们,将这些类分为了不同的包。包又称类库或API 包,所谓API(Application Program Interface)即应用程序接口。API 包—方面提供丰富的类与方法供大家使用,如画图形、播放声音等,另一方面又负责和系统软硬件打交道,圆满实现用户程序的功能。所有Java API 包都以“java.”开头,以区别用户创建的包。 常见Java系统包及其作用: 1)语言包(java.lang):提供的支持包括字符串处理、多线程处理、异常处理、数学函数处理等,可以用它简单地实现Java程序的运行平台。 2)实用程序包(java.util):提供的支持包括哈希表、堆栈、可变数组、时间和日期等。 输入输出包(java.io):用统一的流模型来实现所有格式的I/O,包括文件系统、网络、输入。 3)网络包(java.net):支持Internet的TCP/IP协议,用于实现Socket编程;提供了与Internet的接口,支持URL连接,WWW的即时访问,并且简化了用户/服务器模型的程序设计。 4)抽象图形用户接口包(javax.swing):实现了不同平台的计算机的图形用户接口部件,包括窗口、菜单、滚动条、对话框等,使得 Java可以移植到不同的平台。 接口解决了Java 不支持多重继承的问题,可以通过实现多个接口达到与多重继承相同的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_62982856

感谢你的支持,我会继续加油的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值