乐闻世界logo
搜索文章和话题

面试题手册

Golang 中数组和切片有什么区别?

在Go语言中,数组和切片是两种不同的数据结构,主要有以下几点区别:大小固定性:数组:其长度在声明时就必须指定,而且一旦定义,数组的大小就不能改变。切片:是基于数组的一种更灵活的数据结构,其长度是动态的,可以根据需要增长或缩减。声明方式:数组:声明时需要指定元素的数量,例如 var a [5]int 表示一个包含5个整数的数组。切片:不需要在声明时指定数量,例如 var s []int 是一个整数切片,初始时是空的。内存分配:数组:作为值类型,数组在内存中的分配是连续的,且其大小在编译时就确定了。切片:虽然基于数组,但它包括一个指向数组的指针、切片的长度和容量。这使得切片可以根据需要动态地扩展或缩减其容量。性能影响:数组:因为是值类型,所以在作为参数传递给函数时,会进行整个数组的复制,可能会影响性能,尤其是对于大数组。切片:作为引用类型,传递时只会复制切片的描述符(指针、长度、容量),而不是底层数组的数据,所以性能更优。用途:数组:适用于存储固定数量的同类型元素。切片:更加灵活,适用于不确定数量的情况,是Go中最常用的数据结构之一,尤其是在需要动态增减元素的场景。总结来说,数组是一种基本但固定长度的数据结构,而切片提供了更多灵活性和高性能的操作,适用于更广泛的场景。
阅读 0·2月7日 11:00

Golang 如何创建和使用函数闭包?

在Go语言中,闭包是一种特殊类型的匿名函数,它可以捕获其定义作用域中的变量。这意味着函数可以访问并操作其外部函数中定义的变量,即使外部函数已经执行完毕。创建和使用闭包的基本步骤如下:1. 定义闭包闭包通常在一个函数内部定义,并返回。这个内部函数会访问并操作外部函数的变量。package mainimport "fmt"func outerFunction() func() int { var x int = 0 return func() int { x += 1 return x }}在这个例子中,outerFunction 返回了一个匿名函数,这个匿名函数每次被调用时会增加变量 x 的值并返回。x 是定义在 outerFunction 内部的,所以这个匿名函数就形成了一个闭包,因为它“捕获”了 x 的当前状态和后续状态。2. 使用闭包一旦定义了闭包,你可以像使用普通函数那样使用闭包,但它会记住和操作其闭包变量的状态。package mainimport "fmt"func main() { increment := outerFunction() // 创建闭包 fmt.Println(increment()) // 输出: 1 fmt.Println(increment()) // 输出: 2 fmt.Println(increment()) // 输出: 3}每次调用 increment 时,它都会增加在 outerFunction 中定义的 x 的值。尽管每次调用 outerFunction 都会创建新的 x,这里 increment 使用的是同一个 x。总结闭包允许你将状态与功能绑定在一起,非常适合创建私有变量和构造函数工厂等场景。在Go中,由于闭包的性质,它们常被用于创建生成器、迭代器等结构。
阅读 0·2月7日 11:00

Java中的对象是如何序列化的?

在Java中,对象序列化是指将对象的状态转换为字节序列的过程,这使得对象可以被存储或者通过网络传输。对象序列化主要通过实现 java.io.Serializable 接口来完成。这是一个标记接口,它不包含任何方法,仅用于标识类的对象可以被序列化。具体的序列化过程通常如下:实现Serializable接口: 要使Java类可序列化,类必须实现 java.io.Serializable 接口。ObjectOutputStream: 使用 ObjectOutputStream 类将对象写入流中。这个类有一个 writeObject() 方法,用于序列化指定的对象并将其输出到输出流中。序列化过程: 当通过 writeObject() 方法写入对象时,Java虚拟机(JVM)首先检查该对象是否已经被序列化过。如果没有,JVM将记录该对象的类型和状态(即其成员变量的值),然后递归地对该对象的所有引用进行相同处理。transient关键字: 如果不希望某个字段被序列化,可以使用 transient 关键字来修饰该字段。被 transient 修饰的字段在对象序列化时会被忽略。UID: 在类中声明一个名为 serialVersionUID 的静态常量可以用来显式定义序列化版本UID。这有助于确保序列化的兼容性,即在类定义变化时仍然能够对老版本的序列化对象进行反序列化。反序列化是上述过程的逆过程,主要通过使用 ObjectInputStream 类和其 readObject() 方法来实现,将字节序列恢复为Java对象。
阅读 0·2月7日 00:13

如何在Java中创建线程?

在Java中创建线程主要有两种方式:继承Thread类:首先,定义一个继承自Thread的类。然后,在该类中覆写run()方法,将你想要在该线程中执行的代码放入run()方法中。创建这个继承了Thread类的实例,并调用实例的start()方法来启动线程。示例代码: class MyThread extends Thread { public void run(){ System.out.println("我的线程正在运行"); } } public class TestThread { public static void main(String args[]) { MyThread t = new MyThread(); t.start(); // 启动线程 } }实现Runnable接口:定义一个实现了Runnable接口的类。实现该接口的run()方法,在这个方法里放入你想在线程中运行的代码。创建该类的实例,并将它作为参数传递给Thread的构造函数来创建一个线程对象。调用线程对象的start()方法来启动线程。示例代码: class MyRunnable implements Runnable { public void run(){ System.out.println("通过Runnable接口创建线程"); } } public class TestRunnable { public static void main(String args[]) { MyRunnable myRunnable = new MyRunnable(); Thread t = new Thread(myRunnable); t.start(); // 启动线程 } }这两种方法本质上都是构建一个可以独立执行的代码块,并通过start()方法来让Java虚拟机调用这个代码块的run()方法。使用Runnable接口的方式更加灵活,因为Java不支持多重继承,所以当你的类已经继承了其他类时,只能选用实现Runnable接口的方式来创建线程。
阅读 0·2月7日 00:13