java面试题

java面试题

一、面向对象

面向过程注重的是每一个步骤以及顺序

​ 面向过程比较直接高效,

面向对象更加注重事情的参与者——(就是对象),以及各自需要做什么(方法)

​ 面向对象更易于复用,维护和拓展 4

​ 封装:意义,在于明确标识出允许外部使用的所有的成员函数和数据项

​ 内部的细节对外部透明,外部调用不用关心内部是如何实现[焦1]

​ 继承:将类的共性提取出来置于一个类中作为父类,然后其子类继承父类,并且可以做出自己的改变或定义新的属性

​ 父类中的方法和属性,子类可以直接使用,只需要拓展自己个性化的即可

​ 多态:基于对象所属类的不同,外部对同一个方法的调用,但是实际的执行逻辑却不同[焦2]

​ 想要使用多态类之间必须存在关系,例如:继承,方法重写,实现接口,

二、jdk jre jvm的区别

Jdk是java开发工具——供开发人员使用

Jre是java运行时的环境——对只想要运行java的程序的用户只需要安装jre即可

Jvm 虚拟机 解析class 文件,使得操作系统可以识别

​ JAVA一处编译处处运行的关键就是jvm有针对操作系统的版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gBaZchmm-1648379907031)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)]

Java文件——javac编译——。Class文件 经过jvm映射到操作系统

三、 ==和equals

​ == 对比的是——栈——中的值,

​ 基本数据类型是 变量值

​ 引用类型是堆中内存对象的地址,类似一个指向堆内存的指针

​ Equals: Object中默认采用的是 == 比较,所以在默认使用时等效于==

​ 但是通常会重写equals方法,比较的就是字面值——String类就重写了该方法

栈:存储局部变量,——数据用过之后就释放

堆:所有 new 出来的东西 都存放才堆中,就是说new 出来的东西在堆内存中都有地址值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8VV9bYz-1648379907032)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDwZpJUt-1648379907032)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image005.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WABn1wV-1648379907033)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image006.png)]对Str1直接赋值hello ,使其 栈 内存的值直接指向了常量池中的hello

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I33NGcta-1648379907033)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image007.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-htqTgHXI-1648379907033)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image008.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tabom9YZ-1648379907034)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image009.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2XMY2YMK-1648379907034)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image010.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwd8gdh7-1648379907035)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image011.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-68tpfJcp-1648379907035)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image012.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agFDGUo4-1648379907036)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image013.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6IvMorC-1648379907036)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image014.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EGBk8Mwu-1648379907036)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image015.png)]对str2 通过new 构造方法赋值,先在堆内存中,开辟了一个空间,然后在栈内存的地址值指向常量池中的hello str2栈内存中的值 是它在堆内存中的位置,不是常量池中hello的地址

对str3 通过str2直接赋值,实际上是将str2 的 堆内存中开辟的空间地址值赋给了str3

三个字符串通过 == 比较 获取的结果实际上是比较栈内存中指向堆内存的地址值

明显 1!=2 1!=3 2=3 ,

四、Final

修饰类:表示类不可以被继承

修饰方法:表示方法不可被子类覆盖,但是可重载

修饰变量:变量一旦被final修饰,就不可以更改他的值

​ 修饰成员变量:

​ 如果修饰类变量(static修饰的变量),只能在声明的时候就复制,或者在静态代码块中进行赋值

​ 如果修饰的是普通变量:则在声明的时候进行赋值,或者代码块中进行赋值

​ 修饰局部变量:

​ 系统不会初始化局部变量,所以在final修饰局部变量的时候,必须自己赋值,在使用之前一定要先赋值,但是不可以进行二次赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nnn4F6vz-1648379907037)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image017.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agfvvsfP-1648379907037)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image019.jpg)]

局部内部类和匿名内部类只能访问局部final变量

​ 含有内部类的class 文件编译之后会有两个.class 文件,

​ 类与类是同级的,定义在方法内部的内部类,并不会随着方法的结束而被销毁——注意这一点哈—— 当外界的方法结束时候,局部变量就会被销毁,

​ 但是此时内部类的对象可能还未执行完毕,那么该如果变量就会被销毁,也就是此时的内部类访问了一个不存在的成员变量,显然这是不可能的,,

​ 为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,也就是说内部类实际上访问的是局部变量的复制品,但是此时又产生一个问题,就是如果内部类使得成员变量发生了改变,方法中的成员变量也会随着改变,但是此时的外界的方法已经被销毁,数据不可能再被改变,

​ 所以综上,将局部成员变量设置为final修饰之后,不让任何人对数据进行更改, 就保证了成员变量的一致性。

五、String 、StringBuffer、StringBuilder

​ String是final修饰的,不可变,每次操作都会产生新的String对象

​ StringBuffer和StringBuilder 都是在源对象上操作

​ StringBuffer是线程安全[焦3] 的,StringBuilder是线程不安全的

​ StringBuffer (缓冲) 方法都是被synchronized修饰的,加上同步机制所以是线程安全的。

​ 性能方面:StringBuilder>StringBuffer>String[焦4]

关于怎么选取使用这几个数据类型

​ 优先使用StringBuilder,以此来提高效率

​ 如果该变量,是处于多线程环境下,且被多条语句共同操作,作为共享数据时,就要使用呢StringBuffer了——以此来达到线程安全的目的

​ 如果不经常对数据进行改动的话,就使用String

六、重载和重写的区别

​ 重载是形参列表改变

​ 重写是仅仅改变方法体

​ 重载: 发生在一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-654cpjVL-1648379907037)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image020.png)]
       如果仅仅是访问修饰符和返回值类型不同,在编译时期就会报错

​ 重写: 发生在父子类中,方法名参数列表必须相同, 抛出异常的范围小于或等于 父类,访问修饰符范围大于等于父类,

​ 此外,如果父类中的方法时被private修饰将不可以被子类重写该方法

七、接口和抽象类[焦5] 的方法

​ 抽象类中可以存在普通成员函数, 但是接口中只能存在public abstract final的抽象方法(注意这里就算自己不写,也会被默认修饰)

​ 抽象类只能继承一个,但是接口却可以多实现(就是单继承,多实现)

​ 抽象类的成员方法可以是多个类型的 但是接口中的成员方法只能是public static final类型的

从设计目的上讲

​ 接口的设计目的,就像是对类的行为一个进行一个 “有” 的约束,因为继承接口就必须实现接口中的抽象方法,就必须有这个接口中所约束的功能和行为,

只约束了行为的有无,但是却不对具体的实现进行限制

​ 抽象类——先有子类,后有父类。 父类就是当不同的类具有某些相同的行为的时候,将这些相同的共性提取出来的一个抽象派生类

设计目的就是——代码复用

​ 抽象类不允许被实例化

​ 抽象类是对类本质的抽象,是一种 is a的关系 包含了子类的通用特性,(子类的个性可以由自己实现)

​ 接口是对行为抽象的表达, 是一种 like a的关系, 定义了其实现类可以做什么,但是具体到实现类是谁,实现的方法体是如何实现的并不关心

**
**

八、list和set的区别

​ List:——基于数组 有序可重复

​ 有序,按照对象的进入顺序保存对象,可重复,允许多个null元素对象

​ 遍历方式有两种,可以使用iterator取出所有的元素,在逐一遍历,

​ 也可以使用get(int index)获取指定下标的元素

​ Set:——基于链表

​ 无序,不可重复

​ 最多允许有一个null元素对象,取元素的时只能使用iterator来遍历各元素

九、hashCode和equals

​ Equals如果不去重写,默认使用的是Object中的equals,就是== ,如果引用对象是 基本数据类型变量,那么比较的就是变量值,如果是引用类型,那么比较的就是该变量在栈内存中的地址

​ hashCode的作用就是获取hash码,也就是散列码,以此来确定该对象在哈希表中的索引位置,

为什么有hashcode (这里以hashset检查重复,来说明为什么要有hashcode)

​ 一个对象加入hashset时,hashset首先会计算这个对象的hashcode值,以此来确定该对象的加入的位置,查看该位置是否有值,

​ 如果有,就会再次调用equals方法来检查两个对象是否真的相同,如果相同,就不加入,如果不同,就会再次散列到其他的位置,这样会大大的减少equals的比较次数,大大大提高的了执行速度

​ 如果没有值,就直接放进哈希值所指的索引处

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amP0D31t-1648379907038)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image022.jpg)]

十、Arraylist和linkedList的区别

ArrayList:底层的数据结构是基于动态数组,在存储方面是连续的存储在内存中,可以做到随机访问,适合做查询操作,但是不适合做增删操作

​ 数组的长度固定,当超长度存储数据时,需要创建新的数组,然后将原本的老数组中的数据复制到新的数组中, 在存储数据的过程中还会涉及到数据的移动,如果插入的数据不是在尾部插入,还会涉及到大量数据的移动,

​ 但是如果数据插在尾部,并且在定义初始容量的时候,定义较大的容量,那么就可以极大的提升性能,甚至可以超过linkedList,因为使用linkedList做数据的插入,会耗费大量的资源,来创建node节点对象,而ArrayList只要有足够大的空间且使用尾插法的时候只需要直接将数据放入即可

linkedList:底层的数据结构是基于链表的,在存储方面是分散的存储在内存中的,适合做数据的插入 以删除等操作,

​ 但是不适合查询,因为链表的查询需要从表头逐一遍历

​ Linkedlist在遍历的时候必须选择iterator而不推荐使用for循环,因为for循环体内通过get(i)取得某一个元素的时候都需要对list链表重新的遍历,性能比较差

此外也不推荐使用indexof返回索引,和for是一个道理

有哪些线程安全的List?

Vector

Collections.SynchronizedList

TreeSet和HashSet的区别

​ HashSet、TreeSet中的元素都是不能重复的,并且它们都是线程不安全的,二者的区别是:

  1. HashSet中的元素可以是null,但TreeSet中的元素不能是null;
  2. HashSet不能保证元素的排列顺序,而TreeSet支持自然排序、定制排序两种排序的方式;
  3. HashSet底层是采用哈希表实现的,而TreeSet底层是采用红黑树实现的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Dsqipu2-1648379907038)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image023.png)]

十一、hashMap和hashTable的区别?以及其底层的实现原理是什么

​ 区别:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afQQlTI9-1648379907038)(file:///C:/Users/Lenovo/AppData/Local/Temp/msohtmlclip1/01/clip_image025.png)] (1) Hashmap方法没有synchronized修饰,线程是不安全的,

​ hashtable中的方法都是被synchronized修饰的,线程安全

​ (2) hashmap允许key和value为null,hashtable不允许

​ 底层的实现 : 数组+链表

​ 注意从jdk8之后链表超过8数组长度超过64链表就会变为红黑树,元素以内部类node节点的方式存在——节点node就是链表——也可以说元素是以链表的形式存储

​ 当有元素存储的存储的时候,首先计算key放入hash值,然后对数组的长度取模运算,获取对应的数组下标

​ 如果没有产生hash冲突,先试用equals比较,如果相同,就取代该元素,不同的话就判断链表的高度,然后决定是使用红黑树的结构存储还是链表的方式存储

当key为null的时候,存在下标为0的位置

十一、hashmap的扩容机制

1、数组的初试容量是16,而容量是以2的次方扩充的,

  • 目的是为了提高性能使用足够大的数组
  • 也可以使位运算取代模运算

2、数组是否需要扩充是通过负载因子决定的,

  • 当负载因子为0.75时——即当前元素个数为数组容量的0.75时,就会扩充数组‘
  • 0.75是默认的,也可以设置负载因子大于1,这样数组就不会扩充了

3、为了解决冲突碰撞、数组中的元素是单向链表类型的,当链表长度达到8的时候链表就会转化为红黑树来提高性能

十一、HashMap为什么线程不安全

HashMap在并发执行put操作时,可能会导致形成循环链表,从而引起死循环。

HashMap如何实现线程安全?

  1. ​ 直接使用Hashtable类;

  2. ​ 直接使用ConcurrentHashMap;

  3. ​ 使用Collections将HashMap包装成线程安全的Map。

    LinkedHashMap的底层原理

    ​ LinkedHashMap继承于HashMap,它在HashMap的基础上,通过维护一条双向链表,解决了HashMap不能随时保持遍历顺序和插入顺序一致的问题。在实现上,LinkedHashMap很多方法直接继承自HashMap,仅为维护双向链表重写了部分方法。

    ​ 如下图,淡蓝色的箭头表示前驱引用,红色箭头表示后继引用。每当有新的键值对节点插入时,新节点最终会接在tail引用指向的节点后面。而tail引用则会移动到新的节点上,这样一个双向链表就建立起来了。

Map和Set有什么区别?

​ Set代表无序的,元素不可重复的集合;

​ Map代表具有映射关系(key-value)的集合,其所有的key是一个Set集合,即key无序且不能重复。

HashSet的底层结构

​ HashSet是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。它封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

十二、如何实现IOC容器

先解释一下IOC:控制反转,把对象的创建和对象的调用过程交给spring来管理

实现方式有两种

一、通过xml配置文件来实现

二、通过注解来实现


[焦1]自己做好自己的事情,并且将自己可以做到事情告诉外界,

当外界使用的时候,直接调用就行,不需要告诉他具体是如何实现的

[焦2]父类名 变量名=new 子类对象

变量名.方法名()

这时调用的方法实际上是子类的重写之后的方法。

注意如果想要使用子类特有方法,需要向下转型

[焦3]判断是否线程安全:

​ 是否为多线程环境

​ 是否存在共享数据

​ 是否有多条语句共同操作共享数据

[焦4]Stringbuilder舍弃了线程安全,换取了线程高效率

String要创建大量的对象所以性能是最差的

[焦5]共有的,向上抽取为抽象类,作为父类

扩张功能则使用接口

接口第规范,抽象是模板

十二、如何实现IOC容器

先解释一下IOC:控制反转,把对象的创建和对象的调用过程交给spring来管理,并且对属性的注入也交给spring来管理

底层原理——XML文件解析,工厂模式,发射

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qgOIBe8X-1648379907039)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220308130135432.png)]

实现方式有两种

一、通过xml配置文件来实现的步骤, 创建配置文件,添加bean标签并且将类的路径填在class子属性中

  • 通过new ClassPathXmlApplicationContext(“bean1.XML”) 来解析配置文件的上下文对象,

  • 然后使用刚刚获取的对象。getbean方法获取真正创建的对象

  • Order order=context.getBean(“order”,Order.class);注意这里的传入的是索要创建的对象的字节码文件

  • 属性的注入

    • DI依赖注入:

      ​ 通过set方法注入

      ​ 通过构造方法通过注入——需要使用标签:constructor-arg来对属性进行注入

      • 对于复杂属性的注入——通过外部bean,来引用
        • 即在bean标签外创建好需要引用的值然后用过ref来引用

​ 创建工程类

二、通过注解来实现

  • 使用注解来创建实例

    • @Component

    ​ @Service 【service层】

    ​ @controller 【controller层】

    ​ @repository 【dao层】

  • ​ @注解名称(属性名称=属性值,属性名称=属性值…)

    • @Autowired:根据属性类型进行自动装配——需要先在配置文件中生成bean对象

      • 当注入在IoC容器中该类型只有一个时,就通过byType进行装配

        当注入容器存在多个同一类型的对象时,就是根据byName进行装配

    • @Qualifier :根据属性名称进行注入

      该需要搭配@autowired使用

    • @Resource :可以根据类型注入也可以根据名称注入

      默认的话就是根据类型自动装配

  • 在解析文件时需要使用下面的方法来解析配置文件

    • new AnnotationConfigApplicationContext(SpringConfig.class)

    [焦1]这里的解析配置文件的实现方法改变了。

    使用解析类应用环境类的方法来实现 ,且传入的参数类型是 配置类的class文件

十三、什么是字节码,以及采用字节码的好处

​ java程序,一处编译,导出运行就是因为在编译和机器之间加入了一层虚拟机,虚拟机在任何的系统上编译程序都用一个公共的接口,所以java程序的编译只需要面向虚拟机即可,也就是说只需要虚拟机可以读的懂就行,在java中虚拟机能够理解的就是代码就是字节码——.class文件——只面向虚拟机

十四、java类加载器

jdk自带的三个类加载器:

​ bootstrap ClassLoader

​ ExtClassLoader

​ AppClassLoader

十五、java中的异常体系

顶级异常父类——Throwable

下面有两个子类——Exception和Error

Error程序无法处理的错误,一旦出现这个错误,程序就会被迫停止运行

Exception不会导致程序停止

  • 又分为两个部分:RuntimeException运行时异常和 checkedException检查异常
    • runtimeException发生程序在程序的运行过程中,会导致当前线程执行失败
    • checkedException发生编译时期,会导致程序编译不通过

十六、线程的生命周期、线程的状态

线程有五种状态:创建、就绪、运行、阻塞、死亡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dX7MdVSt-1648379907039)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220308142232359.png)]

阻塞的三种情况:

  • 等待阻塞
    • 运行的线程执行wait方法,该线程会释放所有的资源,这个状态是不会自动唤醒的,必须依靠其他线程调用notify或者notifyAll方法才会被唤醒,
  • 同步阻塞
    • 正在运行的线程在获取对象的同步锁时,该同步锁被别的线程占用
  • 其他阻塞
    • 运行的贤线程执行了sleep或者join方法,该线程就会进入阻塞状态,
    • 当sleep状态超时,join等待线程终止或者死亡的时候,线程就重新转入了就绪状态

新建状态:新创建一个线程对象

就绪状态:线程对象建立之后,调用该线程的start方法,该线程的状态就变成了可运行,等待cpu资源

运行状态:线程获取cpcu,执行了程序代码

阻塞状态:终止了cpu的使用权,暂时停止运行,知道线程进入就绪状态,才有机会进入运行状态

死亡状态:线程执行完了,或者异常推出了run方法,该线程结束生命周期

十七、sleep()、wait()、join()、yield()的区别

在将区别之前先说两个概念

  • ​ 锁池:
    • ​ 需要竞争同步锁的线程都会被放在锁池中,当征用该资源时,如果当前资源已经被其他的线程占用,其他需要使用该资源的线程都会在锁池中等待,挡资源被释放之后,锁池中的线程去争抢资源
  • ​ 等待池
    • 当使用wait()方法之后,线程会被放到等待池中,等待池中的线程不会竞争同步锁,只有线程调用notify或者notifyAll方法被唤醒后,才会去竞争锁资源
      • notify是唤醒一个线程放到锁池中
      • notifyAll是唤醒所有的线程放到锁池中
  1. ​ sleep是Tread类的静态本地方法,wait是object类的本地方法
  2. Sleep不会释放锁资源,会带着锁进入休眠,其他的线程不可能得到该锁资源,
  3. sleep方法不依赖于synchronized,但是wait依赖synchronize关键字
  4. sleep不需要被唤醒,但是wait需要被唤醒
  5. sleep用于当前线程休眠,或者轮循暂停操作,wait使用于多线程之间的通信——例如a唤醒b
  • yield()执行后线程立马进入就绪状态,马上释放cpu的执行权,进入就绪状态
  • join()执行后线程进入阻塞状态
    • 例如在线程b中调用线程A的join(),那么B就会进入到阻塞状态,直至线程a结束,或者中断程序

十八、对线程安全的理解

线程安全就是要当有多个线程访问同一个资源对象的时候,做到像单线程操作资源对象时一样,调用之后可以得到正确的结果就是线程安全的

想要解决线程安全问题,就需要先知道哪些原因会导致出问题(判断一个程序是否有线程安全问题的标准)

A:是否为多线程环境

B: 是否有共享数据

C:是否有多条语句操作共享数据

十九、Thread和Runable接口的区别

这里就不得不看一下实现多线程的两种方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJpdBSGK-1648379907039)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20220308151127618.png)]

要说区别:Thread是一个类,runable是一个接口,

​ 单继承多实现么

二十、守护线程

为所有的非守护线程提供服务,任何一个守护线程都是整个JVM虚拟机中所有非守护线程的守护线程

一个添一群,战狼线程

依赖于整个进程而运行,如果其他的线程都结束了,没有其他的线程要执行了,程序就结束了,不会理会守护线程,直接中断

守护线程的举例:

​ GC垃圾回收,是一个典型的守护线程,当程序中没有任何在在运行的线程,系统就不会在产生垃圾,垃圾回收器也就没什么是干了,程序就会终止,垃圾回收器也会自动关闭

​ GC垃圾回收器,用于实时监控和管理系统中的可回收资源

二十一、并发、并行、串行的区别

串行是任务依次执行,时间上不会发生重叠

并行是,时间上重叠,但是两个任务同一时刻互不干扰的同时执行

并发:允许两个任务彼此干扰,同一时间点,只有一个任务一个任务执行,交替执行——时间片轮转

二十二、线程池

程序启动一个新线程成本是比较高,而使用线程池,可以很好地提高性能,尤其是要创建大量的生存周期很短的线程时,更要考虑使用线程池

线程池的好处:线程池中的每一个线程代码结束后,并不会死亡,而是再回到线程池中变为空闲的状态,等待下一个对象来调用

===========================================================================

Mysql

常用的语句

​ insert into 表名(字段名)values(对应的值)

​ delete from 表名 where(条件)

​ update 表名 set字段名=值1,字段名2=值2、、、where 条件

​ select 字段名 from 表名

分组——group by

排序——order by

分页——limt

表连接

  • 内连接
    • a join b on 条件
  • 外连接
    • 左外连接
      • a left join b on
    • 右外连接
      • a right join b on

事务的四大特性:

  • 原子性、统一性、隔离性、持久性

存储引擎——innoDB——支持事务

===========================================================================

二十三、Spring是什么

Spring是一个轻量级的控制反转和面向切面编程的容器框架

  • 通过控制反转(IOC)来达到松耦合的目的

  • 提供了面向切面编程的支持,

  • 管理bean对象的配置和什么周期,算是一个容器

二十四、对AOP的理解

在不影响原有功能的基础上,进行横向拓展对源方法进行一个增强

底层就是动态代理

代理分为动态代理和静态代理

静态代理可以实现对原有方法的一个增强,但是有弊端,就是一个被代理的角色,就会产生一个代理,会增加代码量,为了解决这一弊端,就产生了动态代理

所谓的动态代理就是,代理类是自动生成的,而不是自己直接写的

  • ​ 动态代理分为两类

    • 以接口的动态代理:JDK动态代理
    • 一个类的动态代理:cglib
  • 需要了解的两个类:

    • Proxy****代理——提供了创建动态代理类和实例的静态方法——也就是proxy.方法,可以创建一个代理的实例——

    • InvocationHandler**:调用处理程序——反射包下的一个接口——每个代理实例都有一个关联的调用处理程序,在代理实例上调用这个方法时,方法将调用实现该接口中的程序的invoke方法**

image-20220308162041712
 public interface userDao {
	    public  int add(int a,int b);
	}
 
public class userDaoImpl implements userDao {

	    @Override
	    public int add(int a, int b) {
	        return a+b;
	    }
}

 class UserDaoProxy implements  InvocationHandler{
    //因为这里是想给userdaoimpl添加的代理对象,这里就需要把对象给传递过来,这样原本对象中的方法还是存在的
    private Object target ;

    public UserDaoProxy( Object target) {
        this.target =target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("增强方法了,在原方法执行之前执行");
        Object res=method.invoke(target,args );
        System.out.println(res);
        System.out.println("原方法之后执行");
        return res ;
    }
}
public class test {
    public static void main(String[] args) {
        //这里作为参数传递的类对象,一定要以多态的形式传递、因为这种方法面向的是接口
       userDao  user=new userDaoImpl();
        Class [] interfaces={userDao.class}; 
        //这里的产生的代理是userImple的代理对象,使用来接收
        //实际增强的是接口,这里必须要拿接口来接收创建的实例
        //代理类和用户类,之间共同实现了同一个接口,要用这个一个共同的接口来接收创建的对象
        userDao user1=(userDao) Proxy.newProxyInstance (test.class.getClassLoader(),  interfaces , new UserDaoProxy(user )); 
        user1.add(1,2); 
    }
}

AOP操作有两种实现方式:

方式一:使用Spring的API接口【】

方式二:自定类实现AOP【自定义切面】

方式三:使用注解的方式实现AOP操作

二十五、对IOC的理解

从三方面将:容器概念,控制反转、依赖注入

**IOC容器:**实际上就是一个map(key,value)集合——key是bean标签中的id value是值,里面存的是各种对象,在项目启动的时候会读取配置文件中的bean节点,然后根据类名使用反射创建对象,放在map集合中,通过或者扫描打上注解的类创建的对象放到map结合中

此时map中已经有对象了,还需要对这些对象进行属性的注入,DI注入

  • 属性的注入

    • DI依赖注入:

      ​ 通过set方法注入

      ​ 通过构造方法通过注入——需要使用标签:constructor-arg来对属性进行注入

      • 对于复杂属性的注入——通过外部bean,来引用
        • 即在bean标签外创建好需要引用的值然后用过ref来引用

控制反转:

  • ​ 例如原本对象A依赖于对象B,在A初始化或者要使用到B的时候必须手动的区创建B的实例或者调用已经创建好的对象B,无论创建还是使用对象B,控制权都在A自己的手上
  • 引入IOC容器之后,对象A和B之间失去了直接的联系,在对象A中需要用到对象B的时候,IOC容器会主动的创建B的实例,注入到A中需要使用的地方,
  • A有原本的主动创建或使用,到被动的注入,这就是控制反转

所有对象的控制权(创建、赋值)都会交给IOC容器,这时IOC容器就是整个系统的关键,将所有的对象融合在了一起

依赖注入:

获取对象的过程被反转了,在控制被反转之后,获取依赖对象的过程由本来的自身管理,变成了由IOC容器主动注入的一个过程,依赖注入是实现了IOC的方法,在IOC容器的运行期间,动态的将某种依赖关系注入到对象中

二十六、beanFactory和ApplicationContext的区别

这两个是Spring提供的IOC容器的实现的两种方式——两个接口

​ (1):beanFactory: IOC容器的基本实现,是spring内部的使用接口,开发中一般不去使用

​ 特点:在加载配置文件时,不会创建对象,只有在使用的时候才去创建对象

​ (2):**ApplicationContext[焦1] :beanFactory接口的子接口,**有很多强大的功能,再开发中经常使用

​ 特点:在加载配置文件的时候,就创建对象


[焦1]在服务器启动的时候执行代码,读取XML文件,在服务器完全启动的时候对象就已经创建完毕,而不是等到,使用的时候再去创建,把耗时好资源的过程都交给服务器 来完成

在实际的使用中,使用的是ApplicationContext的两个子类来实现创建

ApplicationContext的两个实现类:

FileSystemXmlApplicationContext**:后面要写上配置文件在磁盘中的绝对路径(磁盘中位置)例如:E:\Frame\bean1.xml**

ClassPathXmlApplicationContext**:后面要写上配置文件在该项目的中的位置 例如在src下的文件直接写文件名加后缀:bean1.xml**

​ ( 再哪个包下文件要带上包名/文件名)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值