栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

关于我们的java基础

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于我们的java基础

没有多好的开场,只有充分的知识.

一丶List和set的区别

list: 有序,可以按对象的顺序保存对象,可重复,允许多个null元素对象,可以使用iterator取出所有元素,在逐一遍历,还可以使用get(int index)获取下标的指定的元素。

set:无序,不可重复,最多允许有一个null对象,取元素时只能用itertor接口取得所有元素,在逐一遍历各个元素。

二丶hashCode与equals

hashCode的介绍

hashCode()的作用是获取哈希,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用确定该对象在哈希表中的索引位置。hashCode()定义在JDK的object.java中,java中的任何类都包含有hashCode()函数。散列表存储的键值对(key-value),它的特点是:能根据“键”快速的检查出对应的“值”。这其中就利用到了散列码!(可以快速的找到所需要的对象)

为什么要有hashCode 

以“Hashse如何检查重复”为例子来说明为什么要有hashCode“


如果两个对象相等,则hashcode一定也是相同的

两个对象相等,对两个对象分别调用equals方法都返回true

两个对象相同的hashcode值,她们也不一定相等的

因此,equals方法被覆盖过,则hashcode方法必须被覆盖

hashcode()的默认行为是对堆上的对线产生独特值。如果没有重写hashcode()则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

三丶面向对象

什么是面向对象?

对比面向过程,是两种不同的处理问题的角度

面向过程更注重的每一个步骤顺序,面向对象更注重事情有哪些参与者(对象),及各自需要做什么

比如:洗衣机洗衣服

面向过程会将任务拆解成一系列的步骤(函数),1、打开洗衣机-->2、放衣服---->放洗衣粉---->4、清洗---->5、烘干

面线对象会拆出人和洗衣机两个对象

人:打开洗衣机 放衣服 放洗衣粉

洗衣机:清洗 烘干 

从以上例子能看出,面向过程比较直接搞笑,面向对象更易用于复用,扩展和维护

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

内部细节对外部调用透明,外部调用无需修改或者关心内部实现,

1、javabean的属性私有,提供getset对外访问,因为属性的赋值或者获取逻辑只能有javabean本身决定。而不能有外部胡乱修改

private String name;
public void setName(String name){
        this.name ="tui"+name;
}
该name有自己的命名规则,明显不能由外部直接赋值

2、orm框架

操作数据库,我们不需要关心连接是如何建立的,sql是如何执行的,只需要引入mybatis,调用方法即可

继承:继承基类的方法,并做出自己的改变和扩展

子类共性的方法或者属性直接使用父类的,而不需要自己在定义,只需扩展自己个性化的

多态:给予对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。

继承:方法重写,父类引用指向子类对象

父类类型 变量名 = new 子类对象;

变量名.方法名();

无法调用子类特有的功能

 四丶==和equals比较

== 对比的是栈中的值,基本数据类型 是变量值,引用类型是堆中内存对象的地址

equals:object中默认也是采用==比较,通常会重写

Object

public boolean equals(Object obj){
    return(this == obj);
}

String

public boolean equals(Object anObject){
    if(this == anObject){
        return true;
}
}

五丶final

最终的

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

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

修饰变量:表示变量一旦被赋值就不可以改变它的值

(1)修饰成员变量

如果final修饰的是类变量,只能在静态初始化块中指定初始值或者生命该类变量时指定初始值。

如果final修饰的是成员变量,可以在非静态初始化块,声明该变量或者构造器中执行初始值。

(2)修饰局部变量

系统不会为局部变量进行初始化,局部变量必须有程序员显示初始化,因此使用final修饰局部变量时,既可以在定义时指定默认值(后面的代码不能对变量在赋值),也可以不指定默认值,而在后面的代码中final变量赋初值(仅一次)

(3)修饰基本类型数据和引用类型数据

如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;

如果是引用类型的变量,则在对齐初始化之后便不能再让其指向另一个对象。但是引用的值是可变的。

将局部变量复制为内部类的成员变量时,必须保证这两个变量时一样的,也就是如果我们在内部类中修改了成员变量,方法中的局部变量也的得跟着改变,怎么解决问题呢?

就将局部变量设置为final,对它初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协,使得局部变量与内部类内建立的拷贝保持一致。

六丶重载和重写的区别

重载:发生在同一类中,方法名必须相同。参数类型不同,个数不同,顺序不同,方法返回值和修饰符可以不同,发生在编译时。

重写:发生在父子类中,方法名,参数类表必须相同,返回值范围小等于父类,抛出的异常范围小于等于父类,访问修饰符范围大雨等于父类,如果父类方法访问修饰符为private则子类就不能重写该方法。

七丶接口和抽象类的区别 

·抽象类可以存在普通成员函数,而接口中只能存在public abstract方法。 ·抽象类可以存在普通成员函数,而接口中只能存在public abstract方法。

·抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。·抽象类只能继承一个,接口可以实现多个。 ·抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是公共静态最终类型的。·抽象类只能继承一个,接口可以实现多个.

接口的设计目的,是对类的行为进行约束(更准确的说是一种"有"约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为。它只约束了行为的有无,但不对如何实现行为进行限制。| 接口的设计目的,是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为.它只约束了行为的有无,但不对如何实现行为进行限制.|

而抽象类的设计目的,是代码复用。当不同的类具有某些相同的行为(记为行为集合A),且其中一部分行为的实现方式一致时(A的非真子集,记为B),可以让这些类都派生于一个抽象类。在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现。正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。 而抽象类的设计目的,是代码复用.当不同的类具有某些相同的行为(记为行为集合A)、且其中一部分行为的实现方式一致时(A的非真子集,记为B)、可以让这些类都派生于一个抽象类.在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现.正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。

抽象类是对类本质的抽象,表达的是is a的关系,比如: BMw is a car。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现。 抽象类是对类本质的抽象,表达的是是一辆的关系,比如:宝马是一辆汽车。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现.

而接口是对行为的抽象,表达的是like a的关系。比如: Bird like a Aircraft(像飞行器一样可以飞),但其本质上 is a Bird。接口的核心是定义行为,即实现类可以做什么,至于实现类主体是谁、是如何实现的,接口并不关心。 而接口是对行为的抽象,表达的是like a的关系。比如: Bird like a Aircraft(像飞行器一样可以飞),但其本质上 is a Bird。接口的核心是定义行为,即实现类可以做什么,至于实现类主体是谁、是如何实现的,接口并不关心。、

使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。 使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口.

抽象类的功能要远超过接口,但是,定义抽象类的代价高。因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且你可以在一个类中同时实现多个接口。在设计阶段会降低难度 抽象类的功能要远超过接口,但是,定义抽象类的代价高.因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类.在这个类中,你必须继承或编写出其所有子类的所有共性.虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述.而且你可以在一个类中同时实现多个接口.在设计阶段会降低难度

八丶ArrayList和linkedList区别 ArrayList和linkedList区别

ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能、甚至超过linkedList(需要创建大量的node对象) ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组,然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能、甚至超过linkedList(需要创建大量的node对象)

linkedList:基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询:需要逐一遍历遍历linkedList必须使用iterator不能使用for循环,因为每次for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历,性能消耗极大。 linkedList:基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询:需要逐一遍历遍历linkedList必须使用迭代器不能使用循环,因为每次for循环体内通过Get(I)取得某一元素时都需要对List重新进行遍历,性能消耗极大。

另外不要试图使用indexOf等返回元素索引,并利用其进行遍历,使用indexlOf对list进行了遍历,当结果为空时会遍历整个列表。 另外不要试图使用索引等返回元素索引,并利用其进行遍历,使用索引对列表进行了遍历,当结果为空时会遍历整个列表。

九丶HashMap和HashTable有什么区别?其底层实现是什么? HashMap和HashTable有什么区别?其底层实现是什么?

区别︰

(1) HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全;(2) HashMap允许key和value为null,而HashTable不允许 (1)HashMap方法没有同步修饰,线程非安全,HashTable线程安全;(2)HashMap允许Key和Value为和Value为,而HashTable不允许

⒉.底层实现:数组+链表实现 2.底层实现:数组+链表实现

jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在·计算key的hash值,二次hash然后对数组长度取模,对应到数组下标, Jdk 8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在·计算Key的Hash值,二次Hash然后对数组长度取模,对应到数组下标,

·如果产生hash冲突,先进行equal比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表 ·如果产生散列冲突,先进行等于比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表

. key为null,存在下标O的位置 . key为null,存在下标O的位置

数组扩容 

十丶如何实现一个IOC容器
1、配置文件配置包扫描路径
2、递归包扫描获取.class文件
3、反射、确定需要交给loc管理的类

4、对需要注入的类进行依赖注入
·配置文件中指定需要扫描的包路径
·定义一些注解,分别表示访问控制层、业务服务层、数据持久层、依赖注入注解、获取配置文件注解
·从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹信息,我们将当前路径下所有以.class结尾的文件添加到一个Set集合中进行存储
·遍历这个set集合,获取在类上有指定注解的类,并将其交给IOC容器,定义一个安全的Map用来存储这些对象
·遍历这个IOC容器,获取到每一个类的实例,判断里面是有有依赖其他的类的实例,然后进行递归注入
 

十二丶什么是字节码?采用字节码的好处是什么?


java中的编译器和解释器:
Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。


编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(即扩展名为.class的文件),它不面向任何特定的处理器,只面向虚拟机。


每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。这也就是解释了Java的编译与解释并存的特点。
Java源代码--->编译器--->jvm可执行的Java字节码(即虚拟指令)-->jvm--->jvrm中解释器---->机器可执行的二进制机器码---->程序运行。


采用字节码的好处:
Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

十三丶Java类加载器


JDK自带有三个类加载器:bootstrap ClassLoader、IExtClassLoader、AppClassLoader。
BootStrapClassLoader是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%lib下的jar包和class文件。


ExtClassLoader是AppClassLoader的父类加载器,负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类。AppClassLoader是自定义类加载器的父类,负责加载classpath下的类文件。
继承ClassLoader实现自定义类加载器

十四丶Java中的异常体系


Java中的所有异常都来自顶级父类Throwable。Throwable下有两个子类Exception和Error。
Error是程序无法处理的错误,一旦出现这个错误,则程序将被迫停止运行。


Exception不会导致程序停止,又分为两个部分RunTimeException运行时异常和CheckedException检查异常。RunTimeException常常发生在程序运行过程中,会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中,会导致程序编译不通过。

十五丶线程的生命周期?线程有几种状态
1.线程通常有五种状态,创建,就绪,运行、阻塞和死亡状态。

2.阻塞的情况又分为三种:
(1)、等待阻塞:运行的线程执行wait方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池"中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify或notifyAll方法才能被唤醒,wait是object类的方法


(2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则VM会把该线程放入"锁池"中。


(3)、其他阻塞:运行的线程执行sleep或join方法,或者发出了IV/o请求时,JVM会把该线程置为阻塞状态。当sleep状态超时、join等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。sleep是Thread类的方法


1.新建状态(New)︰新创建了一个线程对象。
2就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3.运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4.阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

5.死亡状态(Dead) :线程执行完了或者因异常退出了run方法,该线程结束生命周期。

十六丶对线程安全的理解


不是线程安全、应该是内存安全,堆是共享内存,可以被所有线程访问


当多个线程访问一个对象时,如果不用进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得正确的结果,我们就说这个对象是线程安全的
堆是进程和线程共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部电y走用厂刀E工I问J。
选择语言
堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是用完了要还给操作系统,要不然就是内存泄漏。


在Java中,堆是Java虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域,在虚拟机启动时创建。堆所存在的内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。


栈是每个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是线程安全的。操作系统在切换线程的时候会自动切换栈。栈空间不需要在高级语言里面显式的分配和释放。


目前主流操作系统都是多任务的,即多个进程同时运行。为了保证安全,每个进程只能访问分配给自己的内存空间,而不能访问别的进程的,这是由操作系统保障的。
在每个进程的内存空间中都会有一块特殊的公共区域,通常称为堆(内存)。进程内的所有线程都可以访问到该区域,这就是造成问题的潜在原因。

十七丶对守护线程的理解


守护线程:为所有非守护线程提供服务的线程;任何一个守护线程都是整个JVM中所有非守护线程的保姆;
守护线程类似于整个进程的一个默默无闻的小喽喽;它的生死无关重要,它却依赖整个进程而运行;哪天其他线程结束了,没有要执行的了,程序就结束了,理都没理守护线程,就把它中断了;
注意:由于守护线程的终止是自身无法控制的,因此千万不要把IO、File等重要操作逻辑分配给它;因为它不靠谱;

守护线程的作用是什么?
举例,GC垃圾回收线程:就是一个经典的守护线程,当我们的程序中不再有任何运行的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。


应用场景: (1)来为其它线程提供服务支持的情况;(2)或者在任何情况下,程序结束时,这个线程必须正常且立刻关闭,就可以作为守护线程来使用;反之,如果一个正在执行某个操作的线程必须要正确地关闭掉否则就会出现不好的后果的话,那么这个线程就不能是守护线程,而是用户线程。通常都是些关键的事务,比方说,数据库录入或者更新,这些操作都是不能中断的。


thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个llegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。


在Daemon线程中产生的新线程也是Daemon的。
守护线程不能用于去访问固有资源,比如读写操作或者计算逻辑。因为它会在任何时候甚至在一个操作的中间发生中断。
lava自带的多线程框架,比如ExecutorService,会将守护线程转换为用户线程,所以如果要使用后台线程就不能

十八丶ThreadLocal内存泄露原因,如何避免


内存泄露为程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光,
不再会被使用的对象或者变量占用的内存不能被回收,就是内存泄露。


强引用:使用最普遍的引用(new),一个对象具有强引用,不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。


如果想取消强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样可以使VM在合适的时间就会回收该对象。


弱引用:JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。可以在缓存中使用弱引用。


ThreadLocal的实现原理,每一个Thread维护一个ThreadLocalMap,key为使用弱引用的ThreadLocal实例,value为线程变量的副本

十九丶并发、并行、串行的区别


串行在时间上不可能发生重叠,前一个任务没搞定,下一个任务就只能等着并行在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行。
并发允许两个任务彼此干扰。统一时间点、只有一个任务运行,交替执行

二十丶线程池中阻塞队列的作用?为什么是先添加列队而不是先创建最大线程?


1、一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲长度,就无法保留当前的任务了,阻塞队列通过阻塞可以保留住当前想要继续入队的任务。
阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。


阻塞队列自带阻塞和唤醒的功能,不需要额外处理,无任务执行时;线程池利用阻塞队列的take方法挂起,从而维持核心线程的存活、不至于一直占用cpu资源


2、在创建新线程的时候,是要获取全局锁的,这个时候其它的就得阻塞,影响了整体效率。


就好比一个企业里面有10个(core)正式工的名额,最多招10个正式工,要是任务超过正式工人数(task >core)的情况下,工厂领导(线程池)不是首先扩招工人,还是这10人,但是任务可以稍微积压一下,即先放到队列去(代价低)。10个正式工慢慢干,迟早会千完的,要是任务还在继续增加,超过正式工的加班忍耐极限了(队列满了),就的招外包帮忙了(注意是临时工)要是正式工加上外包还是不能完成任务,那新来的任务就会被领导拒绝了(线程池的拒绝策略)。

二十二丶谈谈你对AOP的理解


系统是由许多不同的组件所组成的,每一个组件各负责一块特定功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件。


当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。


日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。


AOP:将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。AOP可以对某个对象或某些对象的功能进行增强,比如对象中的方法进行增强,可以在执行某个方法之前额外的做一些事情,在某个方法执行之后额外的做一些事情
10/

二十三丶描述一下Spring Bean的生命周期?


1、解析类得到BeanDefinition
2、如果有多个构造方法,则要推断构造方法3、确定好构造方法后,进行实例化得到一个对象
4、对对象中的加了@Autowired注解的属性进行属性填充
5、回调Aware方法,比如BeanNameAware,BeanFactoryAware
6、调用BeanPostProcessor的初始化前的方法
7、调用初始化方法
8、调用BeanPostProcessor的初始化后的方法,在这里会进行AOP9、如果当前创建的bean是单例的则会把bean放入单例池
10、使用bean
11、Spring容器关闭时调用DisposableBean中destory()方法

二十四丶Spring框架中的单例Bean是线程安全的么?


Spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。
如果Bean是有状态的那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域把"singleton"改为"protopyte'这样每次请求Bean就相当于是new Bean()这样就可以保证线程的安全了。


·有状态就是有数据存储功能
·无状态就是不会保存数据
controller、service和dao层本身并不是线程安全的,只是如果只是调用里面的
方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。


Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,Spring的事务管理器使用


Threadlocal为不同线程维护了一套独立的connection副本,保证线程之间不会互相影响(Spring是如何保证事务获取同一个connection的)


不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

二十五丶Spring 框架中都用到了哪些设计模式?


简单工厂:由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

工厂方法:
实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getobject()方法,所以返回的不是factory这个bean,而是这个bean.getojbect()方法的返回值。


单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
spring对单例的实现: spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是任意的java对象。

装饰器模式:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有wrapper,另一种是类名中含有Decorator。


动态代理:
切面在应用运行的时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象。springAOP就是以这种方式织入切面的。
织入:把切面应用到目标对象并创建新的代理对象的过程。


观察者模式:
spring的事件驱动模型使用的是观察者模式,Spring中0bserver模式常用的地方是1istener的实现。


策略模式:
Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源。

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351816.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号