day21-反射枚举

news2024/11/25 13:31:44

day21_反射&枚举

课程目标

1. 【理解】类加载器
2. 【理解】什么是反射
3. 【掌握】获取Class对象的三种方式
4. 【掌握】反射获取构造方法并创建对象
5. 【掌握】反射获取成员变量并使用
6. 【掌握】反射获取成员方法并使用
7. 【掌握】反射综合案例
8. 【理解】枚举

类加载器

类加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的 【加载】,【连接】,【初始化】 这三个步骤来对类进行初始化。

如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化

一个类的生命周期包括了 “加载”、“验证”、“准备”、“解析”、“初始化”、“使用”、“卸载” 这七个阶段,
一般我们只研究前五个阶段,这五个阶段又可以分为 “加载”、“连接、验证,解析” 、 “初始化”

类的加载

类的加载就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象

用于加载二进制数据,类的加载主要做三件事情:

  • 找到类文件(通过类的全限定名来获取定义此类的二进制字节流)

    首先会根据各种途径(比如网络下载、数据库提取、从jar,zip中读取等)获取类的二进制数据

  • 放入方法区(将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构)

    把获取到的二进制数据读入内存,存储在运行时数据区的方法区,
    这些二进制数据所代表的存储结构会被转化为方法区中运行时的数据结构

  • 开个入口(生成一个代表此类的java.lang.Class对象,作为访问方法区这些数据结构的入口)

    在方法区中创建相应的class对象(这里的class对象与平时所说的对象是不一样的,
    当使用new创建实例对象时,就会通过class对象在堆中创建实例对象)用来封装保存在方法区内的数据结构

类的连接

  • 【验证阶段】:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致

    文件格式验证:验证字节流是否符合class文件的规范,确保输入的字节流能正确解析并存储到方法区

    元数据验证:对字节码描述的信息进行语义分析,保证其描述的信息符合规范要求。
    字节码验证:这个阶段是比较复杂的,通过数据流和控制流分析,对类的方法体进行校验,确保程序的合法性 符号引用验证:这里的符号引用不单单指类的,也包括方法。
    ​ 发生在符号引用转为直接引用的时候,也就是解析阶段,
    ​ 对常量池中各种符号引用的信息进行匹配性校验,确保解析动作正确执行

  • 【准备阶段】:负责为类的类变量分配内存,并设置默认初始化值

    需要注意的是:

    * 静态变量只会给默认值。
        * 例:public static int value = 123; // 此时赋给value的值是0,不是123。
    
    * 静态常量(static final修饰的)则会直接赋值。
        * 例:public static final int value = 123; // 此时赋给value的值是123。
    
    
  • 【解析阶段】:将类的二进制数据中的符号引用替换为直接引用

类的初始化

类的初始化的主要工作是为静态变量赋程序设定的初值。

类的初始化步骤

  • 假如类还未被加载和连接,则程序先加载并连接该类
  • 假如该类的直接父类还未被初始化,则先初始化其直接父类
  • 假如类中有初始化语句,则系统依次执行这些初始化语句
  • 注意:在执行第2个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3

类的初始化时机

  • 创建类的实例
  • 调用类的类方法
  • 访问类或者接口的类变量,或者为该类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

类加载器

类加载器的作用

负责将.class文件加载到内存中,并为之生成对应的 java.lang.Class 对象。虽然我们不用过分关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行!

简单来说:类加载器的作用,就是把class文件装进虚拟机

类加载机制

  • 全盘负责

    就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入

  • 父类委托

    就是当一个类加载器负责加载某个Class时,先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类

  • 缓存机制

    保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区

双亲委派机制

这样做的好处是什么?

1.避免重复加载。当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
2.为了安全。避免核心类,比如String被替换。

Java中的内置类加载器

当JVM启动的时候,Java缺省开始使用如下三种类加载器

  • Bootstrap ClassLoader

    引导类加载器(根类加载器), 用来加载 Java 的核心库,是用原生代码来实现的,
    比如:System.String等,jre的lib下rt.jar文件中

  • Platform ClassLoader

    平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类

  • System ClassLoader

    它也被称为应用程序类加载器(系统类加载器)(ApplicationClassLoader) ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类

    负责在jvm启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar和类路径

  • UserClass Loader

    自定义类加载器

如果核心包中没有项目所需要的jar,还有一个扩展加载器:将扩展的jar进行加载

类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap

反射

反射概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;对于这种动态的获取信息以及动态调用对象的方法的功能称为:java语言的反射机制。

反射理解:
可以通你这个对象拿到字节码文件,通过子节码文件还原到类的本身(也就是说你拿到类的Class对象去使用这个类的成员方法,成员变量,构造方法)

获取Class类对象的三种方式

  • 类名.class属性
  • 对象名.getClass()方法
  • Class.forName(全限定类名)方法
public class Person {
	//私有成员变量	
	private String name;
    
    //默认成员变量
	int age;
    
    //公有成员变量
	public String address;

    //公有无参构造方法
	public Person() {
	}
    
	//私有的有参构造方法 1个参数
	private Person(String name) {
		this.name = name;
	}
    
	//默认的有参构造方法 2个参数
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
    
	//公有的有参构造方法 3个参数
	public Person(String name, int age, String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}
    
	//公有的无参无返回值方法
	public void show() {
		System.out.println("show");
	}
    
	//公有的有参无返回值方法
	public void method(String s) {
		System.out.println("method " + s);
	}
    
	//公有的有参有返回值方法
	public String getString(String s, int i) {
		return s + "---" + i;
	}
    
	//私有的无参无返回值方法
	private void function() {
		System.out.println("function");
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", address=" + address
				+ "]";
	}
}

/*
 * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
 * 
 * Person p = new Person();
 * p.使用
 * 
 * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
 * Class类:
 * 		成员变量	Field
 * 		构造方法	Constructor
 * 		成员方法	Method
 * 
 * 获取class文件对象的方式:
 * 		A:Object类的getClass()方法
 * 		B:数据类型的静态属性class
 * 		C:Class类中的静态方法

 * 		public static Class forName(String className)
 * 
 * 一般我们到底使用谁呢?
 * 		A:自己玩	任选一种,第二种比较方便
 * 		B:开发	第三种
 * 			为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中,灵活性较高。
 */
public class ReflectDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		// 方式1
		Person p = new Person();
		Class c = p.getClass();

		Person p2 = new Person();
		Class c2 = p2.getClass();

		System.out.println(p == p2);// false
		System.out.println(c == c2);// true

		// 方式2
		Class c3 = Person.class;
		System.out.println(c == c3);

		// 方式3
		// ClassNotFoundException
		Class c4 = Class.forName("cn.yanqi.Person");
		System.out.println(c == c4);
	}
}


获取构造方法

方法名说明
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象

3.3.2 用于创建对象的方法

方法名说明
T newInstance(Object…initargs)根据指定的构造方法创建对象

3.3.3 代码实现

	//获取无构造方法
	public static void main(String[] args) throws Exception{
		//获取字节码文件对象
		Class c = Class.forName("cn.yanqi.fanse_14.Person");

		/*
		Constructor[] c1 = c.getConstructors();//获取public修饰的构造
		for(Constructor cc : c1 ){
			System.out.println(cc);
		}
		*/

		/*
		Constructor[] c2 = c.getDeclaredConstructors();//获取所有的构造,包括私有
		for(Constructor cc : c2 ){
			System.out.println(cc);
		}
		*/
		
		//获取单个构造方法
		Constructor con = c.getConstructor();
		//相当于 Person p = new Person();
		Object obj = con.newInstance();
		System.out.println(obj);
	}

获取带参public构造方法

//获取带参构造方法
public static void main(String[] args) throws Exception {
		//获取字节码文件对象
		Class c = Class.forName("cn.yanqi.fanse_14.Person");
		
		//获取单个构造方法
		Constructor con = c.getConstructor(String.class , int.class , String.class);	
		System.out.println(con);
		
		Object obj = con.newInstance("江一燕", 33 ,"上海");
		System.out.println(obj);
}

获取私带参构造方法

public static void main(String[] args) throws Exception {
		
		Class c = Class.forName("cn.yanqi.fanse_14.Person");
		//获取私有构造方法对象
		Constructor con = c.getDeclaredConstructor(String.class);//获取所有(不管是什么修饰)
		
		con.setAccessible(true);//暴力访问 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
		Object obj = con.newInstance("yanqi");

		System.out.println(obj);
}

获取成员变量

3.4.1 Class类获取成员变量对象的方法

方法名说明
Field[] getFields()返回所有公共成员变量对象的数组
Field[] getDeclaredFields()返回所有成员变量对象的数组
Field getField(String name)返回单个公共成员变量对象
Field getDeclaredField(String name)返回单个成员变量对象
void set(Object obj,Object value)给obj对象的成员变量赋值为value

3.4.2 代码演示

public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.yanqi.fanse_14.Person");

		// 获取所有的成员变量
		//Field[] fields = c.getFields();//获取public 修饰的
		 Field[] fields = c.getDeclaredFields();//获取所有成员变量(不管是什么修饰)
		 for (Field field : fields) {
			 System.out.println(field);
		 }

		// 通过无参构造方法创建对象
		Constructor con = c.getConstructor();
		Object obj = con.newInstance();
		System.out.println(obj);

		// 获取单个的成员变量
		// 获取address并对其赋值
		Field addressField = c.getField("address");
		// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
		addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
		System.out.println(obj);

		// 获取name并对其赋值
		// NoSuchFieldException
		Field nameField = c.getDeclaredField("name");
		// IllegalAccessException
		nameField.setAccessible(true);//可以直接访问到私有的
		nameField.set(obj, "江一燕");
		System.out.println(obj);

		// 获取age并对其赋值
		Field ageField = c.getDeclaredField("age");
		ageField.setAccessible(true);
		ageField.set(obj, 33);
		System.out.println(obj);
	}	

获取成员方法

3.5.1 Class类获取成员方法对象的方法

方法名说明
Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>… parameterTypes)返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象
Object invoke(Object obj,Object… args)调用obj对象的成员方法,参数是args,返回值是Object类型
public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.yanqi.fanse_14.Person");

		// 获取所有的方法
		// Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
		 Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
		 for (Method method : methods) {
			 System.out.println(method);
		 }

		Constructor con = c.getConstructor();
		Object obj = con.newInstance();

		// 获取单个方法并使用
		// public void show()
		// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
		Method m1 = c.getMethod("show");
		// public Object invoke(Object obj,Object... args)
		// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
		m1.invoke(obj); // 调用obj对象的m1方法  相当于p.show()方法
		System.out.println("----------");
		
		// public void method(String s)
		Method m2 = c.getMethod("method", String.class);
		m2.invoke(obj, "hello");
		System.out.println("----------");

		// public String getString(String s, int i)
		Method m3 = c.getMethod("getString", String.class, int.class);
		Object objString = m3.invoke(obj, "hello", 100);
		System.out.println(objString);
		System.out.println("----------");

		// private void function()
		Method m4 = c.getDeclaredMethod("function");
		m4.setAccessible(true);
		m4.invoke(obj);
	}

案例-通过反射获取配置文件内容

image-20211115190651225
public class Student {
    public  void show(){
        System.out.println("学生学习了");
    }
}

配置文件内容

ClassName=cn.yanqi_07.Student
MethodName=show
public static void main(String[] args) throws Exception {

    //    Student s = new Student();
    //    s.show();
    //获取ApplicationConfig.properties配置文件,字符流缓冲
    BufferedReader br = new BufferedReader(new FileReader("ApplicationConfig.properties"));
    
    //创建properties属性集合对象
    Properties pro = new Properties();
    
    //加载配置文件
    pro.load(br);

    //关闭流
    br.close();

    //获取配置文件中的数据
    String className = pro.getProperty("ClassName");
    String methodName = pro.getProperty("MethodName");

    //获取字节码class对象
    Class c = Class.forName(className);//cn.properties.com.Student

    //创建反射实例
    Constructor con = c.getConstructor();
    Object o = con.newInstance();

    //调用方法
    Method method = c.getMethod(methodName);//show
    method.invoke(o);
}

枚举

枚举的概述

是指将变量的值一一的列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。

枚举格式

public enum 枚举类名{

​ 枚举项1,枚举项2,枚举项3,枚举4。。。;

}

第一版

public enum Direction {
	/*
	 * 通过JDK5提供的枚举来做枚举类
	 */
	FRONT, BEHIND, LEFT, RIGHT;

}
public class DirectionDemo {

	public static void main(String[] args) {
		Direction d = Direction.FRONT;
		System.out.println(d); // FRONT
	}
}

第二版

public enum Direction2 {
	
	FRONT("前"), BEHIND("后"), LEFT("左"), RIGHT("右");

	private String name;

	private Direction2(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

	public static void main(String[] args) {
		
		Direction2 d2 = Direction2.FRONT;
		System.out.println(d2);//FRONT
		System.out.println(d2.getName());//前
		d2 = Direction2.RIGHT;
		System.out.println(d2);//RIGHT
		System.out.println(d2.getName());//右	
	}

第三版

public enum Direction3 {
		FRONT("前") {
			@Override
			public void show() {
				System.out.println("前");
			}
		},
		BEHIND("后") {
			@Override
			public void show() {
				System.out.println("后");
			}
		},
		LEFT("左") {
			@Override
			public void show() {
				System.out.println("左");
			}
		},
		RIGHT("右") {
			@Override
			public void show() {
				System.out.println("右");
			}
		};

		private String name;

		private Direction3(String name) {
			this.name = name;
		}

		public String getName() {
			return name;
		}

		public abstract void show();
}

public static void main(String[] args) {
		
		Direction3 d3 = Direction3.FRONT;
		System.out.println(d3);
		System.out.println(d3.getName());
		d3.show();
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Ubuntu上安装 Hadoop 3详细过程(验证+填坑总结)

在Ubuntu上安装 Hadoop 3 前提条件&#xff1a; Python 推荐3.8JDK 推荐1.8 解压安装 sudo tar -zxvf hadoop-3.3.0.tar.gz -C /usr/local cd /usr/local sudo mv hadoop-3.3.0 hadoop sudo chown -R hadoop ./hadoop 配置环境变量 vim ~/.bashrc # hadoop export…

5、数组的创建和操作

目录 一、创建空数组、行向量、列向量 二、访问数组 三、 子数组的赋值&#xff08;Assign&#xff09; 四、其他创建数组的方式 1. 通过冒号创建一维数组 2.通过logspace函数创建一维数组 3.通过linspace函数创建一维数组 在MATLAB中一般使用方括号“[ ]”、逗号“,”、…

Python FastAPI 框架入门(一)【用于后端API快捷开发】

FastAPI 框架&#xff0c;高性能&#xff0c;易于学习&#xff0c;高效编码&#xff0c;生产可用 官方中文文档&#xff1a;FastAPI 框架中文文档 官方介绍&#xff1a; FastAPI 是一个用于构建 API 的现代、快速&#xff08;高性能&#xff09;的 web 框架&#xff0c;使用 Py…

【GD32F427开发板试用】-05-GD32F427移植Coremark

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;申小林 如何在GD32F427开发板上移植CoreMARK? 1 下载CoreMARK源码 CoreMark开源的代码可以在Gitbub上自己做下载。 下载地址&#xff1a;ht…

CSS设置元素字体、降级使用字体、引入外部字体

设置元素字体 通过font-family属性&#xff0c;可以设置元素里面的字体样式。 font-family 可以把设置多个字体名称。 降级使用字体 几乎所有浏览器都有支持几种通用字体。比如: monospace&#xff0c;serif和sans-serif&#xff0c;当字体不可用&#xff0c;浏览器可以 “…

通过Docker启动Solace,并在Spring Boot通过JMS整合Solace

1 简介 Solace是一个强大的实时性的事件驱动消息队列。本文将介绍如何在Spring中使用&#xff0c;虽然代码使用的是Spring Boot&#xff0c;但并没有使用相关starter&#xff0c;跟Spring的整合一样&#xff0c;可通用。JMS是通过的消息处理框架&#xff0c;可以深入学习一下&…

02.指针的进阶1.练习题

1.辨析 //数组指针是一种指针&#xff0c;指向数组的指针 //数组指针是指向数组地址的指针 //回调函数是调用函数指针指向函数 EG1:杨氏矩阵 有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c;请编写程序在这样的矩阵中…

微服务间通讯负载均衡以及日志

2.通信 HTTP ResthttpJSONRPC远程过程调用二进制 1.使用 RestTemplate RestTemplate restTemplate new RestTemplate(); String forObject restTemplate.getForObject("http://localhot:8888/user", String.class);其负载均衡有问题其无法实现健康检查 2.使用Ri…

新年新气象,跨境电商助推出口再创新高

受疫情等多方面影响&#xff0c;2022年纯棉纱进口量及产量均出现一定幅度地下滑。由于库存增加&#xff0c;消费量下降&#xff0c;供需矛盾也不断加剧。 新年新气象&#xff0c;2023年据预计纯棉纱产量将小幅回升&#xff0c;初步预计将达到535万吨&#xff0c;同比增加5.6%。…

Allegro如何快速打开和关闭层面操作指导

Allegro如何快速打开和关闭层面操作指导 在做PCB设计的时候,打开和关闭某个层面是非常频繁的操作,尤其是丝印等等层面。 Allgeo升级到了172版本的时候,可以将常用的层面添加到Visibility菜单里,就不需要频繁打开颜色管理器打卡和关闭层面了,如下图 具体操作如下 打开颜色…

归纳一下软件测试中「安全测试工具」

大家好啊&#xff0c;我是大田。今天归纳一下安全测试工具&#xff0c;分别用这些工具做哪些工作。自动化测试人员、功能测试人员平常可能用的不多&#xff0c;但是面试时也需要准备&#xff0c;需要知道安全测试工具有什么&#xff0c;还要关注现在有哪些漏洞。本篇先归纳整理…

vue3学习笔记之样式穿透(:deep)及CSS 新特性(:soltted、:gloabl、v-bind、mouldCSS)

文章目录1. scoped的原理2. :deep()3. :slotted()4. :global()5. 动态css&#xff08;v-bind&#xff09;6. css module1. scoped的原理 vue中的 scoped 通过在DOM结构以及css样式上加唯一不重复的标记:data-v-hash的方式&#xff0c;以保证唯一&#xff08;而这个工作是由过P…

如何使用极狐GitLab 机器人大幅提升研发效率

本文来自&#xff1a; 黄松 极狐GitLab 后端工程师 研发效率对互联网/科技类公司来说至关重要&#xff0c;效率高意味着你能用更低的人力、时间成本在市场试错&#xff0c;成功的概率也会更大。 而说到研发效率的常见阻碍&#xff0c;主要有两点&#xff1a; 1. 研发流程中需要…

基础二分查找总结

前言 由于我在学习二分查找的过程中处于会了忘&#xff0c;忘了复习的状态&#xff0c;因此总结一套适合自己记忆的模板。建议先看参考资料[1,2,3]^{[1,2,3]}[1,2,3]&#xff0c;理解二分查找各种细节的由来。 二分查找又死循环了&#xff1f;【基础算法精讲 04】手把手带你撕出…

9656教程总结

9656 世界机器人大会青少年电子信息智能创新大赛官网少儿编程办学经验介绍机器人体验展馆体系课程知乎加盟介绍 知识点汇总 年龄 4-6岁 韩纳机器人主题体验馆 赛事 WRC世界机器人大赛, NOC全国中小学信息技术创新和实践大赛 5岁前:乐高积木,孩子年龄小只需对科特、编程…

事关网站数据安全,你真的了解https与SSL证书之间的关系吗?

虽然根据网上的建站教程&#xff0c;大多数站长都知道要给域名添加一个SSL证书&#xff0c;以此来开启https进而可以获得更好的用户体验以及提高网站的安全性。但是SSL证书为什么能使得网站https&#xff1f;你真的去细究过两者之间的关系吗&#xff1f;本文就来说说https与SSL…

python模拟三颗恒星的运动

文章目录随机三体三星问题随机三体 目前来说我们并不关心真实的物理对象&#xff0c;而只想看一下三个随机的点放在三个随机的位置&#xff0c;赋予三个随机的速度&#xff0c;那么这三个点会怎么走。所以其初始化过程为 import numpy as np m,x,y,u,v [np.random.rand(3) f…

【java入门系列四】java基础-数组

学习记录&#x1f914;数组引出动态初始化数组内的数据会自动转换类型注意事项数组赋值机制数组拷贝数组扩容append&#xff1f;多维数组trick生成随机数Math.random()讨论总结谢谢点赞交流&#xff01;(❁◡❁)更多代码&#xff1a; Gitee主页&#xff1a;https://gitee.com/G…

如何进行复盘

复盘定义 复盘&#xff0c;原本是围棋术语&#xff0c;指下完一盘棋后&#xff0c;双方棋手把对弈过程重新摆一遍&#xff0c;看哪里下得好&#xff0c;哪里下得不好&#xff0c;哪些关键节点有不同甚至更好的下法&#xff0c;以检查对局中招法的优劣与得失&#xff0c;并从中…

深入理解可变参数列表

目录 1.前言 2.基本使用方法 1.引入 2.相关宏介绍 3.原理剖析 1.传参 2.va_list 3.va_start() 4.va_arg() 5.va_end() 4.注意事项 5.总结 1.前言 在C语言中&#xff0c;对于一般的函数而言&#xff0c;参数列表都是固定的&#xff0c;而且各个参数之间用逗号进行分开。而除…