- 浏览: 697444 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
yzs5273:
没什么用。都试过了
WIN7下CS不能全屏的解决方法 -
di1984HIT:
不错,学习了
读取本地计算机中的安装程序列表 -
ffedu:
[flash=200,200][url][img][list] ...
linux/unix中如何用find命令详解,非常详细的介绍,比man find强100倍(转) -
lintghi:
...
Log4j使用相对路径指定log文件及使用总结 -
nick.s.ni:
唉,Java中引用的包没有介绍啊,如果数据库用UTF-8的格式 ...
Oracle 中Java 对象与PL/SQL类型的映射及使用(转)
1常量池:
在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。
2 字符串对象的创建:
由于字符串对象的大量使用[一般在heap(堆)分配内存],Java中为了节省内存空间和运行时间 [如比较字符串时,==比equals()快], 在编译阶段就把所有的字符串文字放到一个字符串池[pool of literal strings]中,而运行时字符串池成为常量池的一部分。字符串池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间。我们知道,对两个引用变量,使用==判断它们的值[引用]是否相等,即指向同一个对象。
现在看String s = new String("abc");语句,这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将pool中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s持有。ok,这条语句就创建了2个String对象。
String s1 = new String("abc") ;String s2 = new String("abc") ;if( s1 == s2 ){ }//false
//创建了几个String Object? [三个,pool中一个"abc",heap中2个。]
只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。
另外
1.==表示引用自同一对象,equals()表示值相等。
String str1 = "abc";引用的对象在栈(或者叫String池)中。
String str1 =new String ("abc"); 引用的对象在内存/堆中。
2.String str1 = "string";在栈中
String str3 = "str";在栈中
String str4 = "ing";在栈中
String str2 = str3+str4; 在堆中,因为+号的作用是返回另外一个新建的String对象,而不是在栈中找string这个值。
String str2 = "str"+"ing";在栈中。str1==str2为true。
但是有一种情况需要引起我们的注意。请看下面的代码:
public class StringStaticTest {
public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {
String s = A + B; // 将两个常量用+连接对s进行初始化
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
}
这段代码的运行结果如下:
s等于t,它们是同一个对象
原因是在上面的例子中,A和B都是常量,值是固定的,因此s的值也是固定的,它在类被编译时就已经确定了。也就是说:String s=A+B; 等同于:String s="ab"+"cd";
我对上面的例子稍加改变看看会出现什么情况:
public class StringStaticTest {
public static final String A; // 常量A
public static final String B; // 常量B
static {
A = "ab";
B = "cd";
}
public static void main(String[] args) {
// 将两个常量用+连接对s进行初始化
String s = A + B;
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
}
它的运行结果是这样:
s不等于t,它们不是同一个对象
只是做了一点改动,结果就和刚刚的例子恰好相反。我们再来分析一下。A和B虽然被定义为常量(只能被赋值一次),但是它们都没有马上被赋值。在运算出s的值之前,他们何时被赋值,以及被赋予什么样的值,都是个变数。因此A和B在被赋值之前,性质类似于一个变量。那么s就不能在编译期被确定,而只能在运行时被创建了。
最后我们再来说说String对象在JAVA虚拟机(JVM)中的存储,以及字符串池与堆(heap)和栈(stack)的关系。我们首先回顾一下堆和栈的区别:
栈(stack):主要保存基本类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据可以共享,速度仅次于寄存器(register),快于堆。
堆(heap):用于存储对象。
我们查看String类的源码就会发现,它有一个value属性,保存着String对象的值,类型是char[],这也正说明了字符串就是字符的序列。当执行String a="abc";时,JAVA虚拟机会在栈中创建三个char型的值'a'、'b'和'c',然后在堆中创建一个String对象,它的值(value)是刚才在栈中创建的三个char型值组成的数组{'a','b','c'},最后这个新创建的String对象会被添加到字符串池中。
如果我们接着执行String b=new String("abc");代码,由于"abc"已经被创建并保存于字符串池中,因此JAVA虚拟机只会在堆中新创建一个String对象,但是它的值(value)是共享前一行代码执行时在栈中创建的三个char型值值'a'、'b'和'c'。
String s0=”kvill”;
String s1=”kvill”;
String s2=”kv” + “ill”;
System.out.println( s0==s1 );
System.out.println( s0==s2 );
String s1 = "a"; String s2 = "b"; String s3 = s1+s2 +"c";
四个对象
另外:
字符串的+运算和字符串转换
字符串转换和串接是很基础的内容,因此我以为这个问题简直就是送分题。事实上,我自己就答错了。
String str = new String("jf"); // jf是接分
str = 1+2+str+3+4;
一共创建了多少String的对象?[我开始的答案:5个。jf、new、3jf、3jf3、3jf34]
首先看JLS的有关论述:
一、字符串转换的环境[JLS 5.4 String Conversion]
字符串转换环境仅仅指使用双元的+运算符的情况,其中一个操作数是一个String对象。在这一特定情形下,另一操作数转换成String,表达式的结果是这两个String的串接。
二、串接运算符[JLS 15.18.1 String Concatenation Operator + ]
如果一个操作数/表达式是String类型,则另一个操作数在运行时转换成一个String对象,并两者串接。此时,任何类型都可以转换成String。[这里,我漏掉了"3"和"4"]
如果是基本数据类型,则如同首先转换成其包装类对象,如int x视为转换成Integer(x)。
现在就全部统一到引用类型向String的转换了。这种转换如同[as if]调用该对象的无参数toString方法。[如果是null则转换成"null"]。因为toString方法在Object中定义,故所有的类都有该方法,而且Boolean, Character, Integer, Long, Float, Double, and String改写了该方法。
关于+是串接还是加法,由操作数决定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中举的一个jocular little example,真的很无趣。]
下面的例子测试了改写toString方法的情况.。
class A
{ int i = 10;
public static void main(String []args)
{ String str = new String("jf");
str += new A();
System.out.print(str);
}
public String toString(){ return " a.i ="+i+"\n"; }
}
三、字符串转换的优化
按照上述说法,str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象:
1+2 =3,then 3→Integer(3)→"3" in pool? [假设如此]
"3"+str(in heap) = "3jf" (in heap)
"3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3"
"3jf3"+4 create "4" in pool
then "3jf34"
这里我并不清楚3、4转换成字符串后是否在池中,所以上述结果仍然是猜测。
为了减少创建中间过渡性的字符串对象,提高反复进行串接运算时的性能,a Java compiler可以使用StringBuffer或者类似的技术,或者把转换与串接合并成一步。例如:对于 a + b + c ,Java编译器就可以将它视为[as if]
new StringBuffer().append(a).append(b).append(c).toString();
注意,对于基本类型和引用类型,在append(a)过程中仍然要先将参数转换,从这个观点看,str = 1+2+str+3+4;创建的字符串可能是"3"、"4"和"3jf34"[以及一个StringBuffer对象]。
现在我仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象,。或许,这个问题不需要过于研究,至少SCJP不会考它。
3、这又不同:str = "3"+"jf"+"3"+"4";
如果是一个完全由字符串文字组成的表达式,则在编译时,已经被优化而不会在运行时创建中间字符串。测试代码如下:
String str1 ="3jf34";
String str2 ="3"+"jf"+"3"+"4";
if(str1 == str2) { System.out.println("str1 == str2"); }
else { System.out.println("think again"); }
if(str2.equals(str1)) System.out.println("yet str2.equals(str1)");
可见,str1与str2指向同一个对象,这个对象在pool中。所有遵循Java Language Spec的编译器都必须在编译时对constant expressions 进行简化。JLS规定:Strings computed by constant expressions (?15.28) are computed at compile time and then treated as if they were literals.
对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象。注意,“创建多少对象”的讨论是说运行时创建多少对象。
BTW:编译时优化
String x = "aaa " + "bbb ";
if (false) { x = x + "ccc "; }
x += "ddd ";
等价于: String x = "aaa bbb "; x = x + "ddd ";
发表评论
-
Transfer
2017-06-29 23:03 0Find connections count: ... -
Discover the Mystery of Metaspace
2017-06-23 16:47 0The JDK 8 HotSpot JVM is now u ... -
Command Line JMX Client
2014-12-29 13:12 2595Command Line Parser: GNUComman ... -
Something about JVM class loading and initialization
2014-05-09 10:04 1031Class loading stages: Loadin ... -
When a class is loaded and initialized in JVM - Java
2014-05-08 19:09 987from: http://javarevisited.blo ... -
【深入Java虚拟机】之四:类加载机制
2014-05-08 15:12 899转载请注明出处:http://blog.csdn.net/n ... -
Java Reflection - Dynamic Class Loading and Reloading
2014-05-08 12:04 941From: http://tutorials.jenkov. ... -
Java 类加载与初始化
2014-02-19 19:12 808转载自:http://www.cnblogs.c ... -
javax.management.StandardMBean: When and Why. (Reposted)
2013-12-26 15:34 1084Q: When is a Standard MBean no ... -
JVM调优的"标准参数"的各种陷阱(转)
2013-11-11 19:55 2050From: http://hllvm.group.itey ... -
Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
2013-11-11 11:05 1017(From: http://www.oracle.com/ ... -
An article about TLAB
2013-11-11 10:57 756(From: https://blogs.oracle.co ... -
【JVM】HotSpot JVM内存管理和GC策略总结(转)
2013-11-07 23:39 591JVM的相关知识是学习java高级特性必须要去深入学习的。平 ... -
jstat分析VM内存
2013-11-07 16:41 904Jstat 是JDK自带的一个轻量级小工具。全称“Java ... -
java的GridBagLayout网格包布局管理器使用详解 (转)
2013-11-01 16:44 0网格包布局管理是最复 ... -
java动态跟踪分析工具BTrace实现原理
2013-09-01 12:34 1267转自:http://kenwublog.com ... -
Java synchronize用法(转)
2012-11-05 00:20 1207在多个并发线程之间共用资源,就需要进行同步处理。Java虚拟机 ... -
Interview material collection
2012-07-09 23:05 11891. Why can't static methods be ... -
不要重复 DAO!(转)
2011-12-29 22:17 1241使用 Hibernate 和 Spri ... -
JVM 诊断工具(转)
2011-11-25 12:00 17611.jinfo 描述:输出给定 java 进程所有的配置信 ...
相关推荐
标题“JAVA错误收集”指的是Java编程中遇到的异常和错误的汇总,这通常涉及到程序运行时的错误处理和调试过程。在Java中,错误(Error)是程序无法处理的严重问题,比如系统资源耗尽或者硬件故障,而异常(Exception...
- **heap space** 主要用于存储Java运行时的对象,这些对象会在垃圾收集(GC)过程中被清理。 - **错误日志**:`java.lang.OutOfMemoryError: Java heap space` 和 `java.lang.OutOfMemoryError: GC overhead ...
而`heapdump`文件则是JVM在运行过程中,通过Java的`jmap`命令或者`VisualVM`等工具手动触发生成的,它记录了JVM堆内存的详细状态,包括对象实例、类加载器、垃圾收集信息等。`ha`(Heap Analysis)工具则用于分析`...
在Java编程环境中,当遇到“Java进程CPU占用率高”的问题时,这通常意味着Java应用程序在执行过程中消耗了大量计算资源,可能导致系统响应变慢,甚至出现性能瓶颈。本篇文章将深入探讨这个问题,并提供相关解决方案...
本篇文章将深入探讨分布式Java应用的基础知识和实践技巧,帮助开发者理解和掌握分布式系统的核心概念。 1. 分布式系统概述 分布式系统是由多个独立的计算机节点通过网络连接,共同协作完成一项任务。在Java中,主要...
1. **JAVA后台开发**:JAVA因其面向对象的特性、强大的类库支持和跨平台能力,在Web应用开发中广泛应用。在自动新闻采集系统中,JAVA用于编写服务器端逻辑,处理HTTP请求,与数据库交互,进行数据处理和计算。通常会...
在本篇文章中,我们将深入探讨如何利用VisualVM进行堆dump分析,以及它在处理"jvm.gc"(Java垃圾收集)问题上的应用。 首先,让我们了解什么是堆dump。在Java应用程序运行过程中,堆内存是用于存储对象的主要区域。...
usb.devices : 这个可选包收集了用 jUSB API 访问不同 USB 设备的 Java 代码,包括柯达数码相机和 Rio 500 MP3 播放器。这些 API 经过特别编写以简化访问特定 USB 设备的过程,并且不能用于访问其他设备。这些 API ...
本篇文章将基于提供的文件信息,深入解析线上问题调查中常用的Linux性能检测工具及JVM性能相关命令,并提供详细的解释与应用场景。 #### Linux性能检测工具 **1. CPU性能检测** ##### 基本概念 - **上下文切换**...
- **堆内存**:Java对象主要存储在堆内存中,分为新生代(Young Generation)和老年代(Tenured Generation)。新生代用于存放新生的对象,通过Minor GC进行垃圾回收;老年代存放长期存活的对象,通过Major GC或...
4. **内存分析**: 分析内存分配,查找内存泄漏,通过对象分配视图和垃圾收集日志来优化内存管理。 5. **线程分析**: 查看线程状态,定位死锁和阻塞,帮助解决多线程问题。 6. **数据库监控**: 检查SQL语句的执行...
在这个例子中,程序创建了大量的1MB大小的对象,并将其添加到列表中。通过使用上述工具,我们可以监测程序在运行过程中的内存消耗情况、线程活动情况以及垃圾回收行为等。 ### 结论 通过本文介绍的JVM命令工具,...
- 监控与日志:通过Prometheus、Grafana等工具监控系统性能,利用Logstash、ELK堆栈收集分析日志。 8. **持续集成/持续部署(CI/CD)** - Jenkins、GitLab CI/CD等工具,实现自动化测试、构建和部署,确保代码质量...
10. **监控与日志**:集成Spring Boot Actuator和ELK(Elasticsearch、Logstash、Kibana)堆栈,实现微服务的性能监控和日志收集分析。 通过上述步骤,我们可以构建一个基于Spring的微服务系统,该系统充分利用了...
10. **监控与日志**:Prometheus、Grafana用于系统性能监控,ELK (Elasticsearch, Logstash, Kibana)堆栈用于日志收集和分析,帮助开发者及时发现和解决问题。 11. **安全**:开源安全库如OAuth2、JWT(JSON Web ...
通过ELK(Elasticsearch、Logstash、Kibana)堆栈收集和分析应用日志,配合Prometheus和Grafana进行性能监控,有助于快速定位问题和优化系统。 10. **测试策略** 使用JUnit进行单元测试,Mockito模拟外部依赖,...