非零基础自学Golang
文章目录
- 非零基础自学Golang
- 第14章 反射
- 14.1 反射定义
- 14.1.1 反射的定义
- 14.1.2 与其他语言的区别
第14章 反射
我们常用的一个打印函数fmt.Println()可以打印任何类型的数据,但是它本身是怎么实现的呢?
解读源码可以看到,fmt包使用了一个叫reflect的反射标准库,也就是基于Go语言反射的特性写出来的
反射的强大之处就在于它非常灵活,通常用于做一些通用框架代码,而不需要理解业务,因此具有快速处理不同业务的功能。但它强大的同时也带来了很多弊端,比如代码可读性和可维护性变差,性能也大打折扣。
因此,是否使用反射需要进行利弊权衡后决定,并不是所有的程序都适合使用反射。
14.1 反射定义
14.1.1 反射的定义
Go语言提供了一种机制:在运行时更新变量和检查它们的值、调用它们的方法和它们支持的内在操作,但是在编译时并不知道这些变量的具体类型。
这种机制被称为反射。Go语言在reflect包中实现了反射,通过reflect.TypeOf(),reflect.ValueOf()分别从类型、值的角度来描述一个Go对象。
反射并不是一个新概念,Go语言反射与其他语言有一定的差异,我们先来了解一下其他语言中的反射。
14.1.2 与其他语言的区别
Java的反射机制是其标志性的特征之一,正是这种语言本身支持的强大的机制,使很多流行的框架有了用武之地。
在运行状态中,Java对于任何的类,都能够确认这个类的所有方法和属性;对于任何一个对象,都能调用它的任意方法和属性。
这种动态获取或者调用的方式就是Java的反射机制。
在Java中,通过反射机制在运行时能够做到:
- 确认对象的类。
- 确认类的所有成员变量和方法。
- 动态调用任意一个对象的方法。
下面举一个例子,看在Java中如何通过反射获取一个Class对象。
[ 动手写 14.1.1]
package Java20221205.test;
/**
* ClassName: Ref
* date: 2022/12/5 19:54
*
* @author DingJiaxiong
*/
public class Ref {
public static void main(String[] args) {
// 1. 通过对象调用getClass() 方法来获取, 通常应用在比如你传过来一个Object 类型的对象,而我不知道你具体是什么类 的情况
Student stu1 = new Student();
Class stuClass = stu1.getClass();
// 2. 直接通过“ 类名.class” 的方式得到, 该方法最为安全可靠, 程序性能更高
// 这也说明Java 中任何一个类都有一个 隐含的静态成员变量 class
Class stuClass2 = Student.class;
// 3. 通过Class 对象的forName() 静态方法来获取, 用得最多, 但可能抛出ClassNotFound Exception 异常
try {
Class stuClass3 = Class.forName("com.test.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Java可以通过三种方式反射获得一个Class对象,分别是
- 通过对象调用getClass()方法
- 通过类名.class
- 通过Class对象的forName()静态方法来获取。
在Go语言中,只能使用如上所示的第一种方法来反射获取运行状态的对象的值或方法,最重要的是,Go语言不支持通过对字符串解析,从而反射出对应的类型结构,这点与Java反射有着很大的区别。
我们再来看一个Go反射的例子:
[ 动手写 14.1.2 ]
package main
import (
"fmt"
"reflect"
)
func main() {
var a interface{} = "我是字符串"
typeOfa := reflect.TypeOf(a)
fmt.Println("变量a 的类型为: " + typeOfa.Name())
valueOfa := reflect.ValueOf(a)
if typeOfa.Kind() == reflect.String {
fmt.Println("变量a 的值为: " + valueOfa.String())
}
}
动手写14.1.2中,使用reflect.TypeOf()获取了变量a的值类型,使用reflect.ValueOf()获取了变量a的原始值,这两个函数非常重要,后面会详细介绍它们的使用,运行结果如下:
【提示】
Go语言不支持解析string然后执行。Go语言的反射机制只能作用于已经存在的对象上。