zoukankan      html  css  js  c++  java
  • Java复习1

    java基础类型

    • 整形:int,long,short,byte
    • 浮点型:double,float
    • 布尔类型:boolean
    • 字符类型:char

    int 4个字节
    long 8个字节
    short 2个字节
    byte 1个字节

    double 8个字节
    float 4个字节

    boolean 1个bit, 八分之一个字节

    char 2个字节

    引用类型

    • 强引用
      • 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
    • 软引用
      • 如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
      • 可以用来内存敏感的高速缓存
      • 可以配合referenceQueue一起使用,当引用被回收的时候,JAVA 虚拟机就会把这个软引用加入到与之关联的引用队列中。
    • 弱引用
      • 与软引用类似,弱引用与软引用的区别在于:更短的生命周期,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存
      • 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java 虚拟机就会把这个弱引用加入到与之关联的引用队列中
    • 虚引用
      • 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

    包装类型:

    • 由于java有基础类型,基础类型本身并不是对象,所以其实本身违反了java的面向对象思想,所以将基础数据类型转换对应的包装类型,那么就可以操作基础类型像操作对象一样了。
    基础类型 包装类型
    boolean Boolean
    char Character
    long Long
    byte Byte
    int Integer
    short Short
    float Float
    double Double
    • 自动拆箱和装箱
      • 拆箱:
        • 自动将包装类型转换成基础数据类型
        • 自动拆箱如果遇到包装给null,则会抛出NEP
      • 装箱:把基础数据类型转换成包装数据类型
        • 装修的数据如果是-128-127之间的数据。调用integer.valueof()会被缓存起来,具体源码如下,
          那么此时访问integer对象使用== , 还是equals的结果是一致的,都是常量池的数据比较。访问在此区间之外的数据则是内存比较
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    

    Object

    • object具体方法:

      • hashcode()
      • equals()
      • wait()
      • notify()
      • notifyall()
      • clone()
      • toString()
      • getClass()
      • finalize() //实例被垃圾回收器回收的时候触发的操作
      • registerNatives()
    • equals 和 ==

      • 如果是两个引用类型比较,那么就是内存地址比较
      • == 不能重写值比较
      • 所有对象集成object都有equals方法,默认实现是==
    • equals 和 hashcode

      • 当equals方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规约定:值相同的对象必须有相同的hashCode。
      • hashCode不同时,object1.equals(object2)为false;
      • hashCode相同时,object1.equals(object2)不一定为true;
      • 当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则链到后面(如果是链地址法)。
    • string sringbuffer stringbuilder

      • 三个都是final 类,不可以被集成
      • string不可变,sringbuffer stringbuilder长度可变
      • sringbuffer是线程安全的
      • stringbuilder线程不安全
      • StringBuffer在StringBuilder的方法之上添加了synchronized,保证线程安全。
    • string是final类,不可以继承,也不可以重写java.lang.String(类加载机制)

      • 双亲委派模型
        • 因为加载某个类的时候,优先使用父类加载器来加载需要使用的类。如果我们自定义了
          java.lang.String这个类
        • 加载该类的类加载器为appclassloader
        • appclassloader的父加载器为extclaassloader,所以这是加载string的类为extclassloader 但是在jre/lib/ext 下并没有发现string.class信息
        • 所以接着上传给顶级加载器bootstrap。
        • bootstrap在jre/lib目录下的rt.jar找到了string.class, 将其加载到内存中。
        • 这就会类加载器的委托模型
        • 所以用户自定义的类加载器不会生效
    • substring

      • 会创建一个新的string
      • 编译时会吧+转换成stringbuilder 的append方法
      • String = “abc”, 可能创建一个或者不创建对象,如果“ABC”在常量池中不存在,那么久会在常量池中创建一个String 对象,然后将对象的指向这个内存地址,以后无论创建多少次“abc”,都是相同的内存地址,
      • 注意: substring和new String 都是在堆中重新创建一个对象。
    • 常量池

      • String str = new String(“ABC”); 至少创建一个对象,也可能两个。因为用到new关键字,肯定会在heap中创建一个str2的String对象,它的value是“ABC”。同时如果这个字符串在字符串常量池里不存在,会在池里创建这个String对象“ABC”。

        • String s1= “a”;
        • String s2 = “a”;
        • 此时s1 == s2 返回true
        • “” 引号创建的对象在常量池塚
        • String s1= new String(“a”);
        • String s2 = new String(“a”);
        • 此时s1 == s2 返回false
        • 如果“a”在常量池中,那么仅在堆中拷贝一份引用(new String)
        • 如果“a”不在常量池塚,那么会现在常量池中创建一份数据,然后在进行堆拷贝,
        • 会创建两个对象
    • 编译优化
      final 都会在编译器优化,并且会被直接算好

    • String intern

      • jdk7以后吧常量池从方法区移到了堆上
      • 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。
    
    String s = new String("1");
    s.intern();
    String s2 = "1";
    System.out.println(s == s2);// false
    
    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);// true
    

    String s = newString("1"),生成了常量池中的“1” 和堆空间中的字符串对象。
    s.intern(),这一行的作用是s对象去常量池中寻找后发现"1"已经存在于常量池中了。
    String s2 = "1",这行代码是生成一个s2的引用指向常量池中的“1”对象。
    结果就是 s 和 s2 的引用地址明显不同。因此返回了false。

    String s3 = new String("1") + newString("1"),这行代码在字符串常量池中生成“1” ,并在堆空间中生成s3引用指向的对象(内容为"11")。注意此时常量池中是没有 “11”对象的。
    s3.intern(),这一行代码,是将 s3中的“11”字符串放入 String 常量池中,此时常量池中不存在“11”字符串,JDK1.6的做法是直接在常量池中生成一个 "11" 的对象。
    但是在JDK1.7中,常量池中不需要再存储一份对象了,可以直接存储堆中的引用。这份引用直接指向 s3 引用的对象,也就是说s3.intern() ==s3会返回true。
    String s4 = "11", 这一行代码会直接去常量池中创建,但是发现已经有这个对象了,此时也就是指向 s3 引用对象的一个引用。因此s3 == s4返回了true。

    String s3 = new String("1") + new String("1");
    String s4 = "11";
    s3.intern();
    System.out.println(s3 == s4);// false
    

    String s3 = new String("1") + newString("1"),这行代码在字符串常量池中生成“1” ,并在堆空间中生成s3引用指向的对象(内容为"11")。注意此时常量池中是没有 “11”对象的。
    String s4 = "11", 这一行代码会直接去生成常量池中的"11"。
    s3.intern(),这一行在这里就没什么实际作用了。因为"11"已经存在了。
    结果就是 s3 和 s4 的引用地址明显不同。因此返回了false。

    String str1 = new String("SEU") + new String("Calvin");
    System.out.println(str1.intern() == str1);// true
    System.out.println(str1 == "SEUCalvin");// true
    

    str1.intern() == str1就是上面例子中的情况,str1.intern()发现常量池中不存在“SEUCalvin”,因此指向了str1。 "SEUCalvin"在常量池中创建时,也就直接指向了str1了。两个都返回true就理所当然啦。

    String str2 = "SEUCalvin";//新加的一行代码,其余不变  
    String str1 = new String("SEU") + new String("Calvin");
    System.out.println(str1.intern() == str1);// false
    System.out.println(str1 == "SEUCalvin");// false
    

    str2先在常量池中创建了“SEUCalvin”,那么str1.intern()当然就直接指向了str2,你可以去验证它们两个是返回的true。后面的"SEUCalvin"也一样指向str2。所以谁都不搭理在堆空间中的str1了,所以都返回了false。

    面向对象

    • 抽象类和接口的区别

      • 抽象类只能被继承并且只能继承一个,接口需要被实现但是可以实现多个
      • 抽象类中可以有成员变量;接口中的变量必须是static final的,必须是被初始化的,接口中只能有常量,不能有变量
      • 抽象类的中方法可以不是抽象的;但是接口中必须是抽象的
      • java 8 接口有default方法,可以被实现了
    • 使用场景:

      • 如果要创建不带变量和实现的基类,那么应该选择接口而不是抽象类
      • 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。
    • 重写和重载:

      • 编译期的静态多分派:overloading重载 根据调用引用类型和方法参数决定调用哪个方法(编译器)
      • 运行期的动态单分派:overriding 重写 根据指向对象的类型决定调用哪个方法(JVM)
  • 相关阅读:
    结束咯
    在Ubuntu上不能使用PPA下载
    月亮+大环
    piano
    花都论坛,广州花都本地生活
    LLVM的调用协议与内存对齐
    SALVIA 0.5.2优化谈
    LLVM随笔
    OS之争:永不停歇的战争(二,完结)
    OS之争:永不停歇的战争(一)
  • 原文地址:https://www.cnblogs.com/yankang/p/13090469.html
Copyright © 2011-2022 走看看