我有一个一直在思考的问题。以这个特殊的类为例
class A{
private static ArrayList<String> listOne;
public Static ArrayList<String> getList()
{
return this.listOne
}
}
假设我有一个B类,它拥有一个使用listOne读取详细信息的方法。要查看数组列表,我需要首先获取列表的大小,以便我的代码知道数组列表何时结束。有两种方法可以做到这一点,一种是
int listSize = A.getList().size()
for(int count =0; count < listSize; count++)
{
// code to read through arraylist
}
或者我也可以用
for(int count=0; count < A.getList().size(); count++)
{
// code to read through arraylist
}
在内存和效率方面,哪种方法更好?此外,假设我正在递归地读取一个非常大的数组。为了简单起见,让我们假设递归读取此数组将导致堆栈溢出异常。在这种情况下,第一个方法在理论上会导致堆栈溢出发生的时间早于第二个方法,因为每个递归调用的堆栈帧都必须保持变量“listSize”的状态吗?
关于哪种方法更有效,我认为它们不会有任何明显的差异。正如Germann所说,根据JVM的不同,编译器甚至会对此进行优化。所以不要担心这种微不足道的差异。
我个人将使用第二种方法,因为它的代码行较少,而且我很懒。。。
但是,为什么两者都不用呢?
有一个超级酷的选择,它的名字是。。。
让我们将其与正常的for循环进行比较:
正常:
for (int i = 0 ; i < A.getList().size() ; i++ {
}
增强型:
for (String item : A.getList()) {
// Instead of using A.getList().get(i) to access the items, just use "item"!
}
看这多好啊!
这两个for循环之间的主要区别是
. iterator(). hasNext()
和. iterator(). Next()
循环。Iterable
和可能的Iterator
即可使用增强的for循环。不需要大小。增强的for循环有以下限制:
indexOf
不是很有效。两个循环相同。第二个是更好的编码,因为它减少了代码行。既然您提到需要遍历列表,那么最好使用增强的(for each)for循环。
Java中增强的循环和迭代器的优势是什么?
为什么增强for loop比普通for loop效率高
查看javap-verbose的结果:
0: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
3: invokevirtual #3 // Method java/util/ArrayList.size:()I
6: istore_1
7: iconst_0
8: istore_2
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
27: iconst_0
28: istore_2
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
52: return
第一种情况是:
9: iload_2
10: iload_1
11: if_icmpge 27
14: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
21: iinc 2, 1
24: goto 9
第二个:
29: iload_2
30: invokestatic #2 // Method A.getList:()Ljava/util/ArrayList;
33: invokevirtual #3 // Method java/util/ArrayList.size:()I
36: if_icmpge 52
39: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
42: iload_2
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: iinc 2, 1
49: goto 29
如您所见,它将在每次循环迭代期间获取列表及其大小。但是,这可能会被JIT优化,因此仅从编译的字节码来看结果并不明显。
创建自:
import java.io.*;
import java.util.*;
public class Z {
public static void main(String[] args) throws Exception {
int listSize = A.getList().size();
for(int count =0; count < listSize; count++) {
System.out.println(count);
}
for(int count =0; count < A.getList().size(); count++) {
System.out.println(count);
}
}
}
class A{
private static ArrayList<String> listOne = new ArrayList<>(Arrays.asList("1", "2", "3"));
public static ArrayList<String> getList()
{
return listOne;
}
}
我有一个非常消耗内存的程序,想使用-Xmx2048m为java jvm分配更多的最大内存。但在启动时,我得到一个“无法为对象堆保留足够的空间”错误。 当尝试多个值并发现我的最大值是时,它就开始了。但我喜欢分配2GB。在使用-Xmx1560m启动java进程后,我有6GB的物理内存,Taskmanager显示3400MB可用。 有人知道我为什么不能分配2GB吗?
问题内容: 我读过某个地方,Java可以在大约12条机器指令中为对象分配内存。这对我来说非常令人印象深刻。据我了解,JVM使用的技巧之一是按块预分配内存。我认为,这有助于最大程度地减少对操作系统的请求数量,这是非常昂贵的。但是,即使是CAS操作,在现代处理器上也可能要花费多达150个周期。 那么,谁能在Java中解释内存分配的实际成本以及JVM使用哪些技巧来加快分配速度? 问题答案: JVM为每个
问题内容: 使用以下Java选项启动Apache Tomcat(Atlassian Confluence)实例: 但是,我看到启动后,它很快就耗尽了虚拟服务器上可用的1GB内存中的大部分。 总消耗的内存(堆+ PermGen)是否不应该保持在使用- Xmx指定的值以下?这引起的问题之一是我无法使用关闭脚本关闭服务器,因为它试图生成具有256MB内存的JVM,该JVM因不可用而失败。 问题答案: T
问题内容: 是局部变量,将其存储在堆或堆栈中的何处? 问题答案: 在堆上。每当您用来创建对象时,它都会在堆上分配。
问题内容: 类B继承了类A。现在,当我们创建类型B的对象时,为B分配的内存是多少?是否包括A和B或任何其他内存分配过程? 问题答案: 当创建对象B时,假设调用了默认构造函数 然后,JVM分配具有更多或更少内容的对象: 在B中显式声明的每个字段都有足够的内存(每个字段通常大约4-8字节,但是类型和主机系统之间有很大差异) 对于A及其祖先继承的每个最终字段,都有足够的内存 足够的内存来包含对调度向量的
我有一个关于java如何处理未使用变量的问题。 假设我有以下代码: 那么我就不会在代码中使用notUsedVariable。该变量是否会被存储,或者java是否足够聪明,可以在编译时忽略该变量? 谢谢