http://wenku.baidu.com/view/0d4f563c0912a21614792928.html
Java基础复习笔记03我们不太注意的陷阱 刘岩 Email:suhuanzheng7784877@163.com 1. 虚拟机对字符串的处理 虚拟机是将字符串直接量(不用new声明的)对象放到一个对象池中去缓存的,第一次使用的时候会将其放入池中,如果下次有其他变量访问一摸一样的直接量的话直接从对象池中去取该直接量,而不是又再生成一个对象。一般该池中的对象都不会被垃圾回收器回收。 比如: String str1 = "1"; String str2 = "1"; 实际上这段代码仅仅创建了一个字符串直接对象,保存在对象池中,池中对象就是”1”。str1和str2指向了该对象池的对象位置。 2. 编译时能确定的值 在编译时就能确定的值,在编译的时候就能够确定是否创建新的对象池对象。比如: String str3 = "suhuanzhen123"; String str4 = "suhuanzhen" + 1 + "2" + "3"; System.out.println(str3 == str4); 实际上str3和str4在内存池中都是指向了"suhuanzhen123"这个字符串对象,所以输出时true。因为str4在编译期间就能确定值是suhuanzhen123,所以JVM不会再创建新的对象。直接从对象池中去取。 3. 在编译期间不能确定的值 如果字符串的拼接包含了函数、变量等等编译时不确定因素,那么此时就不能指向对象池中的变量了。比如 String str5 = "suhuanzhen123"; String str6 = "suhuanzhen" + "1".length() + "2" + "3"; System.out.println(str5 == str6); 4. 在编译时就能确定值的字符串变量创建值 比如代码 String str6 = "suhuanzhen" + "1" + "2" + "3"; 实际上仅仅创建了一个对象——suhuanzhen123,缓存到对象池。 5. StringBuilder和StringBuffer的区别 一般在单线程的系统环境下优先使用StringBuilder,因为它是非线程安全的。而在多线程的环境下,比如Web系统,优先使用StringBuffer,因为它当中绝大部分方法都使用了synchronized进行修饰,保证了多线程环境下的线程安全问题。 6. 字符串之间的比较 用一个线程池的常量对象和一个变量、函数返回值比较直接使用==其实就可以了比如: String jqgridparams = request.getParameter("jqgridparams"); if (jqgridparams != null) { if ("getparams" == jqgridparams) { 文档冲亿季,好礼乐相随mini ipad移动硬盘拍立得百度书包 2 / 14 //„„„„„„„„ } } 更直观一点就是 static String getStr(){ return "suhuanzhen123"; } public static void main(String[] args) { String str7 = getStr(); System.out.println("suhuanzhen123" == str7); } 输出的是true; 如果是2个字符串变量之间比较就不能用==了 String str7 = getStr(); String str8 = new String("suhuanzhen123"); System.out.println(str8 == str7); 输出false。 应该用 System.out.println(str8.equals(str7)); 7. 赋值语句的类型提升 上图程序实际上就是类型自动提升发生了错误,num本身是int型,而num = num+33.567;表达式中使用了double类型的数值,那么此表达式会自动向最高级别的基本类型转型,但是呢num自身是int,会提示不能向上转换的编译错误。如果程序这么写 public static void main(String[] args) { int num = 1; double numDoub = num+33.567; } 就不会报错了。 赋值运算中基本数据转型的级别从高到低排序是String->double->float->long->int->chart、short->byte。 如果运算中含有字符串变量,那么二话不说,此表达式所有的运算最后的返回值就是一个字符串了,比如 int num = 1; double numDoub = num+33.567; String str = num+numDoub+""; 所以最高级别还是String。 8. 符合运算符中的隐式类型转换 3 / 14 在符合运算符中实际上存在着一个隐藏的类型转换 int sum =1; sum += 30.44; System.out.println(sum); 实际上会输出31,如果是之前的例子 int sum =1; sum = sum+30.44; 编译器是会报错的。那么+=实质上是什么意思呢!就是 sum += 30.44; 等价于 sum = (int)(sum+30.44); 也就是说符合运算符自身还隐式地包含了一个强制转型的动作。这样做有时候会失去精度以及高位段位。 short sum =9999; sum += 999999999.9999999; System.out.println(sum); 输出-3826 9. 泛型引起的陷阱 List list = new ArrayList(); list.add("1"); list.add(2); list.add("3q"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } List<String> listNew = list; for (String strNew : listNew) { System.out.println(strNew); } 第一个循环输出无任何问题,第二个循环报出转型异常。换几话说,集合本身可以存储不同类型元素的对象的,只不过自从JDK1.5之后出现了泛型,才使我们很多人觉得集合变量仅仅能存一种类型的对象元素。泛型是为了在编译时更好的排除类型转换带来的繁琐检查。而在大多数应用中确实集合中就是同类型的元素。而泛型配合上加强的新循环,它会强制进行单一类型的转型操作。所以第二个循环的的结果就是 java.lang.Integer cannot be cast to java.lang.String 泛型还有可能引起擦除,如下: class MyT<PK extends Number> { private PK id; public PK getId() { return id; 4 / 14 } public void setId(PK id) { this.id = id; } } public class TTrap { /** * @param args */ public static void main(String[] args) { MyT<Integer> my = new MyT<Integer>(); my.setId(100); System.out.println(my.getId() + ":" + my.getId()); MyT mynew = my; System.out.println(mynew.getId() + ":" + mynew.getId()); } } 在mynew.getId()这一句中实际上编译器这时候仅仅将它识别为Number了,直接当做Integer使用会报错,除非强制转型方可当做Integer来使用。这里就相当于将泛型信息擦除了,程序只有到了真正运行时环境下才能把其当做Integer来用,编译期间他不认识其实质面目。Java擦除泛型信息是将该对象所有的泛型信息全部擦除掉,不仅仅是那个传入的泛型,如果此类本身也定义了其他泛型相关的方法、变量,统统没有了! class MyTT<PK extends Number> { private PK id; private List<String> list; public PK getId() { return id; } public void setId(PK id) { this.id = id; } public List<String> findRows() { list = new ArrayList<String>(); list.add("步惊云"); list.add("聂风"); 5 / 14 return list; } } public static void main(String[] args) { MyTT<BigInteger> myTT = new MyTT<BigInteger>(); for (String str : myTT.findRows()) { System.out.println(str); } MyTT my2 = myTT; List listNoString = my2.findRows(); } 执行MyTT my2 = myTT;实际上是擦除了泛型的所有信息,就连之前定义的public List<String> findRows()也被无辜的擦除了泛型信息。编译时只能认识findRows方法返回的是List而不是List<String>。 10. 遇到含有.的字符串分割成字符串数组 public static void main(String[] args) { String str = "www.google.cn"; String[] array = str.split("\\."); System.out.println(array.length); } 直接用String[] array = str.split(".");不起作用,因为”.”代表可以匹配任意字符,必须转义。 11. 什么样的对象存在线程安全问题 当我们刚学Java的时候不会考虑多线程的问题,在自己的IDE环境下运行成功了就行了,不会考虑并发使用此程序的时候会出现什么情况。等做程序员一段时间后发现自己编写的程序确实存在,多线程安全问题。之后走火入魔似地给自己写的方法加上synchronized。其实我们有时候没搞懂什么情况下会出现线程安全的问题。如果我们开发的是单机版的C/S应用系统,客户的计算机就是软件产品的服务器,那么会不会有并发现象呢?只要不是恶意恶搞你的软件,一般一个客户就对应着一个服务,这个时候不存在并发访问的问题,所以一般情况下不会考虑多线程的问题。如果在基于B/S的Web系统中,可能服务器是一台机器,世界各地的客户都来访问你开发的系统,为这些世界各地的客户提供服务,这个时候可能会出现线程安全的问题。为什么说可能,而不是一定呢?如果你的所有的类和类之间的调用都是通过new一个新的对象为之服务(极端情况下还真有),那么new实际上是在服务器内存中新开辟一块内存空间承载对象,那么这种极端情况是不存在线程安全问题的,只要您的服务器内存极大——1TB内存,每日客户量在2万人左右,估计运行1个月应该差不多没什么问题。不过考虑成本,一般没这样高级的服务器让这种极端的程序运行吧。那么最多的就是类之间的调用不是永远的new一个新的出来,而是为了节省资源,使用对象缓存池或者干脆整个应用软件调用比较频繁的类就使用一个单例对象就得了,每次使用这个对象都是原来已有的,不必在内存新建一个,这样垃圾回收器的工作量也不会那么大。而恰恰是这个时候,这个复用的
分享到:
相关推荐
Java是一种广泛使用的面向对象的编程...以上只是Java常识的冰山一角,深入学习Java还需要掌握更多高级特性和最佳实践,如设计模式、并发编程策略、数据库连接、Spring框架等。不断学习和实践,才能成为真正的Java专家。
Java是一种高级的、面向对象的编程语言,由Sun Microsystems公司在1995年推出,它以其跨平台、动态Web计算的特性受到了广泛欢迎。Java语言的设计目标是具有简单性、面向对象、健壮性、安全性、高效性以及可移植性。...
### 0854考研复试综合面试速成(1):C/C++/Java常识 #### C语言与C++语言的基础对比 - **C语言**: - 面向过程,强调算法和数据结构。 - 程序设计侧重于如何通过一系列步骤处理输入并产生输出。 - 不具备类、...
Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现为Oracle公司)于1995年发布。它以其“一次编写,到处运行”的特性而闻名,因为Java编写的程序可以在任何支持Java的平台上运行,无需重新编译。Java...
Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现为Oracle公司)于1995年发布。这本书“Java基础知识电子书”是为初学者准备的,旨在帮助他们理解和掌握Java编程的基本概念和语法。 Java的基础知识...
符合J2EE的MVC开发模式结合工厂模式,代码通俗易懂,只要稍微有点java常识的人就可以使用本软件来开发大型的java项目,本工作室的开发团队汲取多位资深开发人员多年的项目开发经验开发出本软件,目前使用本软件的...
符合J2EE的MVC开发模式结合工厂模式,代码通俗易懂,只要稍微有点java常识的人就可以使用本软件来开发大型的java项目,本工作室的开发团队汲取多位资深开发人员多年的项目开发经验开发出本软件,目前使用本软件的...
阿里大牛梁飞编写的《Java并发编程常识》PPT,深入浅出地讲解了这个主题,对开发者来说是一份宝贵的资源。 首先,我们来探讨Java并发编程的基础概念。并发是指多个执行单元(线程或进程)在同一时间间隔内同时进行...
在"JAVA常识"这个压缩包中,我们可能会看到以下知识点: 1. **Java基础**:包括变量、数据类型、运算符、控制结构(如if-else、switch、for、while循环)、类与对象、封装、继承、多态等面向对象编程的基础概念。 ...
1. **Java常识** - 牛客知识总结:牛客网是一个提供在线编程练习和面试题库的平台,其中涵盖了大量的Java基础知识,如语法、面向对象、异常处理、集合框架等。 2. **多态规则** - 多态性是面向对象的三大特性之...
由于提供的文件内容存在 OCR 扫描错误和格式...由于原始文件内容混乱,以上知识点是根据可识别的信息进行推测,并结合 Java 常识整理出的可能的内容。在实际操作中,需要清理和纠正扫描错误,并补充可能缺失的信息。
##### 1.8 Java常识语法 - Java语言的一些基本概念和规则,包括变量、数据类型、运算符等。 ##### 1.9 注释、标识符、命名规范 - **注释**:用来解释代码,提高代码可读性。 - 单行注释:使用`//`。 - 多行注释...
内有学习别人介绍学习JAVA的经验及新手常犯的错误
采用java技术构建的一个管理系统。整个开发过程首先对系统进行需求分析,得出系统的主要功能。接着对系统进行总体设计和详细设计。总体设计主要包括系统功能设计、系统总体结构设计、系统数据结构设计和系统安全设计...
Java编程基础常识主要涵盖以下几个关键知识点: 1. **Java编程语言**:Java是一种强类型、面向对象的编程语言,由Sun Microsystems开发,并于1995年发布。它旨在提供强大的功能,易于学习且适用于跨平台开发。Java...
【JAVA开发常识】 Java开发是信息技术领域中广泛采用的一种编程语言,其强大的特性和灵活性使得它成为企业级应用开发的首选。以下是一些关键的知识点: 1. **软件开发流程**: 开发过程通常遵循瀑布模型,包括...
基础概念与常识 Java 语言有哪些特点? JVM vs JDK vs JRE JVM JDK 和 JRE 什么是字节码?采用字节码的好处是什么? 为什么说 Java 语言“编译与解释并存”? Oracle JDK vs OpenJDK Java 和 C++ 的区别? 基本语法 字符...