java总结

1.重载(Overloading)和重写(Overriding)

重载(overload)位于一个类之中或者其子类中。方法名必须相同,参数列表不一样,访问修饰符和返回值类型可以相同也可以不同。

重写(override):一般都是表示子类和父类之间的关系,其主要的特征是:方法名相同,参数相同,但是具体的实现不同。

(1):方法名必须相同,返回值类型必须相同

(2):参数列表必须相同

(3):访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。

(4):子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。

(5):构造方法不能被重写。

(6):异常可以减少或删除,但不能增加。

2.封装、继承、多态

封装:

类的某些信息隐藏在内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。

 

继承:

继承是类与类的一种关系,子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有)从而实现了实现代码的复用。

扩展:父类中被private修饰的方法表示仅在该类可见,所以子类没有继承到父类的private方法,因此,若子类定义了一个与父类的private方法相同的方法名和参数列表也是没问题的,相当于子类自己定义了一个新的方法

而父类中被final修饰的方法表示不可以被子类重写,若子类定义了相同的方法则编译无法通过父类中的final方法,子类不能够重写,但是可以调用

多态:

父类引用可以指向本类对象,也可指向子类对象。引用多态的强大主要体现在调用属性、方法时,可以根据引用具体指向的对象去调用,例如:子类中重写了父类方法

单一职责原则:一个类的功能要单一。

开放封闭原则:一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。

里式替换原则子类应当可以替换父类并出现在父类能够出现的任何地方。

依赖倒置原则:具体依赖抽象,上层依赖下层。

接口分离原则:设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。

3.值类型和引用类型的区别

值类型是基本数据类型8种,其余都是引用类型。基本数据类型的赋值是值传递,当值类型变量a赋值给值类型变量b之后,再去改变a的值那么b不会随着a的改变而改变。引用值类型的赋值是引用传递,传递的是对象的引用地址。当引用值类型变量a赋值给引用值类型变量b之后,再去改变a的值那么b会随着a的改变而改变。

值类型数据是直接存储在栈中,Java JVM直接在栈中给数据开辟了一块空间,直接存储数据的值。

引用类型数据并不是直接存储在栈中,Java JVM会在堆中给数据分配内存空间,堆存储数据。栈存储的是指向对应堆的地址。可以说是栈中的地址引用了堆中的数据。

4.操作字符类型比较

操作字符串的类有:StringStringBufferStringBuilderString 声明的是不可变的对象,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉StringBuffer StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer

5.四中方式实现多线程

1.一种是继承 Thread 类,

2.另一种就是实现 Runnable 接口

实现多线程,一种是继承 Thread 类,另一种就是实现 Runnable 接口。在线程启动虽然调用的是 start() 方法,但实际上调用的却是 run() 方法定义的主体。Thread 类也是 Runnable 接口的子类,在 Thread 类中的 run() 方法调用的是 Runnable 接口中的 run() 方法,也就是说此方法是由 Runnable 子类完成的,所以如果要通过继承 Thread 类实现多线程,则必须覆写 run()。线程一般具有5种状态,即创建,就绪,运行,阻塞,终止。

3.实现Callable接口

通过FutureTask包装器来创建Thread线程,与实现Runnable口的区别。实现Callable接口的任务线程能返回执行结果,Callable接口的call()方法允许抛出异常。Runnable接口的run()方法的异常只能在内部消化,不能继续上

       public class CallableImpl implements Callable<String>

        Callable<String> callable = new CallableImpl("my callable test!");

        FutureTask<String> task = new FutureTask<>(callable);

        // 创建线程

        new Thread(task).start();

4.通过线程池ExecutorService 来实现多线

      Java通过Executos(Executors.newCachedThreadPool();)提供线程池分为以下几种:

newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor、newSingleScheduledThreadExecutor以上线程池的实现均基于ThreadPoolExecutor

1newCachedThreadPool创建一个可缓存线程池

2newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数。

3newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

4newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务

public static ExecutorService newCachedThreadPool() {

 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

 } 

参数:

1)核心线程数为0;

2)最大线程数为Interger.MAX_VALUE,即0x7fffffff(2147483647)

3)线程空闲时长为60秒,如果空闲超过60秒,则线程将被终止,并移出缓存。

4)该线程池,使用J.U.C的 SynchronousQueue阻塞队列,该队列具有以下几个特性:

    没有容量,每一个put操作必须要等待一个take操作,否则不能继续添加元素,反之亦然。一个生产线程,当它生产产品(即put的时候),如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线程调用take操作,take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传递),这样的一个过程称为一次配对过程(当然也可以先take后put,原理是一样的)。

    线程池按以下行为执行任务

1、如果当前线程池的线程数还没有达到基本大小(poolSize < corePoolSize)无论是否有空闲的线程新增一个线程处理新提交的任务;

2、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列未满时,就将新提交的任务提交到阻塞队列排队,等候处理workQueue.offer(command)

3、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列满时

3.1、当前poolSize<maximumPoolSize,那么就新增线程来处理任务;

3.2、当前poolSize=maximumPoolSize,那么意味着线程池的处理能力已经达到了极限,此时需要拒绝新增加的任务。至于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler

创建状态 

在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时它已经有了相应的内存空间和其他资源,但还处于不可运行状态。新建一个线程对象可采用Thread 类的构造方法来实现,例如 “Thread thread=new Thread()”。

  • 就绪状态 

新建线程对象后,调用该线程的 start() 方法就可以启动线程。当线程启动时,线程进入就绪状态。此时,线程将进入线程队列排队,等待 CPU 服务,这表明它已经具备了运行条件。

  • 运行状态 

当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。run() 方法定义该线程的操作和功能。

  • 阻塞状态 

一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入/输出操作,会让 CPU 暂时中止自己的执行,进入阻塞状态。在可执行状态下,如果调用sleep(),suspend(),wait() 等方法,线程都将进入阻塞状态,发生阻塞时线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。

  • 死亡状态 

线程调用 stop() 方法时或 run() 方法执行结束后,即处于死亡状态。处于死亡状态的线程不具有继续运行的能力。

Java 运行时至少会启动两个线程,一个是 main 线程,另外一个是垃圾收集线程。

新提交一个任务时的处理流程

1、如果当前线程池的线程数还没有达到基本大小(poolSize < corePoolSize)无论是否有空闲的线程新增一个线程处理新提交的任务

2、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列未满时,就将新提交的任务提交到阻塞队列排队,等候处理workQueue.offer(command)

3、如果当前线程池的线程数大于或等于基本大小(poolSize >= corePoolSize) 且任务队列满时

3.1、当前poolSize<maximumPoolSize,那么就新增线程来处理任务;

3.2、当前poolSize=maximumPoolSize,那么意味着线程池的处理能力已经达到了极限,此时需要拒绝新增加的任务。至于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler

6.多线程同步方法

加锁的原因:多线程访问共享数据的时候,数据就会发生错误

使用重入锁ReentrantLock实现线程同步

可重入锁:同一线程对某一锁多次加锁不会产生死锁;

            private int account = 100;
            //需要声明这个锁
            private Lock lock = new ReentrantLock();
            public int getAccount() {
                return account;
            }
            //这里不再需要synchronized 
            public void save(int money) {
                lock.lock();
                try{
                    account += money;
                }finally{
                    lock.unlock();
                }
                
            }

同步方法

        由于java的每个对象都有一个内置锁,当用synchronized修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

//存钱  

    public  synchronized void addMoney(int money){  

        count +=money;  

        System.out.println(System.currentTimeMillis()+"存进"+money);  

同步代码块

//存钱  

    public   void addMoney(int money){  

          

        synchronized (this) {  

            count +=money;  

        }  

        System.out.println(System.currentTimeMillis()+"存进:"+money);  

    } 

使用特殊域变量(volatile)实现线程同步

   volatile关键字为域变量的访问提供了一种免锁机制 
   使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新 
   因此每次使用该域就要重新计算,而不是使用寄存器中的值 
   volatile不会提供任何原子操作,它也不能用来修饰final类型的变

private volatile int count = 0;// 账户余

使用局部变量实现线程同步

  1.     private static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){  
  2.   
  3.         @Override  
  4.         protected Integer initialValue() {  
  5.             // TODO Auto-generated method stub  
  6.             return 0;  
  7.         }  
  8.           
  9.     }; 

7.Reentrant和synchronized区别

Synchronized  使用wait()、sleep()、join()进入阻塞,wait方法释放锁sleep不会,join()等待这个线程全部执行完后才继续执行接下来的进程。notify()唤醒一个被阻塞的线程,notifyAll()唤醒全部

ReentrantLock加锁更加灵活,tryLock()判断是否已经持有锁  还可以设置请求锁的时间。

使用condition  c1.await()阻塞线程,使用c1.singal()唤醒线程。

Stop(),destroy()方法终止线程已经被废弃  还有interrupt()向线程内部发送消息;

8.创建对象的5种方式

使用new关键字:Student student = new Student();

使用Class类的newInstance方法:Student student2 = (Student)Class.forName("根路径.Student").newInstance(); 或者:Student stu = Student.class.newInstance();

使用Constructor类的newInstance方法Constructor<Student> constructor = Student.class.getInstance(); Student stu = constructor.newInstance(); 这两种newInstance的方法就是大家所说的反射,事实上ClassnewInstance方法内部调用ConstructornewInstance方法

使用Clone的方法:必须先实现Cloneable接口并实现其定义的clone方法。如:Student stu2 = <Student>stu.clone();原型模式的应

使用反序列化:需要让我们的类实现Serializable接口。如:ObjectInputStream in = new ObjectInputStream (new FileInputStream("data.obj")); Student stu3 = (Student)in.readObject();

9.接口和抽象类的区别

抽象类就相当于一个模板,模板中有子类可以公用的部分,也有需要子类自行实现的部分,是为模板式设计,它同时具有多态性+复用性;
而接口是对行为的抽象,它只定义一组行为规范,每个实现类都要实现所有规范,叫辐射式设计,它只有多态性;

一个类可以实现多个接口,但只能继承一个抽象类。

抽象类可以有构造方法,接口中不能有构造方法。

抽象类和接口不能用于实例化对象

接口不能包含成员变量,除了 static final 变量。

接口中的方法可以是public defaultprivate

10.Lambda表达式和stream???

11.HashMap实现原理

数组+链表+红黑树的数据结构,当链表的元素个数大于8之后,如果数组的长度小于64则进行扩容,如果数组长度大于、等于64时链表将会转为红黑树。扩容的原因是,如果数组度还比较小,就先利用扩容来缩小链表的。当链表的元素个数小于8时链表整体的插入查询效率要高于红黑树,大于8时链表整体的插入查询效率要低于红黑树。

Put实现过程

    1. 根据key生成hashcode
    2. 判断当前HashMap对象中的数组是否为空,如果为空则初始化该数
    3. 根据逻辑与运算,算出hashcode基于当前数组对应的数组下标i
    4. 判断数组的第i个位置的元素(tab[i])是否为
      1. 如果为空,则将keyvalue封装为Node对象赋值给tab[i]
      2. 如果不为
        1. 如果put方法传入进来的key等于tab[i].key,那么证明存在相同的key
        2. 如果不等于tab[i].key
          1. 如果tab[i]的类型是TreeNode,则表示数组的第i位置上是一颗红黑树,那么将keyvalue插入到红黑树中,并且在插入之前会判断在红黑树中是否存在相同的key
          2. 如果tab[i]的类型不是TreeNode,则表示数组的第i位置上是一个链表,那么遍历链表寻找是否存在相同的key,并且在遍历的过程中会对链表中的结点数进行计数,当遍历到最后一个结点时,会将key,value封装为Node插入到链表的尾部,同时判断在插入新结点之前的链表结点个数是不是大于等于8,如果是,则将链表改为红黑
      3. 如果上述步骤中发现存在相同的key,则根据onlyIfAbsent标记来判断是否需要更新value值,然后返回oldValue
    5. modCount++ (哈希表被修改的次数)
    6. HashMap的元素个数size1
    7. 如果size大于扩容的阈值,则进行扩

Get实现过程

  1. 根据key生成hashcode
  2. 如果数组为空,则直接返回
  3. 如果数组不为空,则利用hashcode和数组度通过逻辑与操作算出key所对应的数组下标i
  4. 如果数组的第i个位置上没有元素,则直接返回
  5. 如果数组的第i个位上的元素的key等于get方法所传进来的key,则返回该元素,并获取该元素的value
  6. 如果不等于则判断该元素还有没有下一个元素,如果没有,返回
  7. 如果有则判断该元素的类型是链表结点还是红黑树结
    1. 如果是链表则遍历链
    2. 如果是红黑树则遍历红黑
  8. 找到即返回元素,没找到的则返回

12.ArrayList实现原理

ArrayList是一个动态数组,实现了List<E>, RandomAccess, Cloneable, Serializable,并允许包括null在内的所有元素初始容量为10.当超出后,会自动扩容为原来的1.5倍。

如果要添加海量数据时,为了避免N次扩容,可以使用带参数的构造函数;

成员变量:

默认容量大小 DEFAULT_CAPACITY=10

空数组(当ArrayList的构造方法中显示指出ArrayList的数组长度为0时,类内部将EMPTY_ELEMENTDATA 这个空对象数组赋给elemetData数组。)

Object[] EMPTY_ELEMENTDATA = {};

用于保存ArrayList中数据的数组(transient,意味着在序列化的时候此字段是不会被序列化的)

Object[] elementData;

ArrayList中所包含元素的个数,size是按照调用addremove方法的次数进行自增或者自减的,所以add了一个null进入ArrayListsize也会加1

 private int size;

add(E e)

先调用ensureCapacityInternalsize+1传入的容量和默认的容量比较,返回大的数,来判断是否需要扩容,需要扩容时调用 grow(int minCapacity)方法扩容,//记录当前list的容量

int oldCapacity = elementData.length;

// 扩展为原来的1.5

int newCapacity = oldCapacity + (oldCapacity >> 1);

// 如果扩展1.5倍还不能满足,直接扩展为需求值

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;,接着末尾插入数据,所以ArrayList是按插入的顺序排序

Add实现方法:

get(int index)

get函数会检查索引值是否合法(只检查是否大于size,而没有检查是否小于0)。如果所引致合法,则调用elementData(int index)方法获取值。在elementData(int index)方法中返回元素数组中指定下标的元素,并且对其进行了向下转型

ArrayList 实现了3个标记接口

RandomAccess:说明该类支持随机访问,大部分是基于数组实现

遍历方式:如果实现了RandomAccess接口    jvm遍历  用  for循环   否则用  迭代器

Cloneable:说明该类支持拷贝

浅拷贝:

创建一个新的对象,将当前对象的非静态字段复制到新对象。如果字段是值类型,直接在栈中复制;如果字段是引用类型,复制栈中的引用,不复制堆中的对象,栈中原始的对象和新对象,指向堆中同一个引用。

浅拷贝实现方式

  1. 通过构造函数实现

构造方法参数为该类的对

//构造方法
public Person(Person p) {
        this.name=p.name;
        this.age=p.age;
    }

        

//使用

Person p1=new Person(a,"摇头耶稣");

       Person p2=new Person(p1);

  1. 实现Cloneable接口,重写clone()

//重写Object类的clone方法

    public Object clone() {

        Object obj=null;

        //调用Object类的clone方法,返回一个Object实例

        try {

            obj= super.clone();

        } catch (CloneNotSupportedException e) {

            e.printStackTrace();

        }

        return obj;

    }

深拷贝:

创建一个新的对象,将当前对象的非静态字段复制到新对象中。无论该字段的类型是值类型还是引用类型。修改其中一个对象内容的时候,另一个对象的内容不会收到影响。

深拷贝实现方式:

  1. 让每个引用类型属性内部都重写clone()
  2. 利用序列
Student stu1=new Student("摇头耶稣",a,175);
        //通过序列化方法实现深拷贝
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(stu1);
        oos.flush();
ObjectInputStream ois=new ObjectInputStream(new      ByteArrayInputStream(bos.toByteArray()));
     Student stu2=(Student)ois.readObject();

使用Object的super.clone()方法,拷贝的对象是非独立的。

拷贝的都是栈中的内容;

Serializable:网络传输,写磁盘

SerialVersionUID:类文件的签名,如果不写死,添加属性或方法  值会改变  反序列化失败;

数组特点:不可变的在内存中是连续的,只能存储相同类型的元素

13.红黑树

二叉查找树(BST)、平衡二叉树(AVL树)、TreeMap

BST:左子树上所有结点的数据域均小于或等于根结点的数据域,右子树上所有结点的数据域均大于根结点的数据域

AVL: 左子树与右子树的高度之差的绝对值不超过1

如果数据递增或者递减 BST会退化为链表,红黑树相比AVL树平衡条件更加宽松,节点插入的时候对树的更改小。

红黑树平衡条件,左右深度差一倍以内

AVL左子树和右子树深度差小于等于一

14.ThreadLocal实现原理

线程局部变量,只有当前线程能够访问。为每一个使用该变量的线程都提供一个变量值的副本,每个线程都是改变自己的副本并且不会和其他线程的副本冲突。常用于spring事务管理@transactional控制connection。

Thread内部有个threadLocals指向 ThreadLocal.ThreadLocalMap对象,可以理解为是个Map初始为null。调用set()方法的时候,就是将数据写入到ThreadLocalMap这个对象中,key为ThreadLocal当前对象,value就是我们存入的值。Get()方法就是直接获取当前线程的ThreadLocalMap对象,如果该对象不为空就返回它的value值,否则就把初始值(initialValue()调用方法)设置到ThreadLocal中并返回。

static ThreadLocal<Integer> local = new ThreadLocal<Integer>(){

        @Override

        protected Integer initialValue() {

            return 0;

        }

    };

15.对象的引用

强引用:使用的大部分引用实际上都是强引用,使用new()当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。;gc回收的时候调用finalize()

 String str = "abc";

 List<String> list = new Arraylist<String>();

 list.add(str);

软引用(SoftReference):如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。适合做缓存

        A a = new A();           

        SoftReference<A> sr = new SoftReference<A>(a); 

弱引用(WeakReference):垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

    Car car = new Car(22000,"silver");

    WeakReference<Car> weakCar = new WeakReference<Car>(car);

虚引用(PhantomReference):给垃圾回收器消息,用于回收堆外内存(堆外内存不归GC管,jvm来回收),虚引用必须和引用队列(ReferenceQueue)联合使用

16.队列

一个先入先出(FIFO)的数据结构,在消息处理的时候特别费时间,这个时候如果有新消息来了,就只能处于阻塞状态,造成用户等待Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接 口。

add(E), offer(E) 在尾部添加,add() 方法在添加失败(比如队列已满)时会报 一些运行时错误 错;而 offer() 方法即使在添加失败时也不会奔溃,只会返回 false

remove(), poll() 删除并返回头部,当队列为空时 remove() 方法会报 NoSuchElementException 错; 而 poll() 不会奔溃,只会返回 null。

element(), peek() 获取头部元素但不删除,当队列为空时 element() 抛出异常;peek() 不会奔溃,只会返回 null

17.git管理代码机制

18.PriorityQueue优先队列原理

PriorityQueue通过二叉小顶堆实现,用一棵完全二叉树表示(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。通过公式计算出某个节点的父节点以及子节点的下

leftNo = parentNo*2+1   rightNo = parentNo*2+2       parentNo = (nodeNo-1)/2

offer(E):

先判断传入值是否为空,如果是空就抛异常

如果非空先扩容在调用siftUp(i,e);

获得父节点判断是否大于父节点,如果不是就互换位置

remove()和poll():

调用siftDown()方法,与当前点的左右子节点中较小的那个交换,直到x小于或等于左右子节点的任何一个为止。

19.反射的实现原理和使用

反射机制:将类的各个组成部分封装成其他对象

好处:可以在程序运行中,操作这些对象;解耦。

假设磁盘上有N.java文件,首先我们把这些java文件编译成class文件,继而java虚拟机启动会把这些class文件load到内存,当遇到new关键字的时候会根据类的模板信息实例化这个对象也就是在堆上面分配内

获取Class对象的四种方式:

1.Calss.forname(“全类名”):将字节码文件加载进内存,返回Class对象。

2.类名.class: 通过类名的属性class获取;

3.对象.getClass():Object中存在此方法;

4.类加载器ClassLoader.loadClass(“全类名”);

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论用哪种方法获取得到的Class类都是同一个。

暴力反射:

Class类常用方法:

例子:

20.linkedlist实现原理

linkList 继承了AbstractSequentialList 实现了ListDequeCloneable以及Serializable接口

LinkedList中有int类型的size,和Node类型的first以及last全局变量。

Add()方法实现原理:

add方法会调用linkLast方法,会在链表尾端添加节

linkLast方法步骤

获取原来的last节点,然后创建一个新的节点,其prev为原来的last节点,其next节点为null

last指向新的节点

如果原来的last节点为null,其实就是还没有元素,那么新的节点同样也是first节点;如果不为null,则原来的last节点的next就是新的节点

因为有新元素加入,size1,且修改次数加1modCount++

方法add(int index, E element)实现原理:

1.检查指定index的值是否有效[0,size]

2.如果index == size 则使用linkLast添加在尾部;如果index != size, 则使用linkBefore将新元素添加在指定位置之前

linkBefore实现步骤:

获取插入节点的前节点,然后创建一个新的节点,prev插入节点的前节点,其next节点为插入节点

将新节点指向插入节点的前节点

如果插入节点的前节点为空,新的节点赋值给first节点,如果不为空,新的节点赋值插入节点的前节点的后节点。size1,且修改次数加1modCount++

Add方法:

add(int index, E element)方法:

remove(int index)

按照指定位置移除元素,主要包含如下几个部分:

检查index是否有效

通过node(index)查找index位置下的节点

使用unlink(Node<E> x)修改链表的连接关系,达到移除元素的效

get(int index)逻辑

检查指定的index的值是否有效

调用node(index)获取节点,返回值node(index).item即可

get(int index)实现方式:

node(int index)逻辑

先判断index和中间点(size >>1)位置的大小。如果index < (size >> 1), 那么按下标从小到大查找;否则,按下标从大到小查找~

unlink(Node<E> x)逻辑

记录element , 删除节点prev,next

判断prev是否为空,空first = next,如果不为空,前节点的下个节点为next且当前节点的前节点为空

判断next是否为空,空last=prev,如果不为空,后节点的前节点为prev且当前节点的后节点为空

清空x节点

Size - -

modCount ++

返回element

node(int index)实现方式

unlink(Node<E> x)实现方式

Node内部结构

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

LinkedList 实现 List 接口,能对它进行列表操作。

LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

21.RestFul和RPC的区别

RPC是基于TCP实现的,RESTFUL是基于HTTP来实现

从传输速度上来看,因为HTTP封装的数据量更多所以数据传输量更大,所以RPC的传输速度是比RESTFUL更快

网关和外界的数据传输使用RESTFUL,微服务内部的各模块之间使用RPC,因为HTTP协议是各个框架都普遍支

22.Eureka Zookeeper区别

 RDBMS==>(MySql,Oracle,SqlServer等关系型数据库)遵循的原则是:ACID原则(A:原子性。C:一致性。I:隔离性。D:持久性。)。

NoSql==>    (redis,Mogodb等非关系型数据库)遵循的原则是:CAP原则(C:强一致性。A:可用性。P:分区容错性)

————————————————

原文链接:https://blog.csdn.net/java_xth/article/details/82621776

 CAP 定理,即 C 为数据一致性;A 为服务可用性;P 分区容错

Eureka 是基于 AP 原则构建的,而 ZooKeeper 是基于 CP 原则构建的

  1. ZooKeeper保证cp:当向注册中心查询服务列表时,可以容忍返回的时几分钟以前的注册信息,但是不能接受服务直接down掉不可用,也就是说服务注册功能可用性高于一致性。但是ZooKeeper会出现这样的情况,当master节点因为网络问题和其他节点失去链接时,剩余节点会重新进行leader选举,问题在于选举时间过长30~120s,且选举期间整个ZooKeeper集群不可用,导致选举期间注册服务瘫痪。
  2. Eureka保证ap:每个节点都是平等的,几个节点挂掉不影响其他节点工作,剩余的节点可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册服务时如果发现链接失败,会自动切换到其他节点,只要一台Eureka还在,就能保证注册服务可用,只不过查到的信息可能不是最新的。除此之外,Eureka还有一种自我保护机制,如果再15分钟内超过85%的节点都没有正常的心跳,那么Eureka认为注册中心和客户端出现网络故障此时会出现:
    1. Eureka不再从注册中心移除因为长时间没收到心跳而应该过期的服务
    2. Eureka仍然能接受服务的注册和查询请求,但是不会同步到其他节点,保证当前节点依然可用
    3. 当网络稳定,当前节点新的注册信息会同步到其他节点中

23. Zookeeper?????

24.什么是微服务

微服务是一种架构风格:

是一组基于业务实现小服务,每个服务运行在独立进程中,服务之间使用轻量级通信,服务可独立部署,不需要集中式管理。

25.@Repository 和@Mapper的区别

DRUID    德鲁伊

@Mapper是mybatis自身带的注解,使用@Autowired爆红不耽误使用,可以idea提示降级或用@Resource消除

@Repository是spring提供的注释,使用该注解后,在启动类上要加@Mapperscan,来扫描

26. mybatis中#和$的区别

变量的传递,必须使用#,使用#{}就等于使用了PrepareStatement这种占位符的形式,提高效率。可以防止sql注入等等问题

$只是只是简单的字符串拼接,用于非变量部分,只能用$$方式一般用于传入数据库对象,比如这种group by 字段 ,order by 字段,表名,字段名等没法使用占位符的就需要使用${}

28.@RequestBody和@RequestParam区别

@RequestParam
注解@RequestParam接收的参数是来自requestHeader中,即请求头。用来处理 Content-Type application/x-www-form-urlencoded 编码的内容,Content-Type默认为该属性。也可用于其它类型的请求,例如:POSTDELETE等请求所以在postman中,要选择body的类型为 x-www-form-urlencoded,这样在headers中就自动变为了 Content-Type : application/x-www-form-urlencoded 编码格式

@RequestBody

注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/jsonapplication/xml等类型的数据。

GET请求中,因为没有HttpEntity,所以@RequestBody并不适用

27.Lombok常用注解

@NoArgsConstructor : 生成一个没有参数的构造

@AllArgsConstructor : 生成一个包含所有参数的构造

@RequiredArgsConstructor : 生成一个包含 "特定参数" 的构造器,特定参数指的是那些有加上 final 修饰词的变量

@Data整合包,只要加了 @Data 这个注解,等于同时加了以下注解

  • @Getter/@Setter
  • @ToString
  • @EqualsAndHashCode
  • @RequiredArgsConstructor

@Builder自动生成流式 set 值写法,从此之后再也不用写一堆 setter

@Builder 注解,我们就能够用流式写法快速设定对象的值,但是 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对他们取值/

29.RestTemplate

RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 executeRestTemplate 继承自 InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现

使用:

1.添加maven依赖

2.配置RestTemplateConfig

3.使用:

TempUser result = restTemplate.getForObject("http://localhost:8080/cs-admin/rest/getUser?userName={userName}&age={age}", TempUser.class, paramMap);

30.Spring Boot 自动配置原理是什么

约定大于配置

@SpringBootApplication中引用了@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan

@SpringBootConfiguration就是一个@Configuration啊,一个JavaConfig配置类

那我们使用JavaConfig不就是用来配置bean吗,所以有了这个注解之后我们可以在SpringBoot运行的主类中使用@Bean标签配置类了

@ComponentScan

组件扫描,扫描的范围是:SpringBoot主启动类的同级路径及子路径。

@EnableAutoConfiguration

其中@Import(AutoConfigurationImportSelector.class)AutoConfigurationImportSelector 这个类实现了ImportSelector接口,重写selectImports()方法,返回的是字符串数组存放是要加载的Config配置文件的全包名,通过返回这个全包名,我们就能自动装配上这些配置文件下定义的bean对象,从而达到了自动装配的目的。

通过getAutoConfigurationEntry()获得AutoConfigurationEntry,着里边保存着我们需要的配置信息。getAutoConfigurationEntry中调用getCandidateConfigurations()方法读取配置文件。这里边调用了spring给的SpringFactoriesLoader.loadFactoryNames(),根据Aessert断言在META-INF/spring.factories文件中找到自动配置类Config,配置文件里面的内容,加载了各种已经写好的Config类文件。loadFactoryNames()方法调用loadSpringFactories返回了一个包含我们需要的Config全类名(字符串)的集合容器MultiValueMap<String, String>,然后从这个集合容器中拿出来的东西就是我们的configurations, 通过静态变量找到路径,然后根据路径读取了配置文件,然后返回了读取的result

XML版本的从 IOC 容器中获取 bean 的实例ClassPathXmlApplicationContext使用

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

//2. 从 IOC 容器中获取 bean 的实例

HelloWorld  helloWorld = (HelloWorld) ctx.getBean("helloWorld");

<bean id="helloWorld" class="com.atguigu.spring.helloworld.HelloWorld">

<property name="user" value="Jerry"></property>

</bean>

注解版本的从 IOC 容器中获取 bean 的实例AnnotationConfigApplicationContext使用

public class outPutImpl {

    public void helloworld() {

        System.out.println("hellworld");

    }

}

@Configuration

public class hello {

    @Bean(name = "helloworl")

    public outPut impl() {

        return new outPutImpl();

    }

}

public class Client {

    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(hello.class);

        outPut outPut = (com.spring.lzx.interfacer.outPut) context.getBean("helloworl");

        outPut.helloworld();

    }

}

Spring BeanDefinition

主要成员变量:

private volatile Object beanClass; 这个属性决定了该Bean定义的真正class到底是

private int autowireMode = AUTOWIRE_NO;

自动装配模式默认是AUTOWIRE_NO,就是不开启自动装配

可选的常量值有以下四种:不自动装配,通过名称装配,通过类型装配,通过构造器装配

AUTOWIRE_NO

AUTOWIRE_BY_NAME

AUTOWIRE_BY_TYPE

AUTOWIRE_CONSTRUCTOR

private ConstructorArgumentValues constructorArgumentValues;

改变这个参数值,我们可以做到在实例化对象时指定特定的构造

AbstractBeanDefinitionspring中所有bean的抽象定义对象,当bean.classJVM类加载到内存中时,会被spring扫描到一个map容器中: BeanDefinitionMap<beanName, BeanDefinition>这个容器存储了bean定义,但是bean此时还没有进行实例化,在进行实例化之前,BeanFactoryPostProcessor可以对bean对象进行一些自定义处理。

31.springboot拦截器和过滤器???

32.Spring Boot中的监视器是什么

springboot提供用于监控和管理生产环境的模

1.依赖

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

    <version>2.0.4.RELEASE</version>

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

2.配置

spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true

spring.datasource.username=root

spring.datasource.password=123

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

server.tomcat.uri-encoding=UTF-8

# 程序运行端口

server.port=8888

# 监视程序运行端口

management.server.port=8090

# 激活所有的内置Endpoints

management.endpoints.web.exposure.include=*

# 开启shutdown这个endpoint

management.endpoint.shutdown.enabled=true 

3.加入上述依赖后,默认可以访问几个url

http://localhost:8080/actuator/health

http://localhost:8080/actuator/info

http://localhost:8080/actuator

33.springboot读取配置文件的方式

1.@value+@Configuration对配置的全局处理

1)直接在属性上面@value解(代码简洁,但是每次使用需要先new一个Confignature对象,或者@Autowired先注入)

2)属性上面加static关键字修饰,@value写在对应set方法上面(不需要new,可以其他类直接调用)

2.@ConfigurationProperties注解

新建一个配置类DatasourceConfig,注意属性名称要跟yaml配置文件一致。不能用static修饰属

3. Environment读取yaml配置文件

注入Environment

@value实现方式

ConfigurationProperties实现方式

Environment实现方式

34.spring bean生命周期

在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition。只有当getBean()调用时才是有可能触发Bean实例化阶段的活动

Bean实例(单例bean)生命周期的执行过程如下:

  1. Spring对bean进行实例化,默认bean是单例;
  2. Spring对bean进行依赖注入;
  3. 如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法;
  4. 如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例传进来;
  5. 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;
  6. 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization方法将被调用;
  7. 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法,类似的如果bean使用了init-method属性声明了初始化方法,则再调用该方法;
  8. 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用;
  9. 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  10. 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。如果bean使用了destroy-method属性声明了销毁方法,则再调用该方法;

35.Import导入bean定义方法

@Import支持 三种方式
1.带有@Configuration的配置类(4.2 版本之前只可以导入配置类,4.2版本之后 也可以导入 普通类)
2.ImportSelector 的实现
3.ImportBeanDefinitionRegistrar 的实

通过注解的形式导入bean

实现ImportBeanDefinitionRegistrar方法

实现ImportSelector方法

36.springbean注入的三种形式

1. setter注入

applicationContext.xml文件

2. 构造器注入

我们需要更改applicationContext.xml文件中的propertyconstruct-arg

3.属性注入

applicationContext.xml中开启注解支持和自动包扫描

pojo类中对Person类加上@Component注解,将其标记为组件,并且使用@Value注解为各属性赋初

37.Spring的两种配置方式:

PersonCar、有Dog

1 基于XML的配置

使用ClassPathXmlApplicationContext来加载配置文件,然后获取Bean

2 基于JavaConfig类的配置

使用AnnotationConfigApplicationContext来获取注解配

38.@Resource与@Autowired用法区别

@Resource是Java自己的注解,@Resource有两个属性是比较重要的,分是name和type;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

@Autowired是spring的注解,是spring2.5版本引入的,Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。

39. Redis 主从复制、哨兵和集群三者区别

主从复制是为了数据备份哨兵是为了高可用,Redis主服务器挂了哨兵可以切换,集群则是因为单实例能力有限,搞多个分散压力,简短总结如下:

主从模式:备份数据、负载均衡,一个Master可以有多个Slaves。

sentinel发现master挂了后,就会从slave中重新选举一个master。

cluster是为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器。

sentinel着眼于高可用,Cluster提高并发量。

1. 主从模式:读写分离,备份,一个Master可以有多个Slaves。

2. 哨兵sentinel:监控,自动转移,哨兵发现主服务器挂了后,就会从slave中重新选举一个主服务器。

3. 集群:为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。

40.RPC远程调用?????

41.分布式事务

2PC(Two-phase commit protocol

 基于XA协议是 X/Open DTP Group提出的定义的两段提交(2PC - Two-Phase-Commit)协,是一个同步阻塞协议,是一种强一致性设计2PC 引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段

准备阶段协调者会给各参与者发送准备命令,同步等待所有参与者的响应之后就进入提交阶段(提交事务/回滚事务)。假如所有参与者都返回准备成功,那么协调者则向所有参与者发送提交事务命令,然后等待所有事务都提交成功之后,返回事务执行成功。

假如有一个参与者返回失败,那么协调者就会向所有参与者发送回滚事务的请求,即分布式事务执行失败

如果第二阶段执行的是回滚事务操作失败,不断重试,直到所有参与者都回滚了,不然那些在第一阶段准备成功的参与者会一直阻塞着

如果第二阶段执行的是提交事务操作失败,不断重试,因为有可能一些参与者的事务已经提交成功了,直到提交成功,到最后真的不行只能人工介入处理

2PC 是一种尽量保证强一致性的分布式事务,它是同步阻塞的,而同步阻塞就导致长久的资源锁定问题,总体而言效率低,并且存在单点故障问题,在极端条件下存在数据不一致的风险2PC 适用于数据库层面的分布式事务场

Demo

package com.xiangxue.jack.xa;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;

import com.mysql.jdbc.jdbc2.optional.MysqlXid;

import javax.sql.XAConnection;

import javax.transaction.xa.XAResource;

import javax.transaction.xa.Xid;

import java.sql.Connection;

import java.sql.Statement;

public class XADemo {

    public static MysqlXADataSource getDataSource(String connStr, String user, String pwd) {

        try {

            MysqlXADataSource ds = new MysqlXADataSource();

            ds.setUrl(connStr);

            ds.setUser(user);

            ds.setPassword(pwd);

            return ds;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

    public static void main(String[] arg) {

        String connStr1 = "jdbc:mysql://118.89.107.162:3306/wjq";

        String connStr2 = "jdbc:mysql://118.89.107.162:3307/wjq";

        try {

            //从不同数据库获取数据库数据源

            MysqlXADataSource ds1 = getDataSource(connStr1, "root", "XXXXXXXX");

            MysqlXADataSource ds2 = getDataSource(connStr2, "root", "XXXXXXXX");

            //数据库1获取连接

            XAConnection xaConnection1 = ds1.getXAConnection();

            XAResource xaResource1 = xaConnection1.getXAResource();

            Connection connection1 = xaConnection1.getConnection();

            Statement statement1 = connection1.createStatement();

            //数据库2获取连接

            XAConnection xaConnection2 = ds2.getXAConnection();

            XAResource xaResource2 = xaConnection2.getXAResource();

            Connection connection2 = xaConnection2.getConnection();

            Statement statement2 = connection2.createStatement();

            //创建事务分支的xid

            Xid xid1 = new MysqlXid(new byte[]{0x01}, new byte[]{0x02}, 100);

            Xid xid2 = new MysqlXid(new byte[]{0x011}, new byte[]{0x012}, 100);

            try {

                //事务分支1关联分支事务sql语句

                xaResource1.start(xid1, XAResource.TMNOFLAGS);

                int update1Result = statement1.executeUpdate("UPDATE accounts SET BALANCE = CAST('9700.00' AS DECIMAL) WHERE CUSTOMER_NO = '001'");

                xaResource1.end(xid1, XAResource.TMSUCCESS);

                //事务分支2关联分支事务sql语句

                xaResource2.start(xid2, XAResource.TMNOFLAGS);

                int update2Result = statement2.executeUpdate("INSERT INTO user_purchase_his(CUSTOMER_NO, SERIAL_NO, AMOUNT, CURRENCY, REMARK) "

                        + " VALUES ('001', '20190303204700000001', 200, 'CNY', '购物消费')");

                xaResource2.end(xid2, XAResource.TMSUCCESS);

                // 两阶段提交协议第一阶段

                int ret1 = xaResource1.prepare(xid1);

                int ret2 = xaResource2.prepare(xid2);

                // 两阶段提交协议第二阶段

                if (XAResource.XA_OK == ret1 && XAResource.XA_OK == ret2) {

                    //引擎级别提交

                    xaResource1.commit(xid1, false);

                    xaResource2.commit(xid2, false);

                    System.out.println("reslut1:" + update1Result + ", result2:" + update2Result);

                } else {

                    xaResource1.rollback(xid1);

                    xaResource2.rollback(xid2);

                }

            } catch (Exception e) {

                e.printStackTrace();

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

42.Spring Boot中的事务管理 隔离级别

隔离级别

隔离级别是指若干个并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读取、重复读、幻读。

  • DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是:READ_COMMITTED
  • READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
  • READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
  • SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

@Transactional(isolation = Isolation.DEFAULT)

public enum Isolation {

    DEFAULT(-1),

    READ_UNCOMMITTED(1),

    READ_COMMITTED(2),

    REPEATABLE_READ(4),

    SERIALIZABLE(8);

}

传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。

  • REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED

@Transactional(propagation = Propagation.REQUIRED)

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
}

43.Volatile

volatile是一个变量修饰符,只能用来修饰变量。无法修饰方法及代码块等。

可见性:

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

原理:为了提高处理器的性能,在处理器和内存之间加了多级缓存,这样就呦缓存不一致问题。修改volatile修饰的变量值的时候,jvm会向处理器发送一个lock前缀的指令,将缓存中的变量写回到主内存中。其他处理器通过嗅探总线程上传播的数据来检查自己缓存的值是否过期,当处理器发现自己缓存行对应的内存地址被修改,就将当前缓存行设置为无效。当处理器对这个数据经行修改操作的时候,会强制重新从系统内存把数据读取到缓存中。这就保证了一个volatile修饰的变量在并发编程中,其值在多个缓存中是可见的。

有序性:

volatile可以禁止指令重排,这就保证了代码的程序会严格按照代码的先后顺序执行

44.加密算法:

常用的对称加密算法有:DES3DESRC2RC4AES

常用的非对称加密算法有:RSADSAECC

使用单向散列函数的加密算法:MD5SHA

45.Hashtable和ConcurrentHashMap的区别???

hashtable每次同步执行的时候都要锁住整个结构,ConcurrentHashMap将hash表分为16个桶。

ConcurrentHashMap初始化:

Put:方法

table存放数据:

46.HashMapHashtable的区别

HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。Hashtable所有的方法都是同步的。

47.CAS的思想

Unsafe.compareAndSwapInt(),此方法是Java的native方法,并不由Java语言实现。

方法的作用是,读取传入对象o在内存中偏移量为offset位置的值与期望值expected作比较。

相等就把x值赋值给offset位置的值。方法返回true。

不相等,就取消赋值,方法返回false。

这也是CAS的思想,及比较并交换。用于保证并发时的无锁并发的安全性。

48.BeanFactory和ApplicationContext的区别

ApplicationContextBeanFactory的子类,

BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化

启动的时候占用资源很少;对资源要求较高的应用,比较有优势; 

ApplicationContext在启动的时候就把所有的Bean全部实例化了系统运行的速度快。

49.Spring中Bean的五个作用域

singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例

prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例

request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效

session:对于每次HTTP Session,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效

globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

50. 判断Integer类型的值是否相等

当用“==”进行比较时,jvm默认是比较数据在java堆的地址int是一种基本数据类型,jvm会自动将Integer转成int数值进行比较。在Integer类中,有一个内部静态类IntegerCache ,用来支持自动拆箱和装箱,如下,数值范围[-128,127],如果在这个区间[-128,127]内,他就会把变量i当做一个变量,放到内存中,用“==”比较是会得出true;但如果不在这个范围内,就会去new一个Integer对象,当运用“==”时,会比较Integer两个对象地址,得出false

Rabbitmq????

JMeter高并发压测工具???

Aop????

Ioc?????

分布式消息机制:???

分布式搜索机制:??

Redis同步数据库????

Static

51static关键字

在类中,用static声明的成员变量为静态成员变量,也成为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效。

这里要强调一下:

static修饰的成员变量和方法,从属于类

普通变量和方法从属于对象

静态方法不能调用非静态成员,编译会报错

static关键字的用途

一句话描述就是:方便在没有创建对象的情况下进行调用(方法/变量)。

显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

static可以用来修饰类的成员方法、类的成员变量,另外也可以编写static代码块来优化程序性能

52. 判断线程池中的线程是否全部执行完毕

调用ExecutorService 中的awaitTermination()方法,等待子线程结束

Spring ???????

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值