从字节码文件理解 ++i 和 i++ 的区别_i++ 与 ++i 底层

news2024/11/17 10:34:57

jvm内存模型

jvm 内存模型:Java 代码是运行在 Java 虚拟机之上的,由 Java 虚拟机通过解释执行 (解释器)或编译执行 (即时编译器) 来完成,故 Java 内存模型,也就是指 Java 虚拟机的运行时内存模型。

运行时内存模型,分为线程私有共享数据区两大类,

  • 线程私有的数据区包含程序计数器、虚拟机栈、本地方法区
  • 所有线程共享的数据区包含 Java 堆、方法区,在方法区内有一个常量池

java 运行时的内存模型图,如下:

在这里插入图片描述

从图中,可知内存分为线程私有和共享两大类:

  • 线程私有区,包含以下 3 类:

    • 程序计数器,记录正在执行的虚拟机字节码的地址;

    • 虚拟机栈:方法执行的内存区,每个方法执行时会在虚拟机栈中创建栈帧;

    • 本地方法栈:虚拟机的 Native 方法执行的内存区;

  • 线程共享区,包含以下 2 类

    • Java 堆:对象分配内存的区域;
    • 方法区:存放类信息、常量、静态变量、编译器编译后的代码等数据;
    • 常量池:存放编译器生成的各种字面量和符号引用,是方法区的一部分。

提到的 Java 栈,一般而言是指图中的虚拟机栈,在代码中的方法调用过程中,往往需要从一个方法跳转到另一个方法,执行完再返回,那么在跳转之前需要在当前方法的基本信息压入栈中保存再跳转。

关于寄存器的问题对于 java 最常用的虚拟机,sun 公司提供的 hotspot 虚拟机,是基于栈的虚拟机; 而对于 android 的虚拟机,则采用 google 提供的 dalvik,art 两种虚拟机,在 android 5.0 以后便默认采用 art 虚拟机,这是基于寄存器的虚拟机。 楼主问的是 jvm(即 java vm),这是基于栈的虚拟机。那么关于虚拟机栈,这块内存的内容,我们再进一步详细分析,如下图:

在这里插入图片描述

可以看到,在虚拟机栈有一帧帧的 栈帧组成,而栈帧包含局部变量表操作栈等子项,那么线程在运行的时候,代码在运行时,是通过程序计数器不断执行下一条指令。真正指令运算等操作时通过控制操作栈的操作数入栈和出栈,将操作数在局部变量表和操作栈之间转移

自加自减运算

理解:++ 运算,表示自增1。同理,-- 运算,表示自减1,用法与++ 一致。

1、单独使用

  • 变量在单独运算的时候,变量前++和变量后++,是没有区别的。
  • 变量前++ :例如 ++a
  • 变量后++ :例如 a++
public class ArithmeticTest3 {
	public static void main(String[] args) {
		// 定义一个int类型的变量a
		int a = 3;
		//++a;
		a++;
        // 无论是变量前++还是变量后++,结果都是4
		System.out.println(a);
	}
}

2、复合使用

  • 其他变量放在一起使用或者和输出语句放在一起使用前++后++就产生了不同。
  • 变量前++ :变量先自增1,然后再运算。
  • 变量后++ :变量先运算,然后再自增1。
public class ArithmeticTest4 {
	public static void main(String[] args) {
		// 其他变量放在一起使用
		int x = 3;
		//int y = ++x; // y的值是4,x的值是4,
		int y = x++; // y的值是3,x的值是4
		
		System.out.println(x);
		System.out.println(y);
		System.out.println("==========");
        
		// 和输出语句一起
		int z = 5;
		//System.out.println(++z);// 输出结果是6,z的值也是6
		System.out.println(z++);// 输出结果是5,z的值是6
		System.out.println(z);
        
	} 
}

3、++ 或 – 运算,不会改变变量的数据类型

short s1 = 10;
//方式1:
//编译不通过
//s1 = s1 + 1;//short 运算时转换为int,返回值需要int接受

s1 = (short)(s1 + 1); 
System.out.println(s1);

//方式2:
s1++;
System.out.println(s1);

//结论:++ 或 -- 运算,不会改变变量的数据类型!

从字节码分析

获取字节码方式:

  1. idea插件 jclasslib Bytecode Viewer

  2. 那么从反编译 javap -v xx.class 文件之后,可以看到一下指令

常用指令:

iconst_1	将 int 型 1 推送至栈顶
istore_1	将栈顶 int 型数值存入第二个本地变量   将操作栈数弹出,到局部变量表
iload_1		将第二个 int 型本地变量推送至栈顶    	局部变量表压入操作栈
inc 1 by 1 这是一个双参数指令,主要的功能是将局部变量表中索引为1的值自增一个常量值
iadd	将栈顶两 int 型数值相加并将结果压入栈顶

设计概念:

局部变量表:实例方法局部变量表第一个位置(下标为0)总是保存一个this引用

操作栈:进行表达式运算 如 + - * /

字节码分析

int i = 0;

i = i++;
i= ++i;

字节码解读:

 0 iconst_0   //将 int 型 0 推送至栈顶
 1 istore_1   //将栈顶 int 型数值存入第二个本地变量
 /*  0-1行解释
  i = 1
  局部变量表[this,0]
 */
 
 2 iload_1  
 3 iinc 1 by 1
 6 istore_1
/* 2-6解释 : i = i++;
	
    iload_1		:从局部变量表中第二个值(0)到操作栈中
    iinc 1 by 1	:变量i直接在局部变量表的slot上进行运算,并不影响操作数栈已经存在的值,此时局部变量表中i=1
    istore		:将此时操作栈顶的值(0)弹出,存入局部变量表i中,并将刚刚iinc自增的值覆盖掉 i =0
*/	
 
 7 iinc 1 by 1
10 iload_1
11 istore_1
/* 7-22行解释: i= ++i;
    innc:代表了局部变量表中的变量进行自增操作,此时局部变量表中i=1
    iload:从局部变量表中加载数字(1)到操作栈中
    istore:将此时操作栈顶的值(1)弹出,存入局部变量表中,并将局部变量表中值覆盖掉
*/


12 return

++i 是先在自己的局部变量表中自增了之后,再将局部变量的值入操作数栈并再返回。所以为 1。

i++ 是,先入了操作数栈,栈中为 0,而局部变量表 i 自增为 1,接下里栈中 0 出栈赋值给了 i,所以为 0。

案例分析

第一题

int i = 1;
i = ++i + i++;
System.out.println(i);

思考一下,再看分析过程

 0: iconst_1  //将常量数字1入栈
 1: istore_1 //出栈赋值给局部变量表i=1
 
 // ++i
 2: iinc 1 by 1 // 局部变量表i,自增加1 等于2
 5: iload_1 // 2入栈
 
 // i++
 6: iload_1 //2再次入栈
 7: iinc 1 by 1  // 局部变量表i自增1,等于3
 
 //将栈顶两 int 型数值相加并将结果压入栈顶
10: iadd // 操作数栈中的2+2相加等于4
    
// i =   2 + 2
11: istore_1 //出栈,替换局部变量表i的3为4。

所以结果为 4。

第二题

int i = 1;
i = i++ + ++i + i++ + ++i;
System.out.println(i);
0: iconst_1 	数值1入栈
1: istore_1 	数值1出栈赋值给i
2: iload_1 		i(1)入操作数栈
3: iinc 1, 1 	i在局部变量表自增1,此时i=2
6: iinc 1, 1 	i在局部变量表自增1,此时i=3
9: iload_1 		i继续入栈,第二次为3
10: iadd 		相加,与第一次栈中1和第二次的3相加为4,此时栈中为只有一个值且4
11: iload_1 	又把局部变量表中的i=3入栈
12: iinc 1, 1  	局部变量表中i为3自增1,变为了4
15: iadd 		4+3等于7
16: iinc 1, 1 	局部变量表中i为4自增1,变为了5
19: iload_1 	i=5入操作数栈
20: iadd 		与原本操作数栈中的7相加,等于12
21: istore_1 	出栈返回给局部变量表中的i,即此时i从5变为了12

所以结果为 12

总结

以上就是 i++ 和 ++i 的底层分析,终极区别是,是否先入栈再自增,还是先自增再入栈。

附录 字节码指令

字节码助记符指令含义
0x00nopNone
0x01aconst_null将 null 推送至栈顶
0x02iconst_m1将 int 型 - 1 推送至栈顶
0x03iconst_0将 int 型 0 推送至栈顶
0x04iconst_1将 int 型 1 推送至栈顶
0x05iconst_2将 int 型 2 推送至栈顶
0x06iconst_3将 int 型 3 推送至栈顶
0x07iconst_4将 int 型 4 推送至栈顶
0x08iconst_5将 int 型 5 推送至栈顶
0x09lconst_0将 long 型 0 推送至栈顶
0x0alconst_1将 long 型 1 推送至栈顶
0x0bfconst_0将 float 型 0 推送至栈顶
0x0cfconst_1将 float 型 1 推送至栈顶
0x0dfconst_2将 float 型 2 推送至栈顶
0x0edconst_0将 double 型 0 推送至栈顶
0x0fdconst_1将 double 型 1 推送至栈顶
0x10bipush将单字节的常量值 (-128~127) 推送至栈顶
0x11sipush将一个短整型常量 (-32768~32767) 推送至栈顶
0x12ldc将 int,float 或 String 型常量值从常量池中推送至栈顶
0x13ldc_w将 int,float 或 String 型常量值从常量池中推送至栈顶 (宽索引)
0x14ldc2_w将 long 或 double 型常量值从常量池中推送至栈顶 (宽索引)
0x15iload将指定的 int 型本地变量推送至栈顶
0x16lload将指定的 long 型本地变量推送至栈顶
0x17fload将指定的 float 型本地变量推送至栈顶
0x18dload将指定的 double 型本地变量推送至栈顶
0x19aload将指定的引用类型本地变量推送至栈顶
0x1aiload_0将第一个 int 型本地变量推送至栈顶
0x1biload_1将第二个 int 型本地变量推送至栈顶
0x1ciload_2将第三个 int 型本地变量推送至栈顶
0x1diload_3将第四个 int 型本地变量推送至栈顶
0x1elload_0将第一个 long 型本地变量推送至栈顶
0x1flload_1将第二个 long 型本地变量推送至栈顶
0x20lload_2将第三个 long 型本地变量推送至栈顶
0x21lload_3将第四个 long 型本地变量推送至栈顶
0x22fload_0将第一个 float 型本地变量推送至栈顶
0x23fload_1将第二个 float 型本地变量推送至栈顶
0x24fload_2将第三个 float 型本地变量推送至栈顶
0x25fload_3将第四个 float 型本地变量推送至栈顶
0x26dload_0将第一个 double 型本地变量推送至栈顶
0x27dload_1将第二个 double 型本地变量推送至栈顶
0x28dload_2将第三个 double 型本地变量推送至栈顶
0x29dload_3将第四个 double 型本地变量推送至栈顶
0x2aaload_0将第一个引用类型本地变量推送至栈顶
0x2baload_1将第二个引用类型本地变量推送至栈顶
0x2caload_2将第三个引用类型本地变量推送至栈顶
0x2daload_3将第四个引用类型本地变量推送至栈顶
0x2eiaload将 int 型数组指定索引的值推送至栈顶
0x2flaload将 long 型数组指定索引的值推送至栈顶
0x30faload将 float 型数组指定索引的值推送至栈顶
0x31daload将 double 型数组指定索引的值推送至栈顶
0x32aaload将引用类型数组指定索引的值推送至栈顶
0x33baload将 boolean 或 byte 型数组指定索引的值推送至栈顶
0x34caload将 char 型数组指定索引的值推送至栈顶
0x35saload将 short 型数组指定索引的值推送至栈顶
0x36istore将栈顶 int 型数值存入指定本地变量
0x37lstore将栈顶 long 型数值存入指定本地变量
0x38fstore将栈顶 float 型数值存入指定本地变量
0x39dstore将栈顶 double 型数值存入指定本地变量
0x3aastore将栈顶引用类型数值存入指定本地变量
0x3bistore_0将栈顶 int 型数值存入第一个本地变量
0x3cistore_1将栈顶 int 型数值存入第二个本地变量
0x3distore_2将栈顶 int 型数值存入第三个本地变量
0x3eistore_3将栈顶 int 型数值存入第四个本地变量
0x3flstore_0将栈顶 long 型数值存入第一个本地变量
0x40lstore_1将栈顶 long 型数值存入第二个本地变量
0x41lstore_2将栈顶 long 型数值存入第三个本地变量
0x42lstore_3将栈顶 long 型数值存入第四个本地变量
0x43fstore_0将栈顶 float 型数值存入第一个本地变量
0x44fstore_1将栈顶 float 型数值存入第二个本地变量
0x45fstore_2将栈顶 float 型数值存入第三个本地变量
0x46fstore_3将栈顶 float 型数值存入第四个本地变量
0x47dstore_0将栈顶 double 型数值存入第一个本地变量
0x48dstore_1将栈顶 double 型数值存入第二个本地变量
0x49dstore_2将栈顶 double 型数值存入第三个本地变量
0x4adstore_3将栈顶 double 型数值存入第四个本地变量
0x4bastore_0将栈顶引用型数值存入第一个本地变量
0x4castore_1将栈顶引用型数值存入第二个本地变量
0x4dastore_2将栈顶引用型数值存入第三个本地变量
0x4eastore_3将栈顶引用型数值存入第四个本地变量
0x4fiastore将栈顶 int 型数值存入指定数组的指定索引位置
0x50lastore将栈顶 long 型数值存入指定数组的指定索引位置
0x51fastore将栈顶 float 型数值存入指定数组的指定索引位置
0x52dastore将栈顶 double 型数值存入指定数组的指定索引位置
0x53aastore将栈顶引用型数值存入指定数组的指定索引位置
0x54bastore将栈顶 boolean 或 byte 型数值存入指定数组的指定索引位置
0x55castore将栈顶 char 型数值存入指定数组的指定索引位置
0x56sastore将栈顶 short 型数值存入指定数组的指定索引位置
0x57pop将栈顶数值弹出 (数值不能是 long 或 double 类型的)
0x58pop2将栈顶的一个 (对于非 long 或 double 类型) 或两个数值 (对于非 long 或 double 的其他类型) 弹出
0x59dup复制栈顶数值并将复制值压入栈顶
0x5adup_x1复制栈顶数值并将两个复制值压入栈顶
0x5bdup_x2复制栈顶数值并将三个 (或两个) 复制值压入栈顶
0x5cdup2复制栈顶一个 (对于 long 或 double 类型) 或两个 (对于非 long 或 double 的其他类型) 数值并将复制值压入栈顶
0x5ddup2_x1dup_x1 指令的双倍版本
0x5edup2_x2dup_x2 指令的双倍版本
0x5fswap将栈顶最顶端的两个数值互换 (数值不能是 long 或 double 类型)
0x60iadd将栈顶两 int 型数值相加并将结果压入栈顶
0x61ladd将栈顶两 long 型数值相加并将结果压入栈顶
0x62fadd将栈顶两 float 型数值相加并将结果压入栈顶
0x63dadd将栈顶两 double 型数值相加并将结果压入栈顶
0x64isub将栈顶两 int 型数值相减并将结果压入栈顶
0x65lsub将栈顶两 long 型数值相减并将结果压入栈顶
0x66fsub将栈顶两 float 型数值相减并将结果压入栈顶
0x67dsub将栈顶两 double 型数值相减并将结果压入栈顶
0x68imul将栈顶两 int 型数值相乘并将结果压入栈顶
0x69lmul将栈顶两 long 型数值相乘并将结果压入栈顶
0x6afmul将栈顶两 float 型数值相乘并将结果压入栈顶
0x6bdmul将栈顶两 double 型数值相乘并将结果压入栈顶
0x6cidiv将栈顶两 int 型数值相除并将结果压入栈顶
0x6dldiv将栈顶两 long 型数值相除并将结果压入栈顶
0x6efdiv将栈顶两 float 型数值相除并将结果压入栈顶
0x6fddiv将栈顶两 double 型数值相除并将结果压入栈顶
0x70irem将栈顶两 int 型数值作取模运算并将结果压入栈顶
0x71lrem将栈顶两 long 型数值作取模运算并将结果压入栈顶
0x72frem将栈顶两 float 型数值作取模运算并将结果压入栈顶
0x73drem将栈顶两 double 型数值作取模运算并将结果压入栈顶
0x74ineg将栈顶 int 型数值取负并将结果压入栈顶
0x75lneg将栈顶 long 型数值取负并将结果压入栈顶
0x76fneg将栈顶 float 型数值取负并将结果压入栈顶
0x77dneg将栈顶 double 型数值取负并将结果压入栈顶
0x78ishl将 int 型数值左移指定位数并将结果压入栈顶
0x79lshl将 long 型数值左移指定位数并将结果压入栈顶
0x7aishr将 int 型数值右 (带符号) 移指定位数并将结果压入栈顶
0x7blshr将 long 型数值右 (带符号) 移指定位数并将结果压入栈顶
0x7ciushr将 int 型数值右 (无符号) 移指定位数并将结果压入栈顶
0x7dlushr将 long 型数值右 (无符号) 移指定位数并将结果压入栈顶
0x7eiand将栈顶两 int 型数值 “按位与” 并将结果压入栈顶
0x7fland将栈顶两 long 型数值 “按位与” 并将结果压入栈顶
0x80ior将栈顶两 int 型数值 “按位或” 并将结果压入栈顶
0x81lor将栈顶两 long 型数值 “按位或” 并将结果压入栈顶
0x82ixor将栈顶两 int 型数值 “按位异或” 并将结果压入栈顶
0x83lxor将栈顶两 long 型数值 “按位异或” 并将结果压入栈顶
0x84iinc将指定 int 型变量增加指定值 (如 i++, i–, i+=2 等) 不是操作的操作栈,是局部变量表中
0x85i2l将栈顶 int 型数值强制转换为 long 型数值并将结果压入栈顶
0x86i2f将栈顶 int 型数值强制转换为 float 型数值并将结果压入栈顶
0x87i2d将栈顶 int 型数值强制转换为 double 型数值并将结果压入栈顶
0x88l2i将栈顶 long 型数值强制转换为 int 型数值并将结果压入栈顶
0x89l2f将栈顶 long 型数值强制转换为 float 型数值并将结果压入栈顶
0x8al2d将栈顶 long 型数值强制转换为 double 型数值并将结果压入栈顶
0x8bf2i将栈顶 float 型数值强制转换为 int 型数值并将结果压入栈顶
0x8cf2l将栈顶 float 型数值强制转换为 long 型数值并将结果压入栈顶
0x8df2d将栈顶 float 型数值强制转换为 double 型数值并将结果压入栈顶
0x8ed2i将栈顶 double 型数值强制转换为 int 型数值并将结果压入栈顶
0x8fd2l将栈顶 double 型数值强制转换为 long 型数值并将结果压入栈顶
0x90d2f将栈顶 double 型数值强制转换为 float 型数值并将结果压入栈顶
0x91i2b将栈顶 int 型数值强制转换为 byte 型数值并将结果压入栈顶
0x92i2c将栈顶 int 型数值强制转换为 char 型数值并将结果压入栈顶
0x93i2s将栈顶 int 型数值强制转换为 short 型数值并将结果压入栈顶
0x94lcmp比较栈顶两 long 型数值大小, 并将结果 (1, 0 或 - 1) 压入栈顶
0x95fcmpl比较栈顶两 float 型数值大小, 并将结果 (1, 0 或 - 1) 压入栈顶; 当其中一个数值为NaN时, 将 - 1 压入栈顶
0x96fcmpg比较栈顶两 float 型数值大小, 并将结果 (1, 0 或 - 1) 压入栈顶; 当其中一个数值为NaN时, 将 1 压入栈顶
0x97dcmpl比较栈顶两 double 型数值大小, 并将结果 (1, 0 或 - 1) 压入栈顶; 当其中一个数值为NaN时, 将 - 1 压入栈顶
0x98dcmpg比较栈顶两 double 型数值大小, 并将结果 (1, 0 或 - 1) 压入栈顶; 当其中一个数值为NaN时, 将 1 压入栈顶
0x99ifeq当栈顶 int 型数值等于 0 时跳转
0x9aifne当栈顶 int 型数值不等于 0 时跳转
0x9biflt当栈顶 int 型数值小于 0 时跳转
0x9cifge当栈顶 int 型数值大于等于 0 时跳转
0x9difgt当栈顶 int 型数值大于 0 时跳转
0x9eifle当栈顶 int 型数值小于等于 0 时跳转
0x9fif_icmpeq比较栈顶两 int 型数值大小, 当结果等于 0 时跳转
0xa0if_icmpne比较栈顶两 int 型数值大小, 当结果不等于 0 时跳转
0xa1if_icmplt比较栈顶两 int 型数值大小, 当结果小于 0 时跳转
0xa2if_icmpge比较栈顶两 int 型数值大小, 当结果大于等于 0 时跳转
0xa3if_icmpgt比较栈顶两 int 型数值大小, 当结果大于 0 时跳转
0xa4if_icmple比较栈顶两 int 型数值大小, 当结果小于等于 0 时跳转
0xa5if_acmpeq比较栈顶两引用型数值, 当结果相等时跳转
0xa6if_acmpne比较栈顶两引用型数值, 当结果不相等时跳转
0xa7goto无条件跳转
0xa8jsr跳转至指定的 16 位 offset 位置, 并将 jsr 的下一条指令地址压入栈顶
0xa9ret返回至本地变量指定的 index 的指令位置 (一般与 jsr 或 jsr_w 联合使用)
0xaatableswitch用于 switch 条件跳转, case 值连续 (可变长度指令)
0xablookupswitch用于 switch 条件跳转, case 值不连续 (可变长度指令)
0xacireturn从当前方法返回 int
0xadlreturn从当前方法返回 long
0xaefreturn从当前方法返回 float
0xafdreturn从当前方法返回 double
0xb0areturn从当前方法返回对象引用
0xb1return从当前方法返回 void
0xb2getstatic获取指定类的静态域, 并将其压入栈顶
0xb3putstatic为指定类的静态域赋值
0xb4getfield获取指定类的实例域, 并将其压入栈顶
0xb5putfield为指定类的实例域赋值
0xb6invokevirtual调用实例方法
0xb7invokespecial调用超类构建方法, 实例初始化方法, 私有方法
0xb8invokestatic调用静态方法
0xb9invokeinterface调用接口方法
0xbainvokedynamic调用动态方法
0xbbnew创建一个对象, 并将其引用引用值压入栈顶
0xbcnewarray创建一个指定的原始类型 (如 int, float, char 等) 的数组, 并将其引用值压入栈顶
0xbdanewarray创建一个引用型 (如类, 接口, 数组) 的数组, 并将其引用值压入栈顶
0xbearraylength获取数组的长度值并压入栈顶
0xbfathrow将栈顶的异常抛出
0xc0checkcast检验类型转换, 检验未通过将抛出 ClassCastException
0xc1instanceof检验对象是否是指定类的实际, 如果是将 1 压入栈顶, 否则将 0 压入栈顶
0xc2monitorenter获得对象的锁, 用于同步方法或同步块
0xc3monitorexit释放对象的锁, 用于同步方法或同步块
0xc4wide扩展本地变量的宽度
0xc5multianewarray创建指定类型和指定维度的多维数组 (执行该指令时, 操作栈中必须包含各维度的长度值), 并将其引用压入栈顶
0xc6ifnull为 null 时跳转
0xc7ifnonnull不为 null 时跳转
0xc8goto_w无条件跳转 (宽索引)
0xc9jsr_w跳转至指定的 32 位 offset 位置, 并将 jsr_w 的下一条指令地址压入栈顶

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

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

相关文章

【2023集创赛】安谋科技杯二等奖作品: 智能体感游戏机

本文为2023年第七届全国大学生集成电路创新创业大赛(“集创赛”)安谋科技杯二等奖作品分享,参加极术社区的【有奖征集】分享你的2023集创赛作品,秀出作品风采,分享2023集创赛作品扩大影响力,更有丰富电子礼…

KUKA机器人如何强制输出或取消数字IO信号?

KUKA机器人如何强制输出或取消数字IO信号? 具体的操作方法和步骤可参考以下内容: 如下图所示,点击菜单—显示—输入/输出端,如下图所示,选择想要查看的信号,这里以数字输出端为例进行说明, 如下图所示,此时可以看到输出端信号的编号、名称和当前值,可以通过下拉滚动条…

UE4和C++ 开发-编程基础记录(UE4+代码基础知识)

1、UE4基础元素 ①Actor 我们又见面了Actor,Actor是在一个关卡中持续存在的,通常他包含几个Actor组件。支持网络复制和多人游戏。   Actor不包含位置,方向。这些东西在Root Component中存储。对于UE3 中的Pawn也由PlayerCharacter继承了…

信钰证券:股票交易费用计算方法?

股票生意是股市参加者之间进行的买入和卖出股票的进程。其中,股票生意费用是参加股市生意的重要组成部分。本文将从多个视点分析股票生意费用计算方法。 首先,股票生意费用一般包含三部分。分别是佣钱、印花税和过户费。佣钱是证券公司为代理股票生意而收…

UE4和C++ 开发-常用的宏(二)UPROPERTY(类似于Unity中C#的特性[SerializeField])

UPROPERTY的作用类似于Unity中C#的特性[SerializeField]或者Godot中的export。目的就是通过反射把属性暴露在蓝图或实例的细节面板。 属性说明符(Property Specifiers)

IDEA设置自动导入包

IDEA设置自动导入包 首先进入设置选项 之后勾选以下两项: 第一项:IntelliJ IDEA 将在我们书写代码的时候自动帮我们优化导入的包,比如自动去掉一些没有用到的包。 第二项: IntelliJ IDEA 将在我们书写代码的时候自动帮我们导入…

mac,linux环境的基础工具安装【jdk,tomcat】

安装 一 linux环境一)、JDK安装卸载: 二)、 tomcat 安装1、[下载](https://mirrors.bfsu.edu.cn/apache/tomcat/tomcat-8/v8.5.63/bin/apache-tomcat-8.5.63.tar.gz)后,在目录 /usr/local/tomcat下,解压缩2、配置tomca…

基于SpringBoot的学院班级回忆录

目录 前言 一、技术栈 二、系统功能介绍 管理员模块的实现 用户信息管理 班委信息管理 班级信息管理 班级相册管理 用户和班委模块的实现 班委注册 班级信息管理 加入班级 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越…

spring boot自定义配置时在yml文件输入有提示

自定义一个配置类&#xff0c;然后在yml文件具体配置值时&#xff0c;一般不会有提示&#xff0c;这个解决这个问题 依赖 <!--自定义配置类&#xff0c;在yml文件写的时候会有提示--><dependency><groupId>org.springframework.boot</groupId><arti…

opencv图像卷积操作原理,opencv中常用的图像滤波函数

文章目录 opencv图像卷积操作原理&#xff0c;opencv中常用的图像滤波函数一、图像卷积操作原理&#xff1a;1、卷积操作原理图&#xff1a; 二、opencv常用的图像滤波函数&#xff1a;这些函数的主要作用是对图像进行平滑处理或去除噪声(核心目的是减少图像中的噪声&#xff0…

【C++入门系列】——命名空间和输入输出

​作者主页 &#x1f4da;lovewold少个r博客主页 ⚠️本文重点&#xff1a;c入门第一个程序和基本知识讲解 &#x1f604;每日一言&#xff1a;忙&#xff0c;不会死&#xff0c;人只有越忙越活&#xff0c;流水不腐&#xff0c;户枢不蠹。 目录 ​作者主页 前言 谈谈我个人…

2ED2410-EM:12v / 24v智能模拟高侧MOSFET栅极驱动器

概述 12v / 24v智能模拟高侧MOSFET栅极驱动器。 特性 PRO-SIL ISO 26262-准备根据ISO 26262:2018条款8-13支持硬件元件评估的集成商。一个通道器件具有两个高侧栅极驱动器输出。3 Ω下拉,50 Ω上拉,用于快速开关开/关。支持背靠背MOSFET拓扑(共漏极和共源)。两个双向高侧模拟…

C/C++ 线程超详细讲解(系统性学习day10)

目录 前言 一、线程基础 1.概念 2.一个进程中多个线程特征 2.1 线程共有资源 2.2 线程私有资源 3.线程相关的api函数 3.1 创建线程 创建线程实例代码如下&#xff1a; 需要特别注意的是&#xff1a; -lpthread和-pthread的区别 3.2 给线程函数传参 传参实例代码如…

生命在于学习——Stable Diffution(Mac端)

一、前言 最近一段时间研究了一下Stable Diffution&#xff0c;Windows和MAC端都搭建成功了&#xff0c;也尝试了各种功能&#xff0c;后续会学习新的使用姿势&#xff0c;写一篇文章记录一下。 二、介绍 1、Stable Diffution是什么 Stable Diffusion&#xff0c;是一种AI绘…

如何处理前端安全性问题(XSS、CSRF等)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

记一次生产大对象及GC时长优化经验

最近在做一次系统整体优化,发现系统存在GC时长过长及JVM内存溢出的问题,记录一下优化的过程 面试的时候我们都被问过如何处理生产问题&#xff0c;尤其是线上oom或者GC调优的问题更是必问&#xff0c;所以到底应该如何发现解决这些问题呢&#xff0c;用真实的场景实操&#xff…

PHP LFI 利用临时文件Getshell

PHP LFI 利用临时文件 Getshell 姿势-安全客 - 安全资讯平台 LFI 绕过 Session 包含限制 Getshell-安全客 - 安全资讯平台 目录 PHP LFI 利用临时文件Getshell 临时文件 linux 和 windows的 临时文件存储规则 linux和windows对临时文件的命名规则 PHPINFO()特性 原理 条…

前端项目--尚医通学习分享

这段时间跟着线上课程完成了一个项目&#xff1a;商医通&#xff08;基于Vue3TypeScript的医院挂号平台&#xff09;。具体我就不过多地介绍其具体功能以及详细的实现步骤了&#xff0c;感兴趣的小伙伴直接&#xff1a;传送门 。该文章我就分享一下在该项目中学习到的一些知识点…

如何退出commit_message页面

虽然提示命令了&#xff0c;但我试了&#xff0c;退不出去。我没搞明白。。。 退出编辑 Crtl Z设置git的编辑器为vim或vi git config --global core.editor vim如果没有vim编辑器&#xff0c;设置成vi编辑器也行 git config --global core.editor vi重新提交 再次进入commi…

【高等数学】极限(上)(最全万字详解)

文章目录 1、数列的极限1.1、数列极限的定义1.2、为什么收敛数列极限是唯一的&#xff1f;1.3、为什么收敛数列是有界的&#xff1f;1.4、数列极限的保号性1.4.1、极限保数列值1.4.2、数列值保极限值 1.5、收敛数列与其子列之间的关系 2、函数极限概念2.1、函数极限的定义2.1.1…