java 基础学习记录-2020

目录

哪些方法不可以被重写?

方法的参数传递机制

int 和 Integer 的区别

类的加载顺序

类的生命周期

JVM

垃圾回收算法

内存泄露 和 内存溢出 的区别

ThreadLocal 

强引用、软引用、弱引用、虚引用 的区别

数据结构

抽象类和接口的区别

异常

hashcode相等 和 值相等的 关系

final、finally、finalize的区别

String、StringBuffer、StringBuilder 的区别

BIO、NIO、AIO 有什么区别?

spring

数据库

 MyBatis

Mysql


面向对象的3大特征:封装、继承、多态


哪些方法不可以被重写?

  1. final 修饰的方法
  2. 静态方法
  3. private 修饰的方法

方法的参数传递机制

  1. 形参是基本数据类型:传递数据值
  2. 形参是引用数据类型:传递引用地址
  3. String 和 包装类 创建的变量都是用 final 修饰的,不可改变引用地址,所以虽然传递过来的是引用地址,但是一旦进行数据拼接,就相当于 new 了一个新的对象出来
    public static void main(String[] args) {
        Integer n = 125;
        String str = "hello";
        change(n,str);
        System.out.println(n); // 125
        System.out.println(str); // hello
    }
    public static void change(Integer n,String str){
        n += 1; // 相当于 new Integer(n+1)
        str += "world"; // 相当于 new String("helloworld")
    }

int 和 Integer 的区别

int 的初始值是 0 ,存储数据值;

Integer 的初始值是 null,存储引用地址,是 int 的包装类,在与 int 型数据进行比较时,会自动拆箱为 int 型

非new生成的Integer,在-128~127之间,指向的是同一个地址(java常量池),其他的数值范围都是在堆中重新new出来的

// 非new生成的Integer,在-128~127之间,指向的是同一个地址(java常量池),其他的数值范围都是在堆中重新new出来的
Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1 == i2); // false

Integer i3 = 127;
Integer i4 = 127;
System.out.println(i3 == i4); // true

// Integer 与 int 进行比较时,会进行自动拆箱
int i = 127;
Integer j = 127;
System.out.println(i == j);// true

// 所有的 new 操作,都是在堆中重新创建的对象
Integer l = new Integer(127);
System.out.println(j == l); // false

类的加载顺序

  1. 父类的静态变量/静态代码块(按顺序加载)
  2. 子类的静态变量/静态代码块(按顺序加载)
  3. 父类的实例变量/普通代码块(按顺序加载)
  4. 父类的构造方法
  5. 子类的实例变量/普通代码块(按顺序加载)
  6. 子类的构造方法

注:实例变量 和 普通代码块,每 new 一次对象,就会执行一次;静态变量和静态代码块只会执行一次


类的生命周期

加载 -》 连接 -》 初始化 -》 使用 -》 卸载

加载:类加载器加载class文件,利用双亲委托机制

连接:分为3步:

        1)校验 校验class文件包含的信息是否符合jvm的规范

        2)准备 为类变量分配内存,并将其初始化为默认值

        3)解析 类型中的符号引用转换成为直接引用

初始化:调用构造方法给属性赋初始值

双亲委托机制:

4种类加载器,从上到下依次为:
1、引导类加载器(BootstrapClassLoader)---加载JVM运行时需要的类
2、扩展类加载器(ExtendClassLoader)---加载JVM扩展的类
3、应用类加载器(AppClassLoader)---加载classpath路径下的文件
4、自定义类加载器(CustomClassLoader)---加载自定义的文件

先将加载请求传递到顶层的 引导类加载器,顶层加载不到,就将请求传递给下层加载器,一直加载不到就抛出ClassNotFoundException


JVM


垃圾回收算法

1、标记-清除
可以回收的对象进行标记,然后清除掉,会产生大量的内存碎片
2、复制
将内存分为大小相等的两块,每次只使用其中的一块。当一块内存使用满后,将还存活的对象复制到另一个内存,然后将当前使用的内存整体清除掉(新生代的from区域、to区域)
3、标记-压缩
将可以回收的对象进行标记,然后将依然存活的对象整体移到一块区域,然后将剩余的空间进行回收。因为要整理对象的引用地址,所以效率比较慢
4、分代收集
将上述的算法综合使用:
新生代使用复制算法;老年代使用 标记-清除/标记压缩

可达性分析算法可以用作GC ROOT的有:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中(Native方法)引用的对象

内存泄露 和 内存溢出 的区别

内存泄露

一个对象已经不被引用了,但是无法被回收

内存溢出

创建的对象太多,超过了JVM可以允许的最大值


ThreadLocal 

线程本地变量,弱引用,使用完毕用remove移除

spring 的 @Transactional 底层用的就是 ThreadLocal 存储连接信息


强引用、软引用、弱引用、虚引用 的区别

强引用:GC不会回收

软引用:内存不足时,会被GC回收

弱引用:GC前回收

虚引用:管理堆外内存,可以获取对象被回收的一个结果

数据结构

数据结构是静态描述数据之间的关系;算法是解决问题的一种设计;

数组和Collection的两者的区别:

  1. 数组长度固定,连续的内存地址,集合长度不固定;
  2. 数组可以存储基本数据类型和引用类型,集合只能存储引用数据类型;

Arrays.asList(new数组[])---数组转集合;Collections.toArray(newList())---集合转数组


Collection
  List
    有序,有下标、元素可重复
    分类
      ArrayList
        底层是数组,初始容量10,扩容量是原来的一半;查询快,增删慢
        如果new完以后,没有向集合中添加任何元素,那么初始容量为0;调用add()以后,容量才会扩展到10
        为什么说线程不安全?
      CopyOnWriteArrayList
      LinkedList
        底层是双向链表结构,增删快,查询慢
      Vector
        底层是数组,初始容量为10,扩容量为原来的一倍;查询快,增删慢;底层使用synchronized锁定方法,保证了线程安全
  set
    无序,无下标,元素不可重复
    分类
      HashSet
        基于hashCode实现元素不重复
        hashCode如果相等,如果equals不相等,则拒绝后入者
        底层是HashMap,数组+链表+红黑树
      CopyOnWriteArraySet
        底层是CopyOnWriteArrayList
      SortedSet
        TreeSet
          底层是TreeMap
          有序集合,对象需要实现Comparable接口的campareTo()进行排序
      Set的底层都是Map,key是set的值,value是一个Object常量
  remove
    在使用迭代器循环遍历时,不能使用Collection.remove()删除元素,需要使用Iterator.remove(),否则会报ConcurrentModificationException


Map
  概念

用于存储键值对(key-value),key:无序、无下标、不允许重复,key重复则覆盖原值,只可以存放一个null,value:无序、无下标、允许重复
  HashMap
    数组+单向链表+红黑树
    数组的初始容量16,负载因子0.75,当容量超过 初始容量*0.75 时,扩容量为原来的一倍(目的是减少扩容次数)
    元素个数大于threshold时,进行扩容
    数组长度大于64,并且链表长度大于8时,链表将改为红黑树
    当红黑树的节点数小于6时,红黑树将转回链表
    如果new完以后,没有向集合中添加任何元素,那么table为null、size=0(目的是节省空间);第一次调用put()以后,容量才会扩展到16
  ConcurrentHashMap
  HashTable
    线程安全,不允许key和value都不允许为null
    Properties
      HashTable的子类,key-value都为String类型,一半用于获取配置文件信息
  TreeMap

抽象类和接口的区别

  • 相同点:不能被实例化,都可以被继承
  • 不同点:
    • 抽象类 可以包含非抽象的方法,可以包含普通成员变量,只能被单继承,有构造方法(在子类初始化时调用父类的构造方法)
    • 接口 只能包含抽象方法,所有的变量必须用 public static final 来修饰,可以被多个实现类实现

异常

Throwable

  • Error 是程序中无法处理的错误,表示运行应用程序中出现了严重的错误。此类错误一般表示代码运行时JVM出现问题,非代码性错误。如:内存溢出(OutOfMemoryError)

  • Exception 程序本身可以捕获并且可以处理的异常。

    • 运行时异常(不受检异常-unchecked):一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。RuntimeException类及其子类表示JVM在运行期间可能出现的错误。编译器不会检查此类异常,并且不要求处理异常,如:空指针(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。

    • 非运行时异常(受检异常-checked):编译器会检查此类异常,如果程序中出现此类异常,必须对该异常进行处理,要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。Exception中除RuntimeException及其子类之外的异常。如IOException


throw 和 throws 的区别

throw 在方法内部抛出一个异常对象,用法: throw new Exception()

throws 异常处理的一种方式,类似于try-catch()-finally,在方法声明处声明异常类型,用法:public void test () throws Exception {}


 try-catch-finally 中哪个部分可以省略?

catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally

hashcode相等 和 值相等的 关系

  1. hashcode相等,值不一定相等
  2. hashcode不相等,值一定不相等
  3. 值相等,hashcode一定相等
  4. 值不相等,hashcode不一定不相等

final、finally、finalize的区别

  • final 修饰的类不能被继承,修饰的方法不能被重写,修饰的变量值不能被修改
  • finally 异常处理中,不管是否有异常抛出,都会执行finally块中的执行逻辑
  • finalize 垃圾回收时的一个方法名,用于在垃圾回收前对一些资源进行清理工作

String、StringBuffer、StringBuilder 的区别

  • 相同点:都是用于字符串操作
  • 不同点:
    • String 修饰的变量长度不能更改,声明的是不可变的对象,每次操作都会生成新的 String 对象,线程不安全
    • StringBuilder 变量长度可以更改,操作的都是同一个对象,线程不安全,执行速度比 StringBuffer 快
    • StringBuffer 变量长度可以更改,操作的都是同一个对象,线程安全
  • 执行速度:
        System.out.println("----- 验证 String 每次操作都是 new 了一个新对象 ------");
        String str1 = "123";
        System.out.println(System.identityHashCode(str1)); // 1872034366
        str1 += "333";
        System.out.println(System.identityHashCode(str1)); // 1581781576
        System.out.println("----- 验证 StringBuilder 操作的是同一个对象------");
        StringBuilder str = new StringBuilder("123");
        System.out.println(System.identityHashCode(str)); // 644117698
        str.append("333");
        System.out.println(System.identityHashCode(str)); // 644117698

 String str="i"与 String str=new String("i")一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String("i") 则会被分到堆内存中。

BIO、NIO、AIO 有什么区别?

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

spring

常用的注入方式有哪些?

  • setter 属性注入
  • 构造器注入
  • 注解注入

spring 中的 bean 是线程安全的吗?

spring 中的实例默认都是单例模式,如果bean中有保存共享数据,那就不安全,需要手动处理多线程的安全问题;如果不保存共享数据,就是安全的。


bean 的 有状态/无状态 指的是:

  • 有状态就是有数据存储功能。
  • 无状态就是不会保存数据。

spring 支持几种 bean 的作用域?

spring 支持 5 种作用域,如下:

  • singleton:spring ioc 容器中只存在一个 bean 实例,bean 以单例模式存在,是系统默认值;
  • prototype:每次从容器调用 bean 时都会创建一个新的实例,即每次 getBean()相当于执行 new Bean()操作;
  • request:每次 http 请求都会创建一个 bean;
  • session:同一个 http session 共享一个 bean 实例;
  • global-session:用于 portlet 容器,因为每个 portlet 有单独的 session,globalsession 提供一个全局性的 http session。

使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销


@Autowired 和 @Resource 的区别

  • 相同点:都是通过注解注入外部实例对象
  • 不同点:
    • @Autowired Spring提供的注解,只能通过 byType 方式注入对象,若要使用 byName 方式注入对象,需要搭配 @Qualifier 一起使用
    • @Resource 由J2EE提供,默认通过 byName 方式注入对象,也可以使用 byType 方式注入对象

spring的7个事务传播属性

  1. never 从不使用事务,若上层有事务,则抛出异常
  2. not_supported 声明方法不开启事务,若上层有事务则挂起,当前方法执行完毕后,再恢复上层事务
  3. mandatory 声明方法只能在有事务的环境下运行,本身不创建事务,若上层没有事务,则抛出异常
  4. required(默认方法) 上层有事务则使用,上层没有事务,则创建一个新的事务
  5. requires_new 不管上层有没有事务,都创建一个新的事务,并挂起上层事务,新事物执行完毕后,再恢复上层事务
  6. sopports 上层有事务则使用,若没有,则在非事务环境下运行
  7. nested 上层有事务,则在内部开启一个新的事务,新事物有自己独立的回滚点,新事物的回滚点不会对上层事务产生影响,但是上层事务的提交,会直接提交内层嵌套的事务;上层没有事务,则创建一个新的事务。该属性只会对DataSourceTransactionManager事务管理器有效

数据库

事务的ACID属性

  • 原子性(Atomicity)

指事务是一个不可分割的工作单位,事务中的操作要么全部发生,要么全部不发生

  • 一致性(Consistency)

事务必须是数据库从一个一致性状态变换到另一个一致性状态(比如银行卡转账)

  • 隔离性(Isolation)

一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰

  • 持久性(Durability)

一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响


3种事务并发问题

  • 脏读

读取到其他事务未提交的数据

	例如:
	1.事务1 将某条记录的AGE值从20修改为30
	2.事务2 读取了事务1更新后的值:30
	3.事务1 回滚,AGE的值恢复到了20
	4.事务2 读取到的30就是一个无效的脏数据
  • 不可重复读

读取到其他事务已提交的数据

	例如:
	1.事务1 读取了AGE值为20 
	2.事务2 将AGE值修改为30
	3.事务1 再次读取AGE值为30,和第一次读取的不一致
  • 幻读

读取到其他事务 新插入/删除 的数据行

	例如:
	1.事务1 读取了STUDENT表中的一部分数据
	2.事务2 向STUDENT表中插入了新的行
	3.事务1 再次读取STUDENT表时,多出了一些新的行

 4种隔离级别

  1. read uncommitted (读未提交)此时会出现脏读
  2. read committed(读已提交)此时会出现不可重复读(Oracle默认事务隔离级别
  3. repeatable read(可重复读)此时会出现幻读(mysql 默认事务隔离级别
  4. serializable 串行化,虽然不会出现并发问题,但是给每一行数据加锁(即给表加锁),会导致大量的超时现象和锁竞争

注:事务隔离级别不是越高越好,级别越高效率越低,根据具体情况选择合适的事务隔离级别

 MyBatis

#{}和 ${}的区别是什么?

#{}是预编译处理,${}是字符替换。 在使用 #{}时,MyBatis 会将 SQL 中的 #{}替换成“?”占位符,配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。


Mysql

一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几?

  • 表类型如果是 MyISAM ,那 id 就是 8。

  • 表类型如果是 InnoDB,那 id 就是 6。

InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值