img

java和cpp的forEach循环的区别

众所周知,java内的函数传参方法只有一种—==值传递==,cpp分为值传递和地址传递

那么两者的forEach循环有什么区别呢?

java中的forEach与函数传参类似

  • 对于基本数据类型(八大基本数据类型), forEach循环并不会改变他们实际的数值

    • byte:字节类型,Java中最小的数据类型,1个字节,占8位,取值范围-128127,默认值0
    • char:字符型,用于存储单个字符,2个字节,占16位,取值范围0~65535,默认值为空
    • short:短整型,2个字节,占16位,取值范围-3276832717,默认值0
    • int:整型,用于存储整数,4个字节,占32位,取值范围-2147483648~2147483647,默认值0
    • long:长整型,8个字节 占64位,-263~263-1,默认值0L
    • float:浮点型,占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0
    • double:双精度浮点型,用于存储带有小数点的数字,8个字节 占64位,默认值0
    • boolean:布尔类型,1个字节 占8位,用于判断真或假(仅有两个值,即true、false),默认值false
  • 对于引用数据类型

    引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,

    forEach内对于调出来的元素的操作==会改变==引用类型的实际的值

    • 特殊的,对于==包装类==,包装类的值不会因为forEach内的操作被改变

      ==Integer 对象是不可变的==

      java核心技术卷1 第11版 p194

    ==警告==: 有些人认为包装器类可以用来实现修改数值参数的方法, 然而这是错误的。在第4 章中曾经讲到, 由于Java 方法都是值传递, 所以不可能写一个下面这样的能够增加整型参数值的Java 方法。

    问题是==Integer 对象是不可变的==: 包含在包装器中的内容不会改变: 不能使用这些包装器类创建修改数值参数的方法。
    如果想编写一个修改数值参数值的方法, 就需要使用在org.omg.CORBA 包中定义的
    持有者( holder ) 类型, 包括IntHolder、BooleanHolder 等。每个持有者类型都包含一个公有(!)域值, 通过它可以访问存储在其中的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void triple(int x) // won't work 
{
x=3*x; //modifies local variable;
}

public static void triple(Intger x) // won't work
{
x=3*x;
}

// 可以通过holder类型改变 ,实际上就是引用类型 ,地址传递会被改变
public static void triple(IntHolder x)
{
x.value=3*x.value;
}

代码

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* @author Dhx_
* @className Test
* @description TODO
* @date 2022/7/11 20:52
*/
public class Test {
public static void main(String[] args) {
Book[] books =new Book[]{new Book(12),new Book(122),new Book(1122),new Book(812),new Book(612)};
List<CartItem> cartItemList = new ArrayList<>(5);
cartItemList.add(new CartItem(books[0]));
cartItemList.add(new CartItem(books[1]));
cartItemList.add(new CartItem(books[2]));
cartItemList.add(new CartItem(books[3]));
cartItemList.add(new CartItem(books[4]));
for(CartItem e :cartItemList)
{
e.setBook(new Book(e.getBook().price+10000));
}
cartItemList.forEach(System.out::println);
Integer x=10;
List<Integer> integerList =List.of(1,2,3,4,5);
for(Integer e: integerList)
{
e= new Integer(e.intValue()+1);
}
integerList.forEach(System.out::println);
x=11;
System.out.println(x);
}
}
class CartItem
{
Book book;
Date date=new Date();
public void setBook(Book book) {
this.book = book;
}

@Override
public String toString() {
return "CartItem{" +
"book=" + book.price +
'}';
}

public CartItem(Book book) {
this.book = book;
}

public Book getBook() {
return book;
}
}
class Book {
Book(int price) {
this.price = price;
}
public Integer price;
}

debug

  • 通过debug发现,cartItem和integer的地址都是相应的List的元素的地址

    🎈说明对于引用类型,forEach采用的是地址传递

    image-20220711215956956image-20220711220006149

    而变量Integer x 的地址在经过x=11赋值之后,值改变,地址也改变,与Integer对象是不可变的相照应

    image-20220711220153460image-20220711220206211

cpp

  • cpp中的forEach循环==不会==影响原本的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stdc++.h>
class Integer{
public:
int num;
Integer(int num){ this->num = num; }
Integer() {}
};
int main()
{
string str = "abcdefg";
for (char ch : str) ch += 1;
for (char ch : str) std::cout << ch << ' ';
std::cout << '\n';
Integer integers[] = {Integer(4), Integer(5), Integer(6)};
for (Integer e : integers) e.num++;
for (Integer e : integers) cout << e.num << ' ';
// a b c d e f g
// 4 5 6
getchar();
}