最近在做一个项目里,给ArrayList 赋值发现结果不正常。仔细想了一下然来是没有深入理解 “容器类仅能持有对象引用(指向对象的指针)” 这句话。
下面来看一下示例程序:
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- public class MapList {
- public static void main(String []args){
- ArrayList <Map<String,String>> mapList=new ArrayList <Map<String,String> >();
- Map<String ,String> map=new HashMap<String,String>();
- for(int i=0;i<5;i++){
- map.put("key","value"+i);
- mapList.add(map);
- }
- System.out.println("mapList.size:"+mapList.size());
- System.out.println("mapList:"+mapList);
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- ArrayList <Map<String,String>> mapList1=new ArrayList <Map<String,String> >();
- for(int i=0;i<5;i++){
- Map<String ,String> map1=new HashMap<String,String>();
- map1.put("key","value"+i);
- mapList1.add(map1);
- }
- System.out.println("mapList1:"+mapList1);
- }
- }
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class MapList { public static void main(String []args){ ArrayList <Map<String,String>> mapList=new ArrayList <Map<String,String> >(); Map<String ,String> map=new HashMap<String,String>(); for(int i=0;i<5;i++){ map.put("key","value"+i); mapList.add(map); } System.out.println("mapList.size:"+mapList.size()); System.out.println("mapList:"+mapList); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>"); ArrayList <Map<String,String>> mapList1=new ArrayList <Map<String,String> >(); for(int i=0;i<5;i++){ Map<String ,String> map1=new HashMap<String,String>(); map1.put("key","value"+i); mapList1.add(map1); } System.out.println("mapList1:"+mapList1); } }
打印结果为:
mapList.size:5mapList:[{key=value4}, {key=value4}, {key=value4}, {key=value4}, {key=value4}]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
mapList1:[{key=value0}, {key=value1}, {key=value2}, {key=value3}, {key=value4}]
为什么第一条打印的是:[{key=value4}, {key=value4}, {key=value4}, {key=value4}, {key=value4}]。
因为map 只new 了一次,且在循环外。并且collection 是持有对象的引用。
- Map<String ,String> map=new HashMap<String,String>();
- for(int i=0;i<5;i++){
- map.put("key","value"+i);
- mapList.add(map);
- }
Map<String ,String> map=new HashMap<String,String>(); for(int i=0;i<5;i++){ map.put("key","value"+i); mapList.add(map); }所以打印出来肯定是一样的都是:[{key=value4}, {key=value4}, {key=value4}, {key=value4}, {key=value4}]。
效果如图所示:
而mapList 打印出来结果为:mapList1:[{key=value0}, {key=value1}, {key=value2}, {key=value3}, {key=value4}]。
如下图所示:
在我另一篇转载博客了讲了( link 为: http://blog.csdn.net/clam_clam/article/details/6645021 )
1、容器类和Array的区别、择取
* 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。
* 一旦将对象置入容器内,便损失了该对象的型别信息
但今天一开始还出错所以看书固然重要 ,实践更重要呀。
没看书的话不可能一出错就意识到问题所在,也要经过实践才能强化知识。
- System.out.println("mapList1:"+mapList1);
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- ArrayList <Integer> list3=new ArrayList <Integer> ();
- Integer intvar=new Integer(0);
- for(int i=0;i<5;i++){
- intvar=i;
- list3.add(intvar);
- }
- System.out.println(list3);
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- ArrayList <User> list4=new ArrayList <User> ();
- User user=new User();
- for(int i=0;i<5;i++){
- user.setName("name"+i);
- list4.add(user);
- }
- System.out.println(list4);
System.out.println("mapList1:"+mapList1); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>"); ArrayList <Integer> list3=new ArrayList <Integer> (); Integer intvar=new Integer(0); for(int i=0;i<5;i++){ intvar=i; list3.add(intvar); } System.out.println(list3); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>"); ArrayList <User> list4=new ArrayList <User> (); User user=new User(); for(int i=0;i<5;i++){ user.setName("name"+i); list4.add(user); } System.out.println(list4);
结果为:
[0, 1, 2, 3, 4]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[User [name=name4], User [name=name4], User [name=name4], User [name=name4], User [name=name4]]。
为什么事 [0,1,2,3,4]因为:intvar=i; 会自动装箱,new 一个空间。
而User [name=name4], User [name=name4], User [name=name4], 不会。没有在for 循环里重新开辟空间所以都指向同一个空间。
2. 对象类型数组也是持有引用
看下面例子:
- class Obj{
- String name;
- Obj(String name){
- this.name=name;
- }
- void setName(String name){
- this.name=name;
- }
- @Override
- public String toString() {
- return "Obj["+this.name+"]";
- //return super.toString();
- }
- }
- public class FS {
- public static void main(String[] args){
- Obj[] arr=new Obj[5];
- Obj obj=new Obj("computer");
- for(int i=0;i<5;i++){
- arr[i]=obj;
- }
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- for(int i=0;i<5;i++){
- System.out.print(arr[i]);
- }
- System.out.println("");
- obj.setName("info");
- System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
- for(int i=0;i<5;i++){
- System.out.print(arr[i]);
- }
- System.out.println("");
- }
- }
class Obj{ String name; Obj(String name){ this.name=name; } void setName(String name){ this.name=name; } @Override public String toString() { return "Obj["+this.name+"]"; //return super.toString(); } } public class FS { public static void main(String[] args){ Obj[] arr=new Obj[5]; Obj obj=new Obj("computer"); for(int i=0;i<5;i++){ arr[i]=obj; } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); for(int i=0;i<5;i++){ System.out.print(arr[i]); } System.out.println(""); obj.setName("info"); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); for(int i=0;i<5;i++){ System.out.print(arr[i]); } System.out.println(""); } }运行结果为:
- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- Obj[computer]Obj[computer]Obj[computer]Obj[computer]Obj[computer]
- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- Obj[info]Obj[info]Obj[info]Obj[info]Obj[info]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Obj[computer]Obj[computer]Obj[computer]Obj[computer]Obj[computer] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Obj[info]Obj[info]Obj[info]Obj[info]Obj[info]改变obj 后arr 数组都改变了,所以数组拥有的是obj 对象的引用。
相关推荐
引用则是一种安全的别名,它像指针一样可以用来间接访问对象,但是一旦初始化后就不能改变引用的对象。 容器指针引用示例通常会涉及到如何在容器中使用指针和引用,以及它们之间的相互操作。下面我们将深入探讨这些...
例如,你可以定义一个指向抽象类的指针或引用的容器,然后向容器中添加各种派生类的对象,通过抽象类的接口进行统一的操作,实现代码的灵活性和可扩展性。 总之,理解并熟练掌握抽象类、指针和引用的概念及其相互...
一旦引用被初始化为一个对象,就不能改变它指向另一个对象。例如,`int &ref = x;`声明了一个名为`ref`的引用,它绑定到变量`x`上。通过`ref`所做的任何操作都会直接影响到`x`。引用没有NULL状态,必须在声明时初始...
在Java编程中,容器是用来存储和管理对象的类或接口,它们使得我们可以在程序中方便地组织和操作数据。在Java中,常见的容器主要分为三类:List、Set和Map,这些都是Java集合框架的重要组成部分。 首先,我们来看...
在这个"游戏对象池例子(兼容智能指针、工厂类)"中,我们将探讨如何利用C++实现这种技术,并结合智能指针和工厂模式来确保兼容性和效率。 1. **对象池概念**: 对象池的基本思想是预先创建一批对象,当需要对象时...
在C++编程语言中,一个重要的特性是虚函数(virtual functions),这使得即使通过空对象指针也能调用成员函数,这种行为被称为“空指针调用”或“空对象调用”。本篇将深入探讨这个主题,以及它在C++中的实现原理和...
这些类的实例可以被放入一个STL容器,比如`std::vector*>`,这样容器就能存储不同类型的对象,并通过基类指针调用公共方法。 在实际编程中,这样的设计可以方便地管理一组异构对象,允许在不关心具体类型的情况下...
2. **非静态成员函数指针**:非静态成员函数指针需要一个对象实例才能调用,因此在使用非静态成员函数指针时,需要提供对应的类实例。 3. **typedef简化函数指针**:为了简化函数指针的使用,可以使用`typedef`创建...
3. 重绑定:指针可以在生命周期内指向不同对象,引用一旦绑定后不能改变。 4. 操作符:指针有解引用和地址操作符,而引用没有这些操作符,它直接代表所引用的对象。 5. 大小与存储:指针通常占用机器字长,而引用...
其次,引用不能是NULL,总是与一个有效的对象关联,而指针可以是NULL,这提供了更多的灵活性,但也增加了潜在的陷阱。在函数调用中,如果使用指针作为参数,函数内部对指针的修改(如重新分配内存)不会影响到函数...
本文将深入探讨引用指针这一特殊的概念,帮助开发者更好地理解和使用。 首先,让我们来回顾一下基本的指针概念。在C++中,指针是一个变量,它存储的是另一个变量的地址,也就是内存中的位置。通过指针,我们可以...
在C++中,当你声明一个对象数组时,你实际上是在内存中分配了连续的一块空间,每个位置存储一个对象。例如,假设我们有一个名为`Person`的类,我们可以这样声明一个`Person`对象数组: ```cpp Person persons[10]; ...
在C++编程中,智能指针和容器是两个非常重要的概念,它们极大地提高了代码的效率和安全性。本文将深入探讨这两个主题,并结合`CppTest`测试框架,展示如何编写测试用例来验证其正确性。 首先,让我们了解智能指针。...
一个对象的指针可以用来调用对象的方法(成员函数),并且可以传递对象的引用而不是复制整个对象,提高效率。例如,`MyClass *objPtr = new MyClass();`创建了一个对象,并通过指针引用它。 4. **动态内存管理**:...
数组和字典作为容器类,其复制涉及到浅复制和深复制的区别,而字符串是不可变对象,使用`copy`和`mutableCopy`会产生不同结果。 对于数组,如果数组元素是基本类型(如Int、Float),浅复制和深复制的效果可能相同...
引用在C++中是一个已初始化的别名,它在声明时必须绑定到一个已存在的对象,之后不能改变绑定的对象。声明引用的方式类似于指针,但不使用星号,而是使用"&&",如`int &ref = num;`。引用不是独立的存储单元,它本身...
6. **指针与容器**:在STL容器(如`std::vector`、`std::list`)中,我们可以存储指针来形成动态的对象集合,这样可以灵活地添加、删除和操作对象,而不必关心它们在内存中的位置。 在"指针的艺术(纯类文件)"中,...
这样的转换是安全的,因为基类引用可以指向派生类对象。 - **向下类型转换**:将一个基类对象转换为其派生类对象。这种转换需要显式的类型转换操作,且在运行时才能检查其合法性,因此可能存在类型错误的风险。 #...
C++中的指针和引用是两种非常重要的编程概念,它们都是用来间接访问内存中的对象,但有着本质的区别和各自的用途。 首先,指针是一个变量,它存储了一个内存地址,这个地址指向另一个对象。指针可以被赋值为NULL,...
首先,对象引用意味着变量实际上是对内存中对象的标签,而不是像盒子那样存储数据。当执行赋值语句时,Python会先在右侧创建或获取对象,然后将左侧的变量绑定到该对象,形成一种标注关系。 在比较对象时,我们有两...