我逐渐从C切换到java编程。虽然这样做,但我在理解以下场景时感到困惑: 我有以下Java代码:
ArrayList<Integer> myList = new ArrayList<Integer>();
for(int j = 0 ; j < 10 ;j++){
myList.add(j);
}
System.out.println(myList);
the o/p is:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
根据我的理解,我在这里有一个ArrayList类型的对象(myList)。
现在我尝试使用Array对象执行相同的操作:相同的代码,但用数组替换Arraylist:
int [] Arr = new int[]{1,2,3,4,5,6,7,8,9,10};
System.out.println(Arr);
我获得了垃圾值。为什么会这样? Array和ArrayList有什么区别? 与在C中一样,数组的名称是一种指针。 (IT具有第一个元素的地址),所以在Java中,对象的名称意味着什么? 地址或参考? 有什么不同? 为什么在Array和ArrayList的情况下会得到不同的结果?
答案 0 :(得分:3)
虽然问题的所有部分都已在不同的帖子中得到解答,但我想解决您的具体措辞。
首先,建议您将列表类型声明为接口,并将初始化作为实现 >:
List<Object> list = new ArrayList<Object>();
List<Object> list = new ArrayList<>(); // JDK 7 or later allows you to omit the generic type.
您可以使用多个实现(List
,ArrayList
...)实现LinkedList
接口。请参阅the collection tutorial。
Array和ArrayList有什么区别?
ArrayList
是类,请参阅API。它用作List
接口的实现,请参阅API。这些是 Java Collections Framework 的一部分。
数组不是类,因为ArrayList
是,但数组和类的实例都是对象。请注意上Array
,因为它是different class。
我获得了垃圾值。为什么会这样?
为什么在Array和ArrayList的情况下会得到不同的结果?
这与println
方法有关。它会自动调用传递给它的参数的toString
方法。 toString
类是为Object
类定义的,它超级所有其他类,因此它们都继承它。除非子类覆盖继承的方法,否则它将保留其超类的实现。让我们来看看它对Object
的作用:
public String toString()
返回的字符串表示形式 宾语。通常,toString方法返回一个字符串 &#34;文字表示&#34;这个对象。结果应该是简洁但是 信息表达,便于人们阅读。 是的 建议所有子类都覆盖此方法。
类Object的toString方法返回一个由名称组成的字符串 对象是实例的类,符号字符`@&#39;, 和哈希码的无符号十六进制表示 宾语。换句话说,此方法返回一个等于的字符串 价值:
getClass()。getName()+&#39; @&#39; + Integer.toHexString(hashCode())
强调我的。正如你所看到的那样,&#34;垃圾&#34;你在打印数组变量时得到的。由于数组不是类,因此它们不能覆盖此方法(数组可以调用Object
的所有方法,尽管它们不会以通常的方式对其进行子类化)。但是,AbstractCollection
的子类Object
会覆盖此:
public String toString()
返回此字符串表示形式 采集。字符串表示由一个列表组成 集合元素按迭代器返回的顺序, 用方括号括起来(&#34; []&#34;)。相邻的元素是分开的 人物&#34;,&#34; (逗号和空格)。元素转换为 字符串由String.valueOf(Object)。
由于ArrayList
是AbstractList
的子类,它是AbstractCollection
的子类(并且它们不会覆盖toString
),因此您可以获得简洁的结果但是信息丰富的表达方式对于一个人来说很容易阅读&#34;。
关于JVM如何处理数组有一些细节,但为了从开发人员的角度理解输出,这就足够了。
答案 1 :(得分:2)
在java中,变量的名称是对变量的引用(如果我们与c ++比较)。当您在println
上致电myList
时,您实际上会调用toString()
ArrayList
方法,该方法继承自Object
,但会被覆盖以提供有意义的打印。此方法继承自Object
,因为ArrayList
是一个类,所有类都扩展Object
,因此方法为toString
。
对于基元的本机数组,您没有此特性,因此您获得的是默认对象表示(虚拟内存地址)。
您可以尝试这样的事情:
public class TestPrint {
private String name;
private int age;
public TestPrint(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name;}
public int getAge() { return age; }
}
然后尝试println(new TestPrint("Test", 20));
- 这会打印类似于数组的内容。
现在,添加toString()
方法:
@Override
public String toString() {
return "TestPrint Name=" + name + " Age=" + age;
}
再次致电println(new TestPrint("Test", 20));
,您将获得TestPrint Name=Test Age=20
作为输出。
只是为了进一步解释为什么会发生这种情况 - 方法println
有一个重载,它接受Object
类型的东西。此方法的实现调用toString
来打印对象(当然这是非常示意性的解释)。
答案 2 :(得分:2)
在Java 一切是一个指针,但根据变量指向的内容,行为可能会发生变化。
int[] Arr = new int[]{1,2,3,4,5,6,7,8,9,10};
int[]
是一个基本类型的数组(不是类类型),并且它不包含有关其&#39;字符串表示的任何信息,所以当你想要打印变量时正如你所做的那样(System.out.println(Arr);
),打印出来的只是一个适合任何类型对象的字符串表示,就像它的哈希码一样(它不是垃圾)。
同时:
ArrayList<Integer> myList = new ArrayList<Integer>();
您正在创建(通用)类ArrayList&lt;&gt;的对象:这会覆盖方法(C中的函数)toString(),它指定如何优雅地打印ArrayList本身的内容(该方法非常基本:它只需遍历所有包含的项目,创建一个字符串并打印出来。)
当你调用System.out.println(myList);
时,隐式调用方法toString()(返回一个String),因此将打印由方法创建的字符串,如图所示。