程序=数据+计算。类型确定了数据的定义、数据支持的计算。是程序的基础。

概要介绍C、C++、JAVA、Go、Python的数据类型和运算符。

C语言

C语言类型主要有整型Integer,浮点型Floating Point,字符型Character,枚举类型Enumeration,数组Array,指针Pointer,结构体Structure,共用体Union,空类型void

C 语言支持的运算符,按优先级从高到低排列

  1. () [] -> .,括号、数组下标、成员访问
  2. ! ~ ++ -- - +,逻辑非、按位取反、自增、自减、取负、正号; * & (type) sizeof 解引用、取地址、类型转换、大小计算
  3. * / % 乘法、除法、取模
  4. + - 加法、减法
  5. << >> 左移、右移
  6. < <= > >= 小于、小于等于、大于、大于等于
  7. == != 等于、不等于
  8. & 按位与
  9. ^ 按位异或
  10. | 按位或
  11. && 逻辑与
  12. || 逻辑或
  13. ?:
  14. = += -= *= /= %= <<= >>= &= ^= 赋值及复合赋值
  15. , 逗号

具体类型

整型,整型几乎支持所有运算,包括加减乘除算数运算,左移右移,大于等于比较运算,按位运算,逻辑运算(0表示false,其余整型表示true)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int  //基本整型,4字节

short int // 短整型,2字节
short

long int // 长整型,8字节。
long

unsigned int // 无符号整型,即正整数

int a = 10, b = 5;
printf("%x %x \n", a&b, a|b);
printf("%x %x \n", a&&b, a||b);
// 输出
0 f
1 1

浮点型,浮点型不支持左移右移、按位运算。支持算术、逻辑、比较运算。

1
2
float  // 单精度浮点型,4字节。
double // 双精度浮点型,8字节。

字符型,字符型实际等于8位无符号整型,整数支持的运算它都支持,运算等价于ACCSI码整数运算

1
2
3
4
char  // 字符型,1字节,

// 可以用整数定义char
char c = 68;

枚举类型,C语言的枚举类型同样等价于整型,整数支持的运算它都支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum Color {RED, GREEN, BLUE};

#include <stdio.h>

enum Color {
RED = 10,
GREEN,
BLUE
};

int main() {
enum Color Color1 = RED;
enum Color Color2 = GREEN;
printf("%d %d\n", Color1, Color2);
printf("%d %d %d\n", Color1||Color2, Color1|Color2, Color1<<2);
return 0;
}
// 输出
10 11
1 11 40

数组,数组本身支持[index]索引查询。另外,数组名相当于数组第一个元素的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int arr[10];

#include <stdio.h>

int main() {
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2};
int arr3[] = {1, 2, 3, 4, 5};

printf("%d %d %d\n", arr1[0], arr2[1], arr3[2]);
printf("%x %d %d\n", arr1, *arr1, *(arr1+2));
return 0;
}
// 输出
1 2 3
2d941bd0 1 3

指针,指针本身是一个64位的整型。但不支持乘除、移位、按位运算。支持加减,逻辑运算。当然还支持*解引用运算

1
int *p;

结构体, 结构体支持使用.找到成员变量, 结构体指针则使用->

1
2
3
4
struct Person {
char name[50];
int age;
};

共用体,共享内存。共用体的size是size最大的成员变量的size。共用体运算同结构体。

1
2
3
4
5
union Data {
int i;
float f;
char str[20];
};

void类型, 主要应用于void指针。void指针支持加减,逻辑运算。但不支持*解引用运算

1
void *ptr;

函数指针。函数指针除了支持指针运算,还支持使用()执行函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int add(int a, int b) {
return a + b;
}

int main() {
// 定义一个函数指针,指向返回 int,接收两个 int 参数的函数
int (*func_ptr)(int, int) = add;

printf ("%d\n", *func_ptr);
int result = func_ptr(10, 20);
printf("%d\n", result);

return 0;
}

// 输出
182948169
Result: 30

转型

C语言支持隐式转型和强制转型。强制转型和隐式转型都发生在编译期。

C语言运算符的两侧必须是相同类型,如果不是,就会发生隐式转型。隐式转型规则,隐式转型主要针对整型和浮点型。隐式转型规则是size小的转为size大的,例如char转为int,int 转换为 unsigned/float, float 转换为 double

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
int i = -2;
unsigned int j = 1;
printf ("%d\n", (i + j) >= 0 );
return 0;
}

// 输出.原因,在执行(i + j)时,i转为unsigned int再和j加。0在这里转成了unsigned int
1

C语言的转型很复杂,比如下面的例子

1
2
3
4
int i = -2;
unsigned int j = 1;
printf ("%d\n", ((int)i + (int)j) >= 0 ); // 输出0
printf ("%d\n", ((int)i + j) >= 0 ); // 输出1

C++

C++兼容C语言的类型、操作符和转型,另外,还支持类定义和类重载运算符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

class Point {
public:
int x, y;

Point(int a = 0, int b = 0) : x(a), y(b) {}

// 重载赋值运算符
bool operator==(const Point& other) {
return x == other.y && x == other.y;
}

// 重载输出运算符
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")";
return os;
}
// 重载加法运算符
Point operator+(const Point& other) {
return Point(x + other.y, x + other.y);
}
};

int main() {
Point p1(3, 4);
Point p2(1, 4);
std::cout << p1 << std::endl; // 输出:(3, 4)
printf("%d\n", p1==p2);
Point p3 = p1 + p2;
std::cout << p3 << std::endl;
return 0;
}

// 输出
(3, 4)
0
(7, 7)

C++ 支持bool型,bool型基本等同于1bit的整型,支持加减、移位等运算符,默认false(0)

C语言只能通过malloc申请进程堆内存,把地址给指针,并通过free释放内存。C++提供了new关键字在堆内存创建对象,new后面可以跟int, float, char, 数组等基本类型,也可以跟自定义类型。对应的释放关键字是delete。

在值和指针类型之上,C++增加了引用类型。引用必须在定义的同时初始化,对引用的修改等价于对原值的修改。引用可作为参数和函数返回值(如果函数内部创建的对象,返回的对引用无效)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int& func(){
int a = 1;
return a;
}

int main() {
int a = 10;
int &ref = a;
ref = 20;
printf("%d\n", a);

int&b = func();
printf("%d\n", b);
}

// 输出
20
Segmentation fault

在C语言的隐式和显示转换之上,C++还增加了四个显示类型转换

  1. static_cast,编译期间类型转换,基于类型信息
  2. dynamic_cast,运行时多态向下转型
  3. const_cast,修改本不可变的const对象
  4. reinterpret_cast,等价于指针强制转换

JAVA

JAVA运算符基本和C++一致,除了

  1. 取消指针和引用相关运算符,包括*, ->, &

JAVA类型默认值是0, JAVA的boolean型不再和整型互通

基本数据类型, 存储值本身

1
2
3
4
5
6
7
8
9
10
数据类型	存储大小(字节)
byte 1
short 2
int 4
long 8

float 4
double 8
char 2 (unicode范围)
boolean 依赖 JVM 实现

引用类型, 存储对象的引用。引用类型默认值是null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 类
class Dog {
String name;
int age;
}

// 接口
interface Animal {
void sound();
}

// 数组
int[] numbers = {1, 2, 3, 4};

// 枚举
enum Color {
RED, GREEN, BLUE
}

JAVA提供包装类型为基本数据类型提供引用, 默认值是null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
基本数据类型	包装类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

public class Main {
public static void main(String[] args) {
Integer x = 100;
Integer y = 200;
Integer z = null;
System.out.println(x.compareTo(y));
System.out.println(x.equals(y));
System.out.println(z==null);
}
}
// 输出
-1
false
true

JAVA包装类型的常用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 类静态方法
Integer.valueOf(int i) // 返回表示指定值的 Integer 实例(缓存范围内重用对象)
Integer x = Integer.valueOf(100);

// 实例方法
int intValue() // 返回包装对象的 int 值, 同样还有doubleValue等
Integer x = 10;
int y = x.intValue(); // 10

int compareTo(Integer anotherInteger)
Integer x = 10;
Integer y = 20;
System.out.println(x.compareTo(y));

boolean equals(Object obj) // 比较两个对象的值是否相等。

JAVA提供隐式转换和显示转换

1
2
3
4
5
6
7
8
9
10
11
12
class Animal {}
class Dog extends Animal {}
Dog dog = new Dog();
Animal animal = dog; // 子类对象自动转换为父类引用

Animal animal = new Dog();
Dog dog = (Dog) animal; // 强制将父类引用转换为子类类型

// instanceof 关键字检查对象是否是某个类型, 用于向下转型
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}

JAVA中,所有类都直接或间接继承自 Object 类。Object类提供的成员方法

1
2
3
4
5
6
7
public boolean equals(Object obj)

public native int hashCode()

protected native Object clone() throws CloneNotSupportedException

public String toString()

Go

Golang的运算符和C++的也类似,区别在于

  1. 指针类型不支持算术运算,只支持引用和解引用运算。指针的零值是nil。golang使用 new 分配内存,并返回指针。指针对象引用成员变量也用.

golang支持的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
类型	长度(字节)
// 以下是值类型
bool 1
byte 1
int32, uint32 4
int64, uint64 8
float32 4
float64 8
array
struct
string(字符串如果想要修改,需要转成[]byte类型)

,默认值是nil
slice, 例如[]byte
map
channel
interface
function

Go中只有强制类型转换,没有隐式类型转换。a:=(int)(xxx)。另外, golang支持类型断言将接口转换为其具体类型。对象.(类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
var i interface{} = 42 // 接口存储了具体类型 int

// 类型断言
value, ok := i.(int)
if ok {
fmt.Println("Converted value:", value) // 输出:Converted value: 42
} else {
fmt.Println("Conversion failed")
}
}

Golang中,所有struct都实现interface{}空接口

golang 运行时类型信息

Python

相比以上的强类型语言,python的操作符比较特殊。按照优先级排序为

  1. 小括号()
  2. 索引运算符 x[i] 或 x[i1: i2 [:i3]]
  3. 属性访问 x.attribute
  4. 乘方 **
  5. 按位取反 ~
  6. 符号运算符 +(正号)、-(负号)
  7. 乘除*、/、//、%
  8. 加减+、-
  9. 位移>>、<<
  10. 按位与 &
  11. 按位异或^
  12. 按位或|
  13. 比较运算符==、!=、>、>=、<、<=
  14. is 运算符is、is not
  15. in 运算符 in、not in
  16. 逻辑非 not
  17. 逻辑与 and
  18. 逻辑或 or
  19. 逗号exp1, exp2

Python的类型如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
类型	描述
int 整型 支持任意大小
float 浮点数
complex 复数,形式为 a + bj
bool 布尔值,TrueFalse

str Unicode 文本数据
NoneType None

list 可变的有序集合 [1, 2, 3]
tuple 不可变的有序集合 (1, 2, 3)
range 表示数字范围 range(5)

set 可变集合,支持哈希操作 {1, 2, 3}
dict 可变键值对集合 {"a": 1, "b": 2}

iterator 迭代器 iter([1, 2, 3])

Python变量的类型是在运行时决定的,不需要显式声明。Python 不允许隐式类型转换。

类型检查

1
2
print(type(42))  # <class 'int'>
print(isinstance(42, int)) # True

python类型转换也非常灵活

1
2
3
4
5
6
x = int(3.5)   # 3
y = float(3) # 3.0

lst = list((1, 2, 3)) # [1, 2, 3]
tpl = tuple([1, 2, 3]) # (1, 2, 3)
st = set([1, 2, 2, 3]) # {1, 2, 3}

类似JAVA,在python中,object是所有类的基类。object类的方法

1
2
3
4
5
6
7
8
9
10
11
12
__init__(self)	初始化方法,用于对象创建后初始化属性。
__del__(self) 析构方法,用于对象销毁时清理资源。
__str__(self) 返回对象的字符串表示,通常用于打印或转换为字符串时调用。
__repr__(self) 返回对象的官方表示,通常用于调试。
__eq__(self, other) 比较对象是否相等,默认比较引用地址,可重写实现值比较。
__ne__(self, other) 比较对象是否不等,默认基于 __eq__ 结果。
__hash__(self) 返回对象的哈希值,用于哈希表等数据结构。
__getattribute__(self, name) 获取对象属性的值,所有属性访问都会调用此方法,可重写以自定义行为。
__setattr__(self, name, value) 设置对象属性的值。
__delattr__(self, name) 删除对象属性。
__dir__(self) 返回对象的属性和方法列表,供 dir() 函数使用。
__class__ 返回对象的类。

Python对象和传值/引用

python类型分为两类,可变类型和不可变类型。如果修改一个不可变对象,Python 将会创建一个新的对象。不可变对象包括整数(int)、浮点数(float)、字符串(str)、元组(tuple)等。

可变变量的值可以原地修改。可变对象包括列表(list)、字典(dict)、集合(set)等。

不可变对象作为函数参数,无法在函数内部改变不可变对象的值,相当于传对象拷贝。可变对象作为参数,函数内部修改可变对象的内容会影响外部变量,相当于传引用

1
2
3
4
5
6
7
8
9
10
11
12
13
def modify(x):
x = 10
a = 5
modify(a)
print(a)
# 输出:5,a的值未变

def modify(lst):
lst.append(4)
nums = [1, 2, 3]
modify(nums)
print(nums)
# 输出:[1, 2, 3, 4]