Java基础学习笔记(五)

  • final有哪些用法?

    • 被final修饰的类不可以被继承。
    • 被final修饰的方法不可以被重写。
    • 被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。
    • 被final修饰的方法,JVM会尝试将其内联,以提高运行效率。
    • 被final修饰的常量,在编译阶段会存入常量池中。

    在构造函数内对一个final域的写入。与随后把这个被构造对象的引用赋值给一个引用变量。这两个操作之间不能重排序。初次读一个包含final域的对象的引用。与随后初次读这个final域,这两个操作之间不能重排序。

  • static有哪些用法?

    **static**关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享。

    除了静态变量和静态方法之外,**static**也用于静态块,多用于初始化操作。

    最后一种用法就是静态导包。

  • **transient序列化中如果有些字段不想进行序列化,怎么办?**

    对于不想进行序列化的变量,使用 transient关键字修饰。transient关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient修饰的变量值不会被持久化和恢复。transient只能修饰变量,不能修饰类和方法。

  • **instanceof关键字**

    instanceof严格来说是Java的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

    <aside> 💡 boolean result = obj instanceof Class

    </aside>

    其中obj为一个对象,Class表示一个类或者一个接口,当objClass的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result都返回 true,否则返回false。编译器会检查 obj是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

    int i = 0;
    System.out.println(i instanceof Integer);//编译不通过 i必须是引用类型,不能是基本类型
    System.out.println(i instanceof Object);//编译不通过
    
    Integer integer = new Integer(1);
    System.out.println(integer instanceof Integer);//true
    
    //false,在JavaSE规范中对instanceof运算符的规定就是:如果obj为null,那么将返回false。
    System.out.println(null instanceof Object);
    
  • Java IO流

    • 按照流的流向分,可以分为输入流和输出流;
    • 按照操作单元划分,可以划分为字节流和字符流;
    • 按照流的角色划分为节点流和处理流。

    InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。 OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

    IONIO的区别(补充) NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。

  • Java 反射

    • 定义

      反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。

      这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

    • 哪里会用到反射机制?

      jdbc就是典型的反射,这就是反射。如hibernate,struts等框架使用反射实现的。

      Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
      
    • 反射的实现方式:

      第一步:获取Class对象,有4种方法:

      1. Class.forName(“类的路径”);
      2. 类名.class
      3. 对象名.getClass()
      4. 基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象
    • 实现Java反射的类:

      1. Class:表示正在运行的Java应用程序中的类和接口 注意: 所有获取对象的信息都需要Class类来实现。
      2. Field:提供有关类和接口的属性信息,以及对它的动态访问权限。
      3. Constructor:提供关于类的单个构造方法的信息以及它的访问权限
      4. Method:提供类或接口中某个方法的信息
    • 反射机制的优缺点:

      • 优点

        1. 能够运行时动态获取类的实例,提高灵活性;
        2. 与动态编译结合
      • 缺点

        1.使用反射性能较低,需要解析字节码,将内存中的对象进行解析。

        • 解决方案
          1. 通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
          2. 多次创建一个类的实例时,有缓存会快很多
          3. ReflectASM工具类,通过字节码生成的方式加快反射速度
        1. 相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
  • Java 泛型

    “泛型” 意味着编写的代码可以被不同类型的对象所重用。

    “泛型”,顾名思义,“泛指的类型”。我们提供了泛指的概念,但具体执行的时候却可以有具体的规则来约束,比如我们用的非常多的ArrayList就是个泛型类,ArrayList作为集合可以存放各种元素,如IntegerString,自定义的各种类型等,但在我们使用的时候通过具体的规则来约束,如我们可以约束集合中只存放Integer类型的元素。

    以集合来举例,使用泛型的好处是我们不必因为添加元素类型的不同而定义不同类型的集合,如整型集合类,浮点型集合类,字符串集合类,我们可以定义一个集合来存放整型、浮点型,字符串型数据,而这并不是最重要的,因为我们只要把底层存储设置了Object即可,添加的数据全部都可向上转型为Object。 更重要的是我们可以通过规则按照自己的想法控制存储的数据类型。

  • Java 异常

    try-catch-finally

    1. try 块负责监控可能出现异常的代码
    2. catch 块负责捕获可能出现的异常,并进行处理
    3. finally 块负责清理各种资源,不管是否出现异常都会执行其中 try 块是必须的,
    4. catch 和 finally 至少存在一个标准异常处理流程

    抛出异常→捕获异常→捕获成功(当 catch 的异常类型与抛出的异常类型匹配时,捕获成功)→异常被处理,程序继续运行 抛出异常→捕获异常→捕获失败(当 catch 的异常类型与抛出异常类型不匹配时,捕获失败)→异常未被处理,程序中断运行

    抛出异常→捕获异常→捕获成功(当 catch 的异常类型与抛出的异常类型匹配时,捕获成功)→异常被处理,程序继续运行 抛出异常→捕获异常→捕获失败(当 catch 的异常类型与抛出异常类型不匹配时,捕获失败)→异常未被处理,程序中断运行

    在开发过程中会使用到自定义异常,在通常情况下,程序很少会自己抛出异常,因为异常的类名通常也包含了该异常的有用信息,所以在选择抛出异常的时候,应该选择合适的异常类,从而可以明确地描述该异常情况,所以这时候往往都是自定义异常。

    自定义异常通常是通过继承 java.lang.Exception类,如果想自定义 Runtime 异常的话,可以继承java.lang.RuntimeException类,实现一个无参构造和一个带字符串参数的有参构造方法。

    在业务代码里,可以针对性的使用自定义异常。比如说:该用户不具备某某权限、余额不足等。

  • **try catch finallytry里有returnfinally还执行么?**

    执行,并且finally的执行早于try里面的return

    • 结论:
      1. 不管有没有出现异常,finally块中代码都会执行;
      2. trycatch中有return时,finally仍然会执行;
      3. finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
      4. finally中最好不要包含return,否则程序会提前退出,返回值不是trycatch中保存的返回值。
  • **ExcptionError包结构**

    Java可抛出Throwable的结构分为三种类型:被检查异常CheckedException,运行时异常RuntimeException,错误Error

    • 运行时异常RuntimeException 特点:Java编译器不会检查它。

      定义:RuntimeException及其子类都被称为运行时异常。

      • ClassCastException(类转换异常)
      • IndexOutOfBoundsException(数组越界)
      • NullPointerException(空指针异常)
      • ArrayStoreException(数据存储异常,操作数组是类型不一致)
      • BufferOverflowException
    • 被检查异常CheckedException 特点 :Java编译器会检查它。

      定义:Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。

      • IOException
      • FileNotFoundException
      • SQLException
    • 错误Error 特点 :和运行时异常一样,编译器也不会对错误进行检查。

      定义:Error类及其子类。

      • VirtualMachineError
      • OutOfMemoryError
      • ThreadDeath
  • OOM哪些情况,SOF哪些情况

    • OOM:OutOfMemoryError异常

      • Java Heap溢出

        一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess

        java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

        如果是内存泄漏,可进一步通过工具查看泄漏对象到GCRoots的引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。

        如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。

      • 虚拟机栈和本地方法栈溢出

        如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常 这里需要注意当栈的大小越大可分配的线程数就越少。

      • 运行时常量池溢出

        异常信息:java.lang.OutOfMemoryError:PermGenspace 如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。

      • 方法区溢出

        异常信息:java.lang.OutOfMemoryError:PermGenspace

        方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。也有可能是方法区中保存的class对象没有被及时回收掉或者class信息占用的内存超过了我们配置。 方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。

    • SOF:StackOverflow堆栈溢出:

      StackOverflowError 的定义:当应用程序递归太深而发生堆栈溢出时,抛出该错误。 因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。 栈溢出的原因:递归调用,大量循环或死循环,全局变量是否过多,数组、List、map数据过大。

  • 3*0.1 == 0.3返回值是什么?

    false,因为有些浮点数不能完全精确的表示出来。

  • a=a+b与a+=b有什么区别吗?

    +=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换。如:

    byte a = 127;
    byte b = 127;
    b = a + b; // 报编译错误:cannot convert from int to byte
    b += a;
    
    short s1= 1;
    s1 = s1 + 1;//有错误。short类型在进行运算时会自动提升为int类型,也就是说 s1+1 的运算结果是int类型,而s1是short类型,此时编译器会报错。
    
    short s1= 1;
    s1 += 1;//+=操作符会对右边的表达式结果强转匹配左边的数据类型,所以没错。
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值