Java相关的知识点

401 阅读32分钟

JAVA部分:

  1. JVM内存划分? www.cnblogs.com/ymerge/p/93… blog.csdn.net/suifeng629/… blog.itpub.net/69917606/vi… blog.csdn.net/u012485165/…
  2. 常见的GC回收算法及其含义? www.jianshu.com/p/3fc4450e1…
  3. java代码块,静态代码块,内部类,静态内部类的加载时机? blog.csdn.net/dreamsever/… 这个加载时机最好自己写个demo运行一下,能更深刻的理解和方便记忆
  4. Java 重载与重写是什么?有什么区别? blog.csdn.net/qunqunstyle…
  5. Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock: www.cnblogs.com/yeya/p/1020…
  6. C++和java的区别和联系? www.cnblogs.com/tanrong/p/8…
  7. 什么是HTTP的长连接和短连接? www.cnblogs.com/cswuyg/p/36…
  8. http请求方法有哪些:? blog.csdn.net/potato512/a…
  9. HTTP1.0、HTTP1.1、HTTP2和HTTPS的对比? www.jianshu.com/p/883fd0277…
  10. HashMap讲解? mp.weixin.qq.com/s/AuGv8xLWy…
  11. Java中的浅复制和深复制? blog.csdn.net/weixin_3881…
  12. 什么是CAS机制? blog.csdn.net/qq_32998153…
  13. Java类加载过程? www.cnblogs.com/luohanguo/p…
  14. NIO、BIO、AIO的原理及区别与应用场景? blog.csdn.net/qq_36907589…
  15. 红黑树原理及插入删除操作: blog.csdn.net/weixin_3965…
  16. Java 中的 equals,==与 hashCode 的区别与联系? www.cnblogs.com/xiaofangcun…

Java相关的知识点

JDK1.8 新特性(stream、lambda 表达式、接口 default 方法)

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简单来说,Stream API 提供了一种高效且易于使用的处理数据的方式。

final关键字有什么作用,可以修饰什么东西?
  1. ,该类不能被继承。
  2. 变量,如果是基本类型,则值不可变。如果是引用类型,则变量的引用不能变。
  3. 方法,该方法不能被重写。
  4. 参数,同修饰变量的作用一样。 但是作用域在此方法内。
线程和进程的关系?

线程: 每个进程中至少包含一个线程,而这些线程都在共享进程的资源空间等,当线程发生变化的时候只会引起CPU执行的过程发生变化,不会改变进程所拥有的资源。进程中执行运算的最小单位,亦是执行处理机调度的基本单位

进程: 每个进程都有自己的地址空间,资源如,内存,I/O,CPU,同一个进程里的 线程共享本进程里的地址空间,那能不能使用别人家进程的地址空间呢,显然这是不可以的。

Java进程间通信?

1. 管道(PIPE) 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 2. 命名管道(FIFO) 名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 3. 信号(Signal) 用于通知接收进程某个事件已经发生,主要作为进程间以及同一进程不同线程之间的同步手段。 4. 信号量(Semaphore) 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。 5. 消息队列(MessageQueue) 消息队列是消息的链表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 6. 共享内存(Shared Memory) 共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。 特点: 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。 因为多个进程可以同时操作,所以需要进行同步。 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。 7. 套接字(Socket) 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信

Java线程间通信?

blog.csdn.net/wlddhj/arti…

一、传统线程通信synchronized + wait + notify

Object类的wait()、notify() 、notifyAll()三个方法必须由同步监视器对象来调用,分两种情况:

a)同步方法,该类默认实例(this)就是同步监视器,可以在同步方法中可以直接调用

b)同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用此对象调用这三个方法

二、使用Condition控制线程通信lock + condition + await + signal

Lock代替同步方法或同步代码块,Condition替代同步监视器的功能。

private final Lock lock = newReentrantLock();

private final Condition con =lock.newCondition();

lock.lock(); con.await(); con.signalAll(); lock.unlock():

三、使用阻塞队列(BlockingQueue)控制线程通信

BlockingQueue接口主要作为线程同步的工具。当生产者试图向BlockingQueue中放入元素,如果队列已满,则线程被阻塞;当消费者试图向BlockingQueue中取出元素时,若该队列已空,则线程被阻塞。

数组和链表的区别和联系,他们是线程安全的吗?

答:

链表与数组的主要区别:

(1)数组的元素个数是固定的,而组成链表的结点个数可按需要增减;

(2)数组元素的存储单元在数组定义时分配,链表结点的存储单元在程序执行时动态向系统申请:

(3)数组中的元素顺序关系由元素在数组中的位置(即下标)确定,链表中的结点顺序关系由结点所包含的指针来体现。

(4)对于不是固定长度的列表,用可能最大长度的数组来描述,会浪费许多内存空间。

(5)对于元素的插人、删除操作非常频繁的列表处理场合,用数组表示列表也是不适宜的。若用链表实现,会使程序结构清晰,处理的方法也较为简便。

链表与数组的联系:

ArrayList数组和LinkedList链表都是不同步的,也就是不保证线程安全。

数组和链表的区别

从逻辑结构来看

数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费;数组可以根据下标直接存取。

链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项,非常繁琐)链表必须根据next指针找到下一个元素

从内存存储来看

(静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小

链表从堆中分配空间, 自由度大但是申请管理比较麻烦

从上面的比较可以看出,如果需要快速访问数据,很少或不插入和删除元素,就应该用数组;相反, 如果需要经常插入和删除元素就需要用链表数据结构了。

怎么保证线程安全?

答:

一、线程安全在三个方面体现

1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);

2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);

3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。 解决方法:

对非安全的代码进行加锁控制;

使用线程安全的类;

多线程并发情况下,线程共享的变量改为方法级的局部变量。

线程同步

1、同步方法

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

2、同步代码块

synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动加上内置锁,从而实现同步

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

a.volatile关键字为域变量的访问提供一种免锁机制

b.使用volatile修饰域相当于告诉虚拟机该域可能被其他现象更新

c.因此每次使用该域就要重新计算,而不是使用寄存器中的值

d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

4:使用重入锁实现线程同步

在javaSE5.0新增了一个java.concurrent包来支持同步。ReentrantLock类可以重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具体相同的基本行为和语义,并且扩展了其能力

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

如果使用ThreadLocal管理变量,则每一个使用变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

在并发情况中,如何控制创建线程的情况?

1.自定义线程池

线程状态的切换
  1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
  2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
  3. 阻塞(BLOCKED):表示线程阻塞于锁。
  4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
  5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
  6. 终止(TERMINATED):表示该线程已经执行完毕。
怎么实现多线程(线程有哪些状态,哪些锁,各种锁的区别)
  1. 继承Thread类

  2. 实现Runnable接口

  3. 实现Callable接口

  4. 线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。

创建线程的方式,他们有什么区别?

1.继承Thread类实现多线程

2.覆写Runnable()接口实现多线程,而后同样覆写run().推荐此方式

3.覆写Callable接口实现多线程(JDK1.5)

4.通过线程池启动多线程

线程池一般用在什么情况下?

1.单个任务处理的时间比较短 2.将需处理的任务的数量大

知道线程池吗?说说对线程池的理解?

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等待,等其它线程执行完毕,再从队列中取出任务来执行。

线程池由任务队列和工作线程组成,它可以重用线程来避免线程创建的开销,在任务过多时通过排队避免创建过多线程来减少系统资源消耗和竞争,确保任务有序完成

ThreadPoolExecutor 继承自 AbstractExecutorService 实现了 ExecutorService 接口,ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor 实现了 ExecutorService 和 ScheduledExecutorService 接口

Synchronized 关键字原理

实现原理: JVM 是通过进入、退出 对象监视器(Monitor) 来实现对方法、同步块的同步的,而对象监视器的本质依赖于底层操作系统的 互斥锁(Mutex Lock) 实现。

具体实现是在编译之后在同步方法调用前加入一个monitor.enter指令,在退出方法和异常处插入monitor.exit的指令。

对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程monitor.exit之后才能尝试继续获取锁。

blog.csdn.net/weixin_3675…

谈谈你对锁的了解

1.目的: 为什么要上锁,主要还是多线程的原因。多线程可能对同一块数据同时操作,数据可能会异常,比如,一个map,A线程把对键值对删除,B线程读取键值对,然后段错误就产生了。

并发编程:synchronized 和 volatile 、ReentrantLock 、CAS 的区别

被synchronized修饰的代码段可以防止被多个线程同时执行,必须一个线程把synchronized修饰的代码段都执行完毕了,其他的线程才能开始执行这段代码。

volatile关键字的作用就是保证了可见性和有序性(不保证原子性),如果一个共享变量被volatile关键字修饰,那么如果一个线程修改了这个共享变量后,其他线程是立马可知的。

synchronized 多用于在多个线程中需要对同一段数据进行访问时候,出现的不安全情况。因为多个线程执行同一段代码会造成数据不安全,所以需要用synchronized来同步代码。

ReenTrantLock可重入锁和synchronized同步锁的区别总结

1、可重入性:

从名字上理解, ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大。两者都是同一个线程每进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

2、锁的实现:

Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的,有什么区别,说白了就类似于操作系统来控制实现和用户自己敲代码实现的区别。前者的实现是比较难见到的,后者有直接的源码可供阅读。

3、性能的区别:

在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

4、功能区别:

便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

5、锁的细粒度和灵活度:

很明显ReenTrantLock优于Synchronized

synchronized 修饰实例方法和修饰静态方法有啥不一样。

答:

  1. Synchronized修饰非静态(实例)方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。

两个线程会依次执行,说明产生互斥,因为实例方法加锁针对的是实例对象,当前对象调用一个synchronized方法时,其他同步方法需要等待其执行结束并释放锁之后才能执行。

  1. Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”
  • **用类直接在两个线程中调用两个不同的同步静态方法:结果:**产生互斥,因为对静态方法加锁,实际上是对类加锁,类只有一个。因此当一个同步静态方法被访问时,该类已处于被锁状态。此时其他同步静态方法不能被访问(未用synchronized修饰的静态方法仍可以访问)
  • **两个线程分别调用同步类方法和同步实例方法:结果:**不会互斥,锁对象不同,一个是对实例对象加锁,一个对类加锁,因为静态方法不属于某个实例,而属于类本身。
解释一下死锁

两个/多个线程占有锁的前提又去获得其他锁,这样造成的线程无限的循环等待,产生了死锁!

sleep 、wait、yield 的区别,wait 的线程如何唤醒它

答:

  • sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。
  • wait()方法与sleep()方法的不同之处在于,wait()方法会释放对象的“锁标志”。当调用某一对象的wait()方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。当调用了某个对象的notifyAll()方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。
  • yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。
  • notify()方法就能唤醒wait的线程
了解过 Java 的集合吗?

答:

Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。

Collection

Map

说说 HashMap 的底层实现原理?

答:

**1.**从结构实现来讲,HashMap是数组+链表+红黑树(链表长度大于8时转换成红黑树,小于6时变为单项链表)(JDK1.8增加了红黑树部分)实现的

2. map.put(k,v)实现原理:

第一步:首先将k,v封装到Node对象当中(节点)。

第二步:它的底层会调用K的hashCode()方法得出hash值。

**第三步:**通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。

3. map.get(k)实现原理:

**第一步:**先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。

**第二步:**通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。重点理解如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

为什么放在hashMap集合key部分的元素需要重写equals方法?

因为equals默认比较是两个对象内存地址

HashMap扩容机制

HashMap默认的“加载因子”是0.75,默认的容量大小是16;增加容量时,每次将容量变为“原始容量x2”。

介绍下 HashTable

Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

HashMap与Hashtable的不同点

1 继承和实现方式不同

HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。 Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。

2 线程安全不同

Hashtable的几乎所有函数都是同步的,即它是线程安全的,支持多线程。 而HashMap的函数则是非同步的,它不是线程安全的。

3 对null值的处理不同

HashMap的key、value都可以为null。 Hashtable的key、value都不可以为null。

4 遍历方式不同

HashMap只支持Iterator(迭代器)遍历。此种迭代方式,HashMap是“从前向后”的遍历数组;Hashtabl是“从后往前”的遍历数组;而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。

5 添加元素时的hash值算法不同

HashMap添加元素时,是使用自定义的哈希算法。

Hashtable没有自定义哈希算法,而直接采用的key的hashCode()。

6 容量的初始值和增加方式不一样

HashMap默认的“加载因子”是0.75,默认的容量大小是16;增加容量时,每次将容量变为“原始容量x2”。 Hashtable默认的“加载因子”是0.75,默认的容量大小是11;增加容量时,每次将容量变为“原始容量x2 + 1”。

HashMap 和 ConcurrentHashMap 的区别

HashMap不是线程安全的;而ConcurrentHashMap 是线程安全的,但是效率有点慢

hashmap是线程安全的吗?怎么解决?怎么保证多线程安全?

不是线程安全的;

1、继承HashMap,重写或者按要求编写自己的方法,这些方法要写成synchronized,在这些synchronized的方法中调用HashMap的方法 2、使用Collections.synchronizedMap() 3、使用ConcurrentHashMap替代,并不推荐新代码使用Hashtable,HashTable继承于Dictionary,任意时间只有一个线程能写Hashtable,并发性能不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。不需要线程安全的场景使用HashMap,需要线程安全的场合使用ConcurrentHashMap替换。

ArrayList 和 LinkedList 的区别?

大致区别:

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

Java 集合中哪些是线程安全的?

Vector:就比Arraylist多了个同步化机制(线程安全)。

Hashtable:就比Hashmap多了个线程安全。

ConcurrentHashMap:是一种高效但是线程安全的集合。

Stack:栈,也是线程安全的,继承于Vector。

Vector(白客特)、HashTable、Properties是线程安全的;

ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。

ArrayList对应的线程安全的类是什么?

Vector(白客特)

Java的四大引用(强引用、软引用、弱引用、虚引用的区别以及使用场景。)
  • 强引用:垃圾回收器打死都不会回收掉一个强引用的,那怕是出现OOM也不会回收掉强引用,所有new出来的都是强引用。
  • 软引用:垃圾回收器会在内存不足的情况下回收掉软引用,如果内存充足的话不会理它
  • 弱引用:它跟软引用类似,但是它更脆弱,只要垃圾回收器一发现它,就会立刻回收掉它。比如一个对象持有一个强引用和弱引用,当强引用被取消时,那么只要GC发现了它,就会立刻回收掉。只是GC发现它的这个过程是不确定的,有可能不会马上发生,所以它可能还会多活一会,中间存在一个优先级。
  • 虚引用:它跟上面3种方式都不同。我对虚引用的理解就是如果一个对象持有虚引用,那么就可以在被GC回收前进行一些设定好的工作等等。因为虚引用有个机制,因为虚引用必须和引用队列联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就回在回收对象的内存前,把这个虚引用加入到与之关联的引用队列中。而程序如果判断到引用队列中已经加入了虚引用,那么就可以了解到被引用的对象马上就要被垃圾回收了,这个时候就可以做些被回收之前的事情啦。
JVM 的内存模型?

根据JVM规范,JVM 内存共分为五类:虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。

java中的内存区域?

内存区域是指 Jvm 运行时将数据分区域存储。

类加载机制

整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Useing)、卸载(Unloading)7个阶段。其中验证、准备和解析3个部分统称为连接(Linking),

  1. 加载:通过ClassLoader加载class文件字节码,生成Class对象。
  2. 校验:校验加载字节码的安全性和正确性。
  3. 准备:为类变量分配内存并设置类变量初始的零值。
  4. 解析:将常量池内的符号引用替换为直接引用。
  5. 初始化:将类进行初始化,执行类构造器(类变量赋值和静态语句块)。 5. 初始化:将类进行初始化,执行类构造器(静态语句块),可能执行类的构造函数(如果new对象的话先执行类构造器,再执行类的构造函数)。“new对象会执行类构造器”此时还是类加载过程,“再执行类的构造函数”此时好像已经脱离类加载过程,到了对象的创建过程了。这个地方概念还是有点模糊,待我把对象的创建过程复习一下,再来总结!!!
  6. 使用:使用这个类进行相关操作。
  7. 卸载:不用了,被JVM垃圾回收了。

加载

“加载”是“类加载”过程的一个阶段,由类加载器来完成,主要做以下3件事:

  1. 通过一个类的全限定名来获取此类的二进制字节流。
  2. 将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据接口。
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

验证

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的二进制字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

主要进行如下4个验证:

  1. 文件格式验证 验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。
  2. 元数据验证 对字节码描述的信息进行语义分析,以确保其描述的信息符合Java语言规范的要求。
  3. 字节码验证 通过数据流和控制流分析确定成行语义是合法的、符合逻辑的。
  4. 符号引用验证 对类自身以外的信息(常量池中的各种符号引用)进行匹配性校验。

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段, 这些变量所使用的内存都将在方法区中进行分配。

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程

初始化

类初始化阶段是类加载过程的最后一步,在这一阶段才开始执行类中定义的Java代码(字节码)。初始化阶段是执行类构造器 ()方法(类构造器就是“类变量的赋值动作+静态语句块”)的过程。

简单的说下 Java 的垃圾回收?

www.cnblogs.com/aspirant/p/…

JVM 内存共分为五类:虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生、随线程而灭,因此这几个区域的内存分配和回收都具备确定性,就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。而Java堆区和方法区则不一样、不一样!(怎么不一样说的朗朗上口),这部分内存的分配和回收是动态的,正是垃圾收集器所需关注的部分。

java的垃圾标记算法

Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。

引用计数法:

引用计数法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的,可以当做垃圾收集。

可达性分析算法:

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

java中垃圾回收算法

Java中存在着四种垃圾回收算法,标记清除算法、复制算法、标记整理算法以及分代回收算法。

1.标记清除算法

该算法分为“标记”和“清除”两个阶段:标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。它是最基础的收集算法

2.复制算法

为了解决效率问题,我们开发出了复制算法。它可以将内存分为大小相同的两块,每次使用其中的一块。当第一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

简单来说就是该对象分为对象面以及空闲面,对象在对象面上创建,对象面上存活的对象会被复制到空闲面,接下来就可以清除对象面的内存。

3.标记整理算法

为了解决复制算法的缺陷,充分利用内存空间,提出了标记整理算法。该算法标记阶段和标记清除一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。

4.分代收集算法

当前虚拟机的垃圾收集都采用分代收集算法,这种算法就是根据具体的情况选择具体的垃圾回收算法。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

StringBuffer 是如何实现线程安全的?

**答:**因为 StringBuffer 的所有公开方法都是 synchronized 修饰的

String ,stringBuilder和stringBuffer区别

**答:区别1:**StringBuffer:线程安全,StringBuilder:线程不安全。因为 StringBuffer 的所有公开方法都是 synchronized 修饰的,而 StringBuilder 并没有 synchronized修饰。

**区别2:**缓冲区 StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串。而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。所以,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。

**区别3:**既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。

介绍一下你对反射的理解,它的应用场景是什么:?

所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。

Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method。

Java反射的作用:在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。

什么是序列化

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。

抽象类和接口的区别是什么?

1、抽象类可以提供某些方法的部分实现,而接口不可以;

2、抽象类是单个继承机制,其子类不一定要实现父类中的所有没实现的方法,而接口一个类可以有多个接口,并且方法都要实现。

数据结构中常用排序算法?

冒泡排序、快速排序

如何实现对象的排序?
关于 Java 中深拷贝和浅拷贝的区别?

最根本的区别在于是否真正获取一个对象的复制实体,而不是引用

深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

了解注解吗?

可以对程序作出解释,方便被其他程序(编辑器)读取

你平常是怎么进行加密的?

MD5

MD5 加密是可逆的吗?

不可逆的

static 方法可以被覆盖吗?为什么?

不可以,覆盖(override)是在继承+多态的前提下的概念。Java中的静态方法不多态,所以不涉及覆盖,无论静态方法是在基类还是派生类上。

Java 中关于 equals 和 hashcode 的理解?
面向对象的三大特性,如何理解其中的多态?

封装的概念

  封装性是面向对象编程的核心思想

  指的就是将描述某种实体的数据和基于这些数的操作集合到一起,形成一个封装体

  封装的思想保证了类内部数据结构的完整性,使用户无法轻易直接操作类的内部数据,这样降低了对内部数据的影响,提高了程序的安全性和可维护性。

继承的概念

  继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

  继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或类从父 类继承方法,使得子类具有父类相同的行为。

多态的概念

多态指的就是在应用程序中出现的“ 重名 ” 现象。多态性允许以统一的风格编写程序,以处理种类繁多的已存在的类及其相关类。这样既降低了维护难度,又节省了时间

你知道哪些设计模式?为什么要这样用?能解决什么问题?

创建者模式又叫建造者模式,是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。

  • 在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。

  • 方便用户创建复杂的对象(不需要知道实现过程)

  • 代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)

Mysql索引

1.普通索引index :加速查找 2.唯一索引 主键索引:primary key :加速查找+约束(不为空且唯一) 唯一索引:unique:加速查找+约束 (唯一) 3.联合索引 -primary key(id,name):联合主键索引 -unique(id,name):联合唯一索引 -index(id,name):联合普通索引 4.全文索引fulltext :用于搜索很长一篇文章的时候,效果最好。 5.空间索引spatial :了解就好,几乎不用

zhuanlan.zhihu.com/p/29118331

在什么情况下不适合加索引

(频繁改动和删除的数据、数据量小、区分度小的字段(比如性别))

索引失效的情况

(不满足最左前缀原则、where 后面不能用函数)