Java基础查缺补漏03(附赠哈夫曼树&哈夫曼编码)

继续我的复习刷题

构造器显式调用父类构造方法的规则

题目:

以下程序的输出结果为

class Base{
    public Base(String s){
        System.out.print("B");
    }
}
public class Derived extends Base{
    public Derived (String s) {
        System.out.print("D");
    }
    public static void main(String[] args){
        new Derived("C");
    }
}

A. BD
B. DB
C. C
D. 编译错误

正确答案: D 你的答案: A (错误)


这道题其实没什么特别的,就是之前对这个规则不熟悉:

在子类的构造方法中,必须调用父类的构造方法,如果没有显示地调用,编译器会在第一行添加一个父类的无参构造方法,但是如果父类重载了构造方法导致没有无参的构造方法,子类就必须在构造方法中显示地调用父类的构造方法,否则就会报错。

IO流分为节点流和处理流

题目:

下列流当中,属于处理流的是:()

A. FileInputStream
B. InputStream
C. DataInputStream
D. BufferedInputStream

正确答案: C D 你的答案: A C (错误)


这道题选错是不知道节点流和处理流是什么。原来IO流可以这样分类:(来自牛客网用户:无情的AC机器)

按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。

  • 节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.
  • 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

JAVA常用的节点流:
+ 文 件 FileInputStreamFileOutputStreanFileReaderFileWriter。文件进行处理的节点流。
+ 字符串 StringReaderStringWriter。对字符串进行处理的节点流。
+ 数 组:ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter。对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
+ 管 道:PipedInputStreamPipedOutputStreamPipedReaderPipedWriter。对管道进行处理的节点流。

常用处理流(关闭处理流使用关闭里面的节点流)

  • 缓冲流:BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter。增加缓冲功能,避免频繁读写硬盘。
  • 转换流:InputStreamReaderOutputStreamReader。实现字节流和字符流之间的转换。
  • 数据流:DataInputStreamDataOutputStream等。提供将基础数据类型写入到文件中,或者读取出来.

如何通过反射获取和设置对象私有字段的值

这个倒不是刷题刷出来的,就是整理知识点的时候对这个API有点不太熟练,这里复习一下:

Java基础查缺补漏03(附赠哈夫曼树&哈夫曼编码)

我相信这个思维导图已经概括得很详细了(这只是我复习中整理的一小部分,等我把整个java体系复习完了把整个思维导图分享出来)

下面上代码说明:

class Security{
    private int num = 10;
    private int getNum(){
        return num;
    }
}

public class TestReflect {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Security security = new Security();
        // 获取字段
        Field num = security.getClass().getDeclaredField("num");
        // 设置访问权限
        num.setAccessible(true);
        // 修改值
        num.set(security, 5);

        Method getNum = security.getClass().getDeclaredMethod("getNum");
        getNum.setAccessible(true);
        Object invoke = getNum.invoke(security);
        System.out.println(invoke);
    }
}

这段代码中还有一个知识点:getNum方法返回的是基本类型int,但invoke只能返回一个Object对象,它会自动把int类型装箱,即变成Integer类型返回,因此是可以输出的。

哈夫曼树&哈夫曼编码

哈哈越扯越偏了,这里顺便放一个数据结构的知识点上来,这个不太想单独写一篇博客。

哈夫曼树,就是使带权外部路径长度最小(课本上这样说的)的一种二叉树。

至于如何计算这个带权外部路径:

  1. 所有外部节点(叶子节点)带有一个权值
  2. 每个外部节点乘以其到根节点的路径长之和,就是该树的带权外部路径长度。

如何构造一个哈夫曼树:

  1. 将所有外部节点按权值大小从小到大排序,组成一个有序链表
  2. 取出前两个节点,将它们的值相加,得到一个新的权值,用它构造一个新的节点,同时是这两个节点的父节点,然后把这个新的节点按值的大小插入链表中
  3. 重复第二步,直到组成一棵树

我不太想画图,累了0v0(复习哪有时间认真写博客)

注意哈夫曼树是一种满二叉树(满二叉树这个定义有争议,我这里的定义就是除了叶子节点所有的节点的度都为2),即不包含度为1的节点。

然后哈夫曼树有一个应用就是哈夫曼编码,左边的出度取0,右边的出度取1。从根节点到叶子节点路径上的0、1值组成的就是哈夫曼编码。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e5%9f%ba%e7%a1%80%e6%9f%a5%e7%bc%ba%e8%a1%a5%e6%bc%8f03%ef%bc%88%e9%99%84%e8%b5%a0%e5%93%88%e5%a4%ab%e6%9b%bc%e6%a0%91%e5%93%88%e5%a4%ab%e6%9b%bc%e7%bc%96%e7%a0%81%ef%bc%89/

发表评论

电子邮件地址不会被公开。