Java 基础总结(一)

本文参见:http://www.cnblogs.com/dolphin0520/category/361055.html

 

1. String,StringBuffer,StringBuilder

    1). 对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象

    2). StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized

    3). 对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+"love"+"java"; 的字符串相加,在编译期间便被优化成了"Ilovejava"。这个可以用javap -c命令反编译

         生成的class文件进行验证。对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。

    4). String、StringBuilder、StringBuffer三者的执行效率:StringBuilder > StringBuffer > String

         当然这个是相对的,不一定在所有情况下都是这样。比如String str = "hello"+ "world"的效率就比 StringBuilder st = new StringBuilder().append("hello").append("world")要高。

       因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:

         当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;

     当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。

    5). "hello"+2在编译期间就已经被优化成"hello2" ;  由于有符号引用的存在,所以 String c = b + 2 ; 不会在编译期间被优化,不会把b+2当做字面常量来处理的;

          对于被final修饰的变量,会在class文件常量池中保存一个副本,也就是说不会通过连接而进行访问,对final变量的访问在编译期间都会直接被替代为真实的值。那么String c = b + 2;

          在编译期间就会被优化成:String c = "hello" + 2; 

          虽然将b用final修饰了,但是由于其赋值是通过方法调用返回的,那么它的值只能在运行期间确定 

          String str = new String("abc") : 在类加载的过程中,确实在运行时常量池中创建了一个"abc"对象,而在代码执行过程中确实只创建了一个String对象。

          详细内容请阅读:http://www.cnblogs.com/dolphin0520/p/3778589.html

2. hashcode()

    1). 如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;如果两个对象的hashcode值

         不等,则equals方法得到的结果必定为false;如果两个对象的hashcode值相等,则equals方法得到的结果未知。

    2). 在重写equals方法的同时,必须重写hashCode方法


3. 自动装箱和拆箱:

    1). 在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。

    2). 在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。

    3). Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。

    4). Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。Double、Float的valueOf方法的实现是类似的。

    5). Boolean i1 = false; Boolean i2 = false; System.out.println(i1==i2); // 打印结果为true。Boolean中定义了两个静态成员变量。

         public static final Boolean TRUE = new Boolean(true);

         public static final Boolean FALSE = new Boolean(false);

     6). 当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。

     7). 谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:

          a. 第一种方式不会触发自动装箱的过程;而第二种方式会触发;

          b. 在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

 

4. == 和 equal

    1). 对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;如果作用于引用类型的变量,则比较的是所指向的对象的地址

  2). 对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;诸如String、Date等类对

         equals方法进行了重写的话,比较的是所指向的对象的内容。

 

5. 访问修饰符:

    1). 修饰类:

         a. 默认访问权限(包访问权限):用来修饰类的话,表示该类只对同一个包中的其他类可见。

         b. public:用来修饰类的话,表示该类对其他所有的类都可见。

    2). 修饰类的方法和变量

         a. 默认访问权限(包访问权限):如果一个类的方法或变量被包访问权限修饰,也就意味着只能在同一个包中的其他类中显示地调用该类的方法或者变量,在不同包中的类中不能显示地调用该类的

             方法或变量。

         b. private:如果一个类的方法或者变量被private修饰,那么这个类的方法或者变量只能在该类本身中被访问,在类外以及其他类中都不能显示地进行访问。

         c. protected:如果一个类的方法或者变量被protected修饰,对于同一个包的类,这个类的方法或变量是可以被访问的。对于不同包的类,只有继承于该类的类才可以访问到该类的方法或者变量。

         d. public:被public修饰的方法或者变量,在任何地方都是可见的。

 

6. JVM内存区域划分:

    1). 首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在整个程序执行

         过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。

    2). 程序计数器(Program Counter Register): 也有称作为PC寄存器。虽然JVM中的程序计数器并不像汇编语言中的程序计数器一样是物理概念上的CPU寄存器,但是JVM中的程序计数器的

         功能跟汇编语言中的程序计数器的功能在逻辑上是等同的,也就是说是用来指示 执行哪条指令的。在JVM规范中规定,如果线程执行的是非native方法,则程序计数器中保存的是当前需要

         执行的指令的地址;如果线程执行的是native方法,则程序计数器中的值是undefined。

     由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。

    3). Java栈 : Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池

       (运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建

        一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。

    4). 本地方法栈 : 本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,

         并没有对本地方法栈的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

    5). 堆 : Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。

    6). 方法区 : 方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及

         编译器编译后的代码等。在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。

      在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件

        常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

 

7. Java 如何有效地避免OOM:善于利用软引用和弱引用

    1). 强引用(StrongReference): 强引用就是指在程序代码之中普遍存在的,只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出

         OutOfMemory错误也不会回收这种对象。

    2). 软引用(SoftReference): 软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候

         JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。

    3). 弱引用(WeakReference): 弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference

         类来表示。

    4). 虚引用(PhantomReference): 虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,

         则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

 

8. 使用maven管理jar可能会引起jar冲突,可以通过 

    <exclusions>
        <exclusion>
            <artifactId>slf4j-log4j12</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>

   来排除某个jar的依赖,避免多处引用不同版本jar。

   可以通过 intellij idea 查看具体哪些jar冲突。选中项目,右键 show dependency,然后搜索冲突的jar

 

 

posted @ 2015-06-27 18:51  Jtianlin  阅读(472)  评论(0编辑  收藏  举报