Java C++ Python - 数据类型、字面常量与类型转换
一、数据类型1. Java的数据类型分为三大类布尔型boolean、字符型char和数值型整型byte、short、int、long浮点型float、double。Java还有8个包装类将简单类型的变量表示为类Boolean、Character、Byte、Short、Integer、Long、Float和Double。此外编程时还经常使用到两种类变量String和Date。2. 数据类型的字节大小首先我们要明确的是Java并不像C/C那样提供运算符sizeof()因为所有的内存都是由虚拟机来管理的程序员不需要自己管理堆内存的分配和释放。TypeSize(Bytes)TypeSize(Bytes)byte1java.lang.Byte16char1java.lang.Character16boolean1java.lang.Boolean16short2java.lang.Short16int4java.lang.Integer16long8java.lang.Long16float4java.lang.Float16double8java.lang.Double163. 数据类型与包装类的初始化赋值以及引用相等判断byte b1 -128; byte b2 -128; System.out.println(byte: (b1 b2)); Byte B1 127; Byte B2 127; System.out.println(Byte: (B1 B2)); char c1 a; char c2 a; System.out.println(char: (c1 c2)); Character C1 a; Character C2 a; System.out.println(Character: (C1 C2)); short s1 128; short s2 128; System.out.println(short: (s1 s2)); Short S1 128; Short S2 128; System.out.println(Short: (S1 S2)); int i1 128; int i2 128; System.out.println(int: (i1 i2)); Integer I1 128; Integer I2 128; System.out.println(Integer: (I1 I2)); long l1 128l; long l2 128l; System.out.println(long: (l1 l2)); Long L1 128l; Long L2 128l; System.out.println(long: (L1 L2)); double d1 1.0; double d2 1.0; System.out.println(double: (d1 d2)); Double D1 1.0; Double D2 1.0; System.out.println(Double: (D1 D2)); float f1 1.0f; float f2 1.0f; System.out.println(float: (f1 f2)); Float F1 1.0f; Float F2 1.0f; System.out.println(FLoat: (F1 F2));运行结果byte: trueByte: truechar: trueCharacter: trueshort: trueShort: falseint: trueInteger: falselong: truelong: falsedouble: trueDouble: falsefloat: trueFLoat: false其中Short、Integer和Long的包装类内部维护了一个1字节大小的缓存池它们总是从缓存池中获取对象只有在超出了其缓存池缓存池-128到127它才创建新的对象。二、类型转换1. 简单数据类型之间的转换在Java中整型、浮点型和字符型被视为简单数据类型这些类型由低级到高级分别为(byte, short, char)—int—long—float—double。1自动类型转换低级变量可以直接转换为高级变量同级间byte也可直接转换为short。e.g.byte b 1; short s b; int i s; long l i; float f l; double d f;如果低级变量char型向高级类型转换时会自动转换为对应的ASCII码。如果是作为双目运算符的参数则遵循以下自动转换规则所有的byteshortchar型自动提升为int型如果有一个操作数为long型计算结果是long型如果有一个操作数为float型计算结果是float型如果有一个操作数为double型计算结果是double型如果有一个操作数是常量表达式另一个操作数为变量类型为T时常量表达式可以被T表示输出结果的类型为T。被final修饰的变量不会自动改变类型。当两个变量都被final修饰时结果会根据实际赋值的变量的类型而转化。e.g.final byte b1 1; byte b2 1; final short s3 1; int i4 b1 b2; // 正常编译b2由byte自动提升为int byte b5 b1 s3; // 正常编译b1和s3都有final修饰转换的类型由b5决定运算符会对两边的参数进行自动类型转换而则不会其他的也以此类推。e.g.short s 1; s 1; // 编译通过 s s 1; // 编译出错三目运算符中的 : 也遵循以上自动类型转换的规则。e.g.System.out.println(false ? 1.2 : 1); // 输出结果为1 char x x; int i 10; System.out.println(false ? i : x); // 输出结果为120 System.out.println(false ? 10 : x); // 输出结果为x2强制类型转换将高级转换为低级或者同级间char与byte之间的转换、char与short之间的转换、short转换成byte需要使用强制类型转换。e.g.int i 1; short s (short)i; byte b (byte)s; char c (char)b;注基本数据类型不可以强制类型转换为包装类。e.g.Double d 1; // 编译出错int类型无法转换为Double3注意boolean类型与其他类型既不能自动转换也不能强制转换。所以Java是类型安全的而C不是。2. 包装类与简单类型的转换// 定义double类型变量 double a 91.5; // 手动装箱 Double b new Double(a); // 自动装箱 Double c a; System.out.println(装箱后的结果为 b 和 c); // 定义一个Double包装类对象值为8 Double d new Double(87.0); // 手动拆箱 double e d.doubleValue(); // 自动拆箱 double f d; System.out.println(拆箱后的结果为 e 和 f);我们同样可以利用包装类的手动拆箱实现更高级类型的自动转换。e.g.Float f1 0.1f; double d1 f1.doubleValue();3. 字符串与基本类型的转换// 将基本类型转换为字符串 int c 10; String str1 Integer.toString(c); // 方法一使用包装类的 toString() 方法 String str2 String.valueOf(c); // 方法二使用String类的 valueOf() 方法 String str3 c ; // 方法三用一个空字符串加上基本类型得到的就是基本类型数据对应的字符串 System.out.println(str1); System.out.println(str2); System.out.println(str3); double m 78.5; String str4 Double.toString(m); System.out.println(m 转换为String型后与整数20的求和结果为 (str420)); // 将字符串转换为基本类型 String str 8; int d Integer.parseInt(str); // 方法一调用包装类的 parseXxx 静态方法 int e Integer.valueOf(str); // 方法二调用包装类的 valueOf() 方法转换为基本类型的包装类会自动拆箱 System.out.println(d); System.out.println(e); String str5 180.20; Double a Double.parseDouble(str5); System.out.println(str 转换为double型后与整数20的求和结果为 (a20));4. 将字符直接作为数值转换为其它数据类型将字符变量转换成数值型变量除了将其自动转换成对应的ASCII码以外还可以使用Character包装类的类方法getNumericCalue(char ch)来实现将字符1到数值1的转换。e.g.int i Character.getNumericValue(1); System.out.println(i); float f Character.getNumericValue(1); System.out.println(f);三、C的基本数据类型以及隐式类型转换1. C基本数据类型的内存大小cout sizeof(bool) endl; // 1 cout sizeof(char) endl; // 1 cout sizeof(short) endl; // 2 cout sizeof(int) endl; // 4 cout sizeof(long) endl; // 4 cout sizeof(float) endl; // 4 cout sizeof(double) endl; // 8 cout sizeof(char *) endl; // 8 cout sizeof(int *) endl; // 8 cout sizeof(char[2]) endl; // 2 cout sizeof(int[2]) endl; // 8 cout sizeof(string) endl; // 32注意指针大小是由当前CPU运行模式的寻址位数决定32位机是4字节64位机是8字节数组对象等于数据类型的大小乘以数组的元素个数。2. C的字面常量1整型常量前缀0b表示二进制0表示八进制0x表示十六进制。int a 0b10, b 010, c 10, d 0x10; cout a b c d endl;运行结果2 8 10 16后缀不加后缀默认为int(32位)l/L表示long(32位)ll/LL表示long long(64位)u/U表示unsigned(32位)u/U和l/L的组合不分先后表示unsigned long(32位)u/U和ll/LL的组合不分先后表示unsigned long long(64位)。#define A -1u #define B -1ul #define C -1ull cout A B C endl;运行结果4294967295 4294967295 184467440737095516152浮点型常量后缀默认是双精度浮点型doublef/F表示单精度浮点型floatl/L表示长双精度浮点型long double。中缀科学计数e表示以10为底的指数p表示以2为底的指数前面的系数必须是16进制表示。#define A 1.2f #define B 1e3 #define C 0x10p2 cout A B C endl;运行结果1.2 1000 643字符常量字符常量是括在单引号中默认为窄字符例如x可以存储在char类型的简单变量中。如果常量以L开头则表示宽字符例如Lx此时它必须存储在wchar_t类型的变量中。字符常量可以是一个普通的字符例如 x、一个转义字符例如\n或一个通用的字符例如\u02C0。C的转义字符主要包括ValueEscape sequencenewline换行\nbackslash反斜杠\\horizontal tab水平制表\tquestion mark问号? or \?vertical tab垂直制表\vsingle quote单引号\backspace退格\bdouble quote双引号\carriage return回车\rthe null character空字符NULL\0form feed换页\foctal三位8进制字符\oooalert响铃\ahexadecimal两位16进制字符\xhhcout a \141 \x61 endl;运行结果a a a4字符串常量字符串字面值或常量是括在双引号 中的默认为窄字符串。如果常量以L开头则表示宽字符串。C11 引入了原始字符串不进行转义最基本的用法是R定界符(...)定界符由R开头双引号内包围着原始字符串定界符是可选的当原始字符串中出现 ) 的情况下因为编译器无法知道哪一个)和左边的默认定界符(相对应这时候就需要自定义定界符定界符最长不超过16个字符且不为小括号、空白、控制字符和反斜杠。一个字符串包含类似于字符常量的字符普通的字符、转义序列、通用的字符和原始字符串。#define A 1\t2\t3 #define B L1\t2\t3 #define C R(1\t2\t3) #define D R.(1\t(2)\t3). cout A: A ; B: B ; C: C ; D: D endl;运行结果A: 1 2 3; B: 0x404012; C: 1\t2\t3; D: 1\t(2)\t3当两个宽字符串之间或者字符串和宽字符串之间只有空白符或者没有任何字符时可以直接进行拼接。此外字符串中使用 \ 进行分行。char a[] 1234; char b[] 12 34; char c[] 12 34; char d[] 12\ 34; cout a: a ; b: b ; c: c ; d: d endl;运行结果a: 1234; b: 1234; c: 1234; d: 12345布尔常量true和false3. 宏定义1宏定义的本质是字符串替换所以也可以使用\来进行分行。#define SWAP(A, B) \ int TEMP A; \ A B; \ B TEMP; int a 1, b 2; SWAP(a, b); cout a b endl;运行结果2 12宏定义中如果没有使用到反斜杠\或者多行注释/**/那么该宏定义就是当行结束的所以如果参数要进行字符串拼接的话字符串之间就不能是\n。#define A 1234 // 编译通过 #define B 12 34 // 编译通过 #define C 12 34 // 编译报错应输入声明3宏定义中可以听过多行注释来进行分行而且多行注释是可以替代宏指令、宏名称和字符串之间的空格的。特别注意多行注释可以插入的位置包括#号之后宏名称前后拼接字符串之间聚合中的括号、逗号前后。#define A {{1}, 1 2} #/**/define/**/B/**/{/**/{/**/1/**/}/**/,/**/1/**/2/**/} #/* */define/* */C/* */{/* */{/* */1/* */}/* */,/* */1/* */2/* */}4. 何时发生隐式类型转换1在混合类型的表达式中操作数会被转换为相同类型类型提升。int ival; double dval; ival dval; // ival converted to double2条件表达式会被转换为bool类型。int ival; if (ival) // ival converted to bool while (cin) // cin converted to bool条件操作符? :中的第一个操作数逻辑非!、逻辑与、逻辑或||的操作数都是条件表达式。if、while、do while、以及for的第2个表达式都是条件表达式。3初始化和赋值int ival 3.14 // 3.14 converted to int int *ip; ip 0; // the int 0 converted to a null pointer of type int *但要注意的是数组的初始化是不会进行隐式类型转换的。e.g.int a[1] {1.1};报错信息error: narrowing conversion of 1.1000000000000001e0 from double to int inside { } [-Wnarrowing]4在函数调用时所传递的参数也可能发生隐式类型转换。5. 如何进行隐式类型转换1算术转换算术转换保证在执行操作前将二元操作符的两个操作数转换为同一类型并使表达式的值也具有相同的类型。算术转换通常的是做整形提升integral promotion对于所有比int小的整形包括char、signed char、unsigned char、short和unsigned short如果该类型的所有可能的值都能包含在int内它们就会被提升为int否则被提升为unsigned int。如果将bool值提升为int则false转换为0true转换为1。包含short和int类型的表达式short转换为int。如果int足以表示所有unsigned short类型的值则将unsigned short转换为int否则两个操作数均转换为unsigned int。long和unsigned int的转换也一样。只要机器上的long足够表示unsigned int类型所有的值就将unsigned int转换为long否则两个操作数都转换为unsigned long。在32位的机器上long和int通常用一个字长表示此时如果表达式包含unsigned int和long两者都转换为unsigned long。如果表达式包含signed和unsigned intsigned会被转换为unsigned。如果int 操作数的值恰为负数其转换为unsigned int可能会变为一个很大的正数转换结果是该负值对unsigned int的取值个数求模。所以最好避免对int和unsigned int的两个操作数进行比较。转换示例2数组名转换为指向其第一个元素的指针int ia[10]; // array of 10 ints int *ip ia; // convert ia to pointer to first element另外任意数据类型的指针都可转换为void *整形数值常量0可以转换为任意类型指针。3指针值可转换为bool如果指针为0转换为false否则转换为true。if (cp) // true if pointer cp is not zero4算术类型与bool的转换算术类型转换为bool时0转换为false其他值包括负值转换为true。将bool转换为算术类型时true转换为1false转换为0。5转换与枚举类型枚举类型对象或枚举成员将自动转换为整形其转换结果可以用于任何需要使用整数值的地方。具体会被转换为哪种整形依赖于枚举成员的最大值和机器。enum对象或枚举成员至少提升为int如果int无法表示枚举成员的最大值则提升到能表示所有枚举成员值的、大于int型的最小类型unsigned int 、long或unsigned long。四、Python的基本数据类型以及类型转换1. Python3的6种标准数据类型Number包括int(表示长整型囊括了Python2中的Long)、float、bool和complex(复数)StringstrListlistTupletupleSetsetDictionarydict其中又可分类为不可变数据和可变数据不可变数据Number、String、Tuple可变数据List、Dictionary、Set2. 数据类型的内存使用sys.getsizeof方法可以查看 python 对象的内存占用单位字节(byte)实际上是调用了__sizeof__方法可以直接查看类的内存占用 import sys sys.getsizeof(int()) 24 sys.getsizeof(float()) 24 sys.getsizeof(bool()) 24 sys.getsizeof(complex()) 32 sys.getsizeof(str()) 49 sys.getsizeof(tuple()) 48 sys.getsizeof(list()) 64 sys.getsizeof(set()) 224 sys.getsizeof(dict()) 240也可以查看类的实例的内存占用 sys.getsizeof(1) # int(1) 28 sys.getsizeof(1073741823) # int(1073741823) 28 sys.getsizeof(1073741824) # int(1073741824) 32 sys.getsizeof(1.0) # float(1.0) 24 sys.getsizeof(3.141592653589793238462643383279) # float(3.141592653589793238462643383279) 24 sys.getsizeof(True) # bool(True) 28 sys.getsizeof(False) # bool(False) 24 sys.getsizeof(complex(1, 1)) 32 sys.getsizeof(complex(1073741824, 1073741824)) 32 sys.getsizeof(1) # str(1) 50 sys.getsizeof(12) # str(12) 51 sys.getsizeof((1, 2)) # tuple((1, 2)) 64 sys.getsizeof((1, 2, 3)) # tuple((1, 2, 3)) 72 sys.getsizeof([1]) # list([1]) 72 sys.getsizeof([1, 2]) # list([1, 2]) 80 sys.getsizeof(set([1])) 224 sys.getsizeof(set([1, 2])) 224 sys.getsizeof({1: 1}) # dict({1: 1}) 240 sys.getsizeof({1: 1, 2: 2}) # dict({1: 1, 2: 2}) 240可以看出int类型的数值每增加内存占用就会增加4个字节我也不清楚为什么不是float类型不管浮点数有多少小数位内存占用始终为24个字节bool类型中True值占据一个字节False值不占字节complex类型不管实部和虚部的数值有多大内存占用始终为32个字节str类型每增加一个字符内存占用就会增加1个字节tuple类型每增加一个数内存占用就会增加8个字节list类型每增加一个数内存占用就会增加8个字节set类型的初始内存占224个字节dict类型的初始内存占240个字节。3. 字面常量以常量的形式给出的原始数据不可改变1数值型字面量# 整型字面量 a 0b1111 # 二进制 b 15 # 十进制 c 0o17 # 八进制或017 d 0xf # 十六进制A~F也可大写 print(a, b, c, d) # (15, 15, 15, 15) # 浮点型字面量 f1 3.14159 f2 2.6e5 # 科学计数 print(f1, f2) # (3.14159, 260000.0) # 复数型字面量 x 3.14j 159 print(x, x.imag, x.real) # ((1593.14j), 3.14, 159.0)注意与C的区别C只能使用0前缀表示八进制Python可以使用0前缀或0o前缀来表示八进制。python支持str类型向int/float的转换 int(10) 10 int(0b10) Traceback (most recent call last): File stdin, line 1, in module ValueError: invalid literal for int() with base 10: 0b10 int(0b10, 2) 2 int(0o10, 8) 8 int(0x10, 16) 16 float(3.14) 3.14 float(2.6e5) 260000.0 complex(12j) (12j) complex(2j1) Traceback (most recent call last): File stdin, line 1, in module ValueError: complex() arg is a malformed string complex(1 2j) Traceback (most recent call last): File stdin, line 1, in module ValueError: complex() arg is a malformed string2字符串字面量a abc b abc c a b c d a b c u unicode(123) # unicode编码 print u # u123 r rraw \n string # 原始字符串(防转义) print r # raw \n string f a{0}{1}.format(b, 1) # 格式化方法 print f # ab1另外转义的问题也可以通过string_escape编码来转换。string-escape是对二进制的字节流一个字节一个字节转义并对每个字节以16进制输出。 a \n\r\t\v\f\b\a\\\ a \n\r\t\x0b\x0c\x08\x07\\ b a.encode(string_escape) b \\n\\r\\t\\x0b\\x0c\\x08\\x07\\\\\\ c b.decode(string_escape) c \n\r\t\x0b\x0c\x08\x07\\ a c True但是要注意的是双引号在字符串中一般默认不使用转义因为边界符一般默认使用单引号。 a \ b a.encode(string_escape) b # 注意结果不是\\ 3布尔型字面量True和False4特殊字面量None用来指定未创建的字段五、字符数组和字符串的转换1. Java1String类的toCharArray()方法将字符串转为字符(char)数组String ss abc; char[] cc; cc ss.toCharArray(); // cc {a, b, c}2String类的valueOf()方法将字符(char)数组转换为字符串char[] cc {a, b, c}; ss String.valueOf(cc); // ss abc2. C1字符数组转化成字符串char ch [] ABCDEFG; string str(ch); // string str ch; 在原有基础上添加可以用str ch;2将string类型转换为字符数组char buf[10]; string str(ABCDEFG); length str.copy(buf, 9); buf[length] \0; // or strcpy(buf, str.c_str()); //strncpy(buf, str.c_str(), 10);注意字符串类型的c_str()函数返回的是字符常量指针如果直接赋值需要加上conststring str ABCDEFG; const char *cptr str.c_str();参考博客【1】Python3 基本数据类型【2】使用 sys.getsizeof 查看 python 对象的内存占用【3】[Python] sys.getsizeof(int())返回24bytes问题【4】String字符串与字符(char类型)数组互相转换【5】C中字符数组与string的相互转换【6】Python初级教程(04): 变量、常量和字面量【7】C 常量或字面量【8】C 中 各种类型数值的表示法C数值后缀【9】C 字面量【10】C 字面量【11】【现代C】原始字符串-raw string literal