`

Java六大问题你都懂了吗?

    博客分类:
  • java
阅读更多

一、到底要怎样进行初始化!

 

本问题讨论变量的初始化,所以先来看一下java中有哪些变量。

 

1.类的属性,或者叫作值域;

2.方法里的局部变量;

3.方法的参数

 

对于第一种变量,java虚拟机会自动进行初始化。如果给出了初始值,则初始化为该初始值;如果没有给出,则把它初始化为该类型变量的默认初始值。

 

所有对象引用类型变量默认初始值为null,即不指向任何对象。注意数组本身也是对象,所以没有初始化的数组引用在自动初始化后其值也是null。

 

对于两种不同的类属性,static属性和instance属性,初始化的时机是不同的。instance属性在创建实例时初始化,static属性在类加载,也就是第一次用到这个类的时候初始化。

 

对于第二种变量,必须明确的进行初始化,如果在没有初始化之前就使用它,编译器会抗议。如果初始化的语句在try块中或者if块中,也必须要让它在第一次使用前得到赋值,也就是说,把初始化语句放在只有if块的条件判断语句中编译器也会抗议,因为执行的时候可能不符合if后面的判断条件,如此一来初始化语句就不会被执行了,这就违反了局部变量使用前必须要初始化的规定。但如果在else块中也有初始化语句,就可以通过编译,因为无论如何,总有至少一条初始化语句会被执行,不会发生使用前未被初始化的事情。对于try-catch也是一样,如果只有在try块里才有初始化语句,编译部通过。如果在catch或finally里也有,则可以通过编译。总之,要保证局部变量在使用前一定被初始化了。所以,一个好的方法是在声明他们的时候就初始化他们,如果不知道初始化成什么值,就用默认值。

 

其实对于第三种变量,和第二种本质上是一样的,都是方法中的局部变量,只不过作为参数,肯定是被初始化过的,传入的值就是初始值,所以不需要初始化。

 

综上:1.类的属性,或者叫作值域(不需要进行初始化)

         2.方法里的局部变量(需要进行初始化)

         3.方法的参数(不需要进行初始化)

 

二、instanceof是神马?

 

instanceof是一个java的二元操作符,和==,>=,<是同一类东西。由于它是由字母组成的,所以也是java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。然而,这种做法通常是被认为没有好好利用面向对象的多态性,所以,使用instanceof在绝大多数情况下并不是推荐的做法,应当好好利用多态。

 

三、"=="和equals方法究竟有什么区别?

 

==操作符专门用来比较变量的值是否相等。比较好理解的一点是:对象变量其实是一个引用,它的值其实是指向对象所在的内存地址,而不是对象本身。a和b都使用了new操作符,意味着将在内存中产生两个内容为"foo"的字符串,既然是"两个",它们自然位于不同的内存地址。a和b的值其实是两个不同的内存地址的值,所以使用"=="操作符,结果会是false.诚然,a和b所指的对象,它们的内容都是"foo",应该是"相等",但是==操作符并不涉及到对象内容的比较。对象内容的比较,正是equals方法做的事。看一下Object对象的equals方法是如何实现的:

 

boolean equals(Object o)

{

 

     return this==o;

 

}

 

Object对象默认使用了==操作符。所以如果你自创的类没有覆盖equals方法,那你的类使用equals和使用==会得到同样的结果。同样也可以看出,Object的equals方法没有达到equals方法应该达到的目标:比较两个对象内容是否相等。因为答案应该由类的创建者决定,所以Object把这个任务留给了类的创建者。所以当你是用equals方法判断对象的内容是否相等,请不要想当然。因为可能你认为相等,而这个类的作者不这样认为,而类的equals方法的实现是由他掌握的。如果你需要使用equals方法,或者使用任何基于散列码的集合(HashSet,HashMap,HashTable),请察看一下java doc以确认这个类的equals逻辑是如何实现的。

 

 

四、final关键字到底修饰了什么?

 

final使得被修饰的变量“不变”,但是由于对象型变量的本质是引用,使得“不变”也有了两种含义:引用本身不变和引用指向的对象不变。

 

引用本身的不变:

 

final StringBuffer a = new StringBuffer("immutable");

 

final StringBuffer b = new StringBuffer("not immutable");

 

a=b;//编译期错误

 

 

引用指向的对象不变:

 

  final StringBuffer a=new StringBuffer("immutable");

 

  a.append(" broken!");//编译通过

 

 

可见,final只对引用的"值"有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。这很类似==操作符:==操作符只负责引用的"值"相等,至于这个地址所指向的对象内容是否相等,==操作符是不管的。理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象,不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它声明为final,意图使得它"永远不变".其实那是徒劳的。

 

 

五、我声明了什么!

 

String s = new String("Hello world!");

 

许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String,内容是"Hello world!".这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。这个语句声明的是一个指向对象的引用,名为"s",可以指向类型为String的任何对象,目前指向"Hello world!"这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象,我们只是声明了一个只能指向String对象的引用变量。所以,如果在刚才那句语句后面,如果再运行一句:String string = s;我们是声明了另外一个只能指向String对象的引用,名为string,并没有第二个对象产生,string还是指向原来那个对象,也就是,和s指向同一个对象。

 

 

六、String到底变了没有?

 

没有。因为String被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。请看下列代码:

  String s = "Hello";

  s = s + " world!";

  s所指向的对象是否改变了呢?从本系列第一篇的结论很容易导出这个结论。我们来看看发生了什么事情。在这段代码中,s原先指向一个String对象,内容是"Hello",然后我们对s进行了+操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量不再指向它了。通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为String对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都new一个String.例如我们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样做:

  public class Demo {

  private String s;

  public Demo {

  s = "Initial Value";}

  }

  而非

  s = new String("Initial Value");

  后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即StringBuffer.

<!-- baidu_tc block_end -->

 

 

 

分享到:
评论

相关推荐

    自考Java语言程序设计例题大全

    Java语言程序设计是计算机科学领域中的重要组成部分...在学习过程中,不仅要读懂代码,还应尝试修改和扩展,以提升问题解决能力。同时,理论知识与实践相结合,不断巩固,才能在自考Java语言程序设计的道路上取得成功。

    一个java写的简易飞机游戏.zip

    理解这些概念对于读懂源码至关重要。 二、游戏循环与事件处理 飞机游戏的核心是游戏循环,它通常由初始化、更新、渲染和处理用户输入四个阶段组成。在这个过程中,Java的`while`或`for`循环用于不断刷新游戏状态。...

    java版飞机大战源码-curated-article:收集各大技术社区网站每日热文

    Liziba-HashMap详解之一文读懂 : WinvenChang-4-2 Python面试常考算法 : 不止会写代码5-如何看待毕业一年半,就能拿了年薪70W大厂OFFER的专科生! : 落尘-001-常用的几种排序,卖菜的王婆已经学废了,你不来瞅瞅? :...

    Java中List for循环的6种写法总结(推荐)

    这种方法的优点是1、不必每次都计算List的大小,2、所有变量的作用域都遵循了最小范围原则,缺点是1、结果的顺序会反,2、看起来不习惯,不易读懂。这种方法适用于与显示结果顺序无关的地方,例如保存之前数据的校验...

    source insight解析命令行

    它支持多种编程语言,包括C、C++、Java等,并提供了诸如语法高亮、代码折叠、智能提示等功能,极大地提高了开发效率。 #### 二、Source Insight配置文件c.tom的作用 c.tom是Source Insight为C/C++语言提供的配置...

    最透彻的的Netty高性能原理和框架架构解析,使用文件和图形详细描述了netty的原理

    * 《高性能网络编程(六):一文读懂高性能网络编程中的线程模型》 * 《有关“为何选择 Netty”的 11 个疑问及解答》 * 《开源 NIO 框架八卦——到底是先有 MINA 还是先有 Netty?》 * 《选 Netty 还是 Mina:深入研究...

    编程及C&amp;C++初学者 FAQ.pdf

    #### 六、TC下常见的问题解决 ##### 用TC创建第一个程序 TC(Turbo C)是一个老旧但仍然流行的编译器。创建第一个程序通常涉及到编写“Hello World”的代码,然后在TC环境中编译和运行。 ##### TC的库路径设置 ...

    第13届蓝桥杯Python省赛真题-大学B组(完整题目&源码).zip

    这要求参赛者具备良好的逻辑分析能力,能够读懂题目要求,迅速构建模型,并用Python代码实现解决方案。 通过参加蓝桥杯Python省赛,不仅可以提升编程技能,还能锻炼逻辑思维和问题解决能力,对于未来的学习和职业...

    最透彻的的Netty高性能原理和框架架构解析.pdf

    2. **在线教程与博客**:如《高性能网络编程(五):一文读懂高性能网络编程中的 I/O 模型》、《高性能网络编程(六):一文读懂高性能网络编程中的线程模型》等。 3. **社区讨论与问答**:加入 Netty 的官方论坛或 ...

    Oracle XML Publisher技巧集锦.docx

    - **XML文件基本知识**:了解XML文件结构和语法,能够读懂简单的XML文档。 - **XSL-FO开发经验**:虽然不是必需的,但具备XSL-FO开发经验能更好地利用XMLP的高级功能。 - **Java开发经验**:对于需要集成Java应用...

    软考试题解析

    做题的关键是要读懂题干,理解题干中对算法的描述。这道题不难,基本是送分题。希赛的辅导综合答疑中特别强调了快速排序及时间复杂度。 栈 试题五考查了“栈”的掌握,要求考生平时多阅读程序,理解算法的精髓,...

    competitiveProgramming

    1. 读懂题目:理解问题背景、输入输出格式、约束条件。 2. 模型构建:将问题转化为数学模型或算法模型。 3. 策略选择:根据问题性质选择合适的算法和数据结构。 七、在线判题系统 熟悉各大在线编程平台,如...

    计算机求职意向简历.pdf

    *掌握计算机基本的硬件知识,能够解决一些常见的硬件问题 英语水平 基本技能:较强的听,说,读,写的能力 标准测试:国家大学英语四级,国家大学英语六级 个人能力 *学习能力较强,有一套适合自己学习方法,自学...

    PowerWord.exe

    2009年6月,对应Symbian、iPhone、Android和Java的等多个手机平台的手机版金山词霸3.0正式发布,金山词霸进军移动互联网领域。 2008年 2008年5月,金山携手谷歌联合推出《谷歌金山词霸合作版》,一款全免费、灵巧...

    算法导论(part1)

    书中的算法以英语加伪代码的形式给出,只要有一点程序设计经验的人都能读懂,并可以用任何计算机语言(如C/C++和Java等)方便地实现。在书中,作者将算法的讨论集中在一些比较现代的例子上,它们来自分子生物学(如...

    算法导论(part2)

    书中的算法以英语加伪代码的形式给出,只要有一点程序设计经验的人都能读懂,并可以用任何计算机语言(如C/C++和Java等)方便地实现。在书中,作者将算法的讨论集中在一些比较现代的例子上,它们来自分子生物学(如...

    嵌 入 式 系 统 的 分 层

    - **理解电路图和逻辑设计**:优秀的驱动工程师不仅需要能够读懂电路图,还应具备一定的硬件设计能力,如使用CPLD进行逻辑设计。 #### 三、驱动层 驱动层位于硬件层之上,负责连接硬件与操作系统,实现硬件功能的...

    android多媒体框架详细分析

    本文将尝试以清晰、易于理解的方式呈现这一架构的核心概念和技术细节,尽管其内容繁复且难以一读即懂,但希望能为开发者提供一个全面而深入的理解视角。 #### 三、Android多媒体架构 ##### 3.1 代码位置 Android...

Global site tag (gtag.js) - Google Analytics