自己总结的javaSE面试题

2021/6/17 1:24:13

本文主要是介绍自己总结的javaSE面试题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

se基础

1、面向对象深刻理解?

万物皆对象,比如在开发过程中,前端的一个请求就是一个对象,request对象。Class对象 , 异常在java中也是一个类,发生一个异常系统也就会生成一个异常对象。

面向对象三大特征:封装、继承、多态。

  1. 封装 :方法就是一种封装,比如开发中需要导入各种依赖。Json的依赖,Jwt的依赖

2.继承:就是子类继承父类的所有财产,但是实际应用中子类只能继承一个父类,而实际开发中一个类可能需要使用多个父类中的东西,这就出现了接口。一个类可以实现多个接口。(单继承吗,多继承)

3.多态: 父类引用向子类对象。比如我们经常使用的就是,List list = new ArrayList(); 在实际开发中也可以说是解耦吧,比如经理让你造一辆车,给你个父类,你只需在子类中实现功能。另一个同事也可以去造一个另一辆车,实现其他的功能。

2、Java语⾔和其他语⾔区别?

Java有自己的虚拟机,好处就是一次编译处处运行。

3、JRE、JDK、JVM区别?

JDK 是java开发工具包,里面包括JRE(java运行环境)和JVM

Jvm是建立在os操作系统上,相当于一个专为java开发用的虚拟计算机,里面有相应的堆,栈,方法区等。

JRE是java运行环境,里面有java运行时所需要的核心类库。

4、JDK1.8之前和JDK1.8之后接口不同?和jdk1.8 的新特性

(1) Jdk7及以前,接口中只能定义全局常量,和抽象方法

全局常量:public static final (但是书写时,可以省略)

抽象方法:pubic abstract

Jdk8, 除了可以定义全局常量和抽象方法之外,还可以定义静态方法,(default)默认方法。

(2)stream流 :一种流的思想,好比一个流水线,对数组和集合进行高效的操作。

Stream流的三类方法:

1,获取Stream流。

2,中间方法(skip跳过前几个,limit截取前几个, concat(Stream a , Stream b)合并流 filter 过滤)

3,终结方法,流水线上最后一个操作。 foeach(在foreach中可以新建一个集合用来结果封装), 和 count

(3)Lamba表达式:一种简化匿名内部类的开发方式。是一种函数式思想。

面向对象的思想:做一件事,找到一个能做这件事的对象,调用对象的方法。

函数式编程的思想:只要能获得结果,谁去做都行。

(4)Hashset 底层是哈希表 jdk8之前是数组+链表jdk8之后是数组+链表+红黑树

,1.8当链表长度为8时,再次添加自动将链表转换为红黑树。

在这里插入图片描述

5、接口和抽象类区别?

抽象类:指的是用abstract修饰的类或者类中有抽象方法。

接口:只有方法体没有具体的实现。用interface修饰

接口是一种规范,是抽象类的的变体。一个方法可以实现多个接口,但是只能继承一个抽象类。

在实际项目开发中,架构师一般会定义好接口,我们只需要在具体的业务中对接口进行实现。在多变的业务中,我们只需要改变相应的实现类。

如果在业务中,多个实现类有着相同可以复用的代码,这时候我们可以在实现类和接口之间,添加一个抽象类,把公共的代码抽取道抽象类中。

6,Java中的常用容器有哪些?

集合,数组

7,线程和进程有什么区别?

进程:一个在内存中运行的应用程序。一个进程可以有多个线程。比如360,可以一边杀毒,一边清理内存,他就是一个单进程,多线程的程序。

从操作系统角度上说:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。

从JVM的角度上说一个进程中可以有多个线程,多个线程共享进程的方法区 (JDK1.8 元空间方法区只是一个抽象的概念,元空间是具体的实现 )资源,但是每个线程有自己的程序计数器虚拟机栈本地方法栈

8,final、finally、finalize区别,怎么使⽤?

final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承

finally是异常处理语句结构的一部分,表示总是执行。

finalize,Object类的一个方法,在垃圾回收器执行的时候会被调用。当该方法被系统调用时则代表该对象即将“死亡”,但需要注意的是,我们主动行为上去调用该方法不会导致对象“死亡”,这是一个被动的方法,不需要我们调用。

9,局部变量和成员变量区别?

定义的位置不一样【重点】

局部变量:在方法的内部

成员变量:在方法的外部,直接写在类当中

作用范围不一样【重点】

局部变量:只有在方法当中才可以使用,出了方法就不能再用了

成员变量:整个类全都可以通用

默认值不一样【重点】

局部变量:没有默认值,如果要想使用,必须手动进行赋值

成员变量:如果没有赋值,会有默认值,规则和数组一样

内存的位置不一样(了解)

局部变量:位于栈(Stack)内存

成员变量:位于堆(Teap)内存

生命周期不一样(了解)

局部变量:随着方法进栈而诞生,随着方法出栈而消失

变量:随着类的创建而诞生,随着对象被垃圾回收而消失(静态方法使用局部变量,局部变量必须为final修饰)

10,值传递和引⽤传递区别?

**按值传递:**指在方法调用时,传递的参数是按照值得拷贝进行传递的。

**引用传递:**指的是在方法调用时,传递的参数是按引用进行传递,也就是变量所对应的内存空间的地址。

高斯林认为在JAVA中传递的方式都是为值传递,没有引用传递。(将引用地址看做值)

一般情况下,在数据做为参数传递的时候,基本数据类型是值传递,引用数据类型是引用传递(地址传递)。 String(字符串常量,常量值创建之后就不能改变)

11,==和equals区别?

==比较的是两个值的地址是否相同, equals是比较字符串的值是否相同

12,Hashcode和equals的区别?

在Java中任何一个对象都具备equals(Object obj)和hashCode()这两个方法,因为他们是在Object类中定义的

Hashcode方法,是将对象的地址值进行hash运算,得到的一组hash值。

可以看到,在Object类型的equals方法是直接通过来比较的,和是没有任何区别的。

那么为什么又要说equlas和==的区别呢?是因为equals方法是可以由我们自己重写的。

在hashMap中,Hashcode计算出来的哈希值相同,两个字符串的值不一定相同,所以在hashmap中存的类型,都得重写,hashcode方法和equals方法,是先进行hash值的比较,再进行equals的比较。
在这里插入图片描述

13,重载和重写区别?

重载:就是两个方法,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关.

比如:一般会出现类构造方法的重载,有参,和无参,还有在实际业务接口中,你想用id查询数据,或者用名称查询数据,都提供了响应的重载方法。

(1):方法名必须相同

(2):方法的参数列表一定不一样。

(3):访问修饰符和返回值类型可以相同也可以不同。

重写:方法名相同,参数相同,但是具体的实现不同。一般都是子类对父类方法的增强。或者接口,的实现类进行重写接口中的方法。

14, Java基本数据类型?

整型byte 、short 、int 、long 浮点型float 、 double 字符型char 布尔型boolean

15, 包装类和基本数据类型区别?为什么要提供包装类?

包装类就是对基本数据类型的增强,解决基本数据类型无法参与反射,泛型等问题。

java是面向对象进行编程的,而基本数据类型不是对象。

基本类不能为空,有默认值。

包装类可以为空。可以在泛型中使用。

自动装箱拆箱.

16, 构造器代码块、局部代码块、静态代码块执⾏顺序和执⾏次数?

Static修饰会随着类的加载,而进入方法区。

这是父类的静态代码快

这是子类的静态代码快

这是父类的构造代码快

这是父类的构造方法

这是子类的构造代码快

这是子类的构造方法

public parent() {
      System.out.println("父类构造函数");
    }

   static{
    System.out.println("父类静态块");
   }

 {
        System.out.println("父类构造代码f块");
 }

17、Integer是否可以被继承?为什么?

不能,因为看源码是被final修饰的,被final修饰的类不能被继承

18, Integer缓存区间?什么时候触发缓存区间?

IntegerCache.cache数组中至少缓存[-128,127]范围的Integer实例。 在这个区间类直接从缓冲区拿来用。

当数值不处于 【-128,127】区间时,将会直接 new Integer();进行新创建一个对象。

装箱:Integer a = 10;

拆箱:将包装类赋值给 基本数据类型

19,String、StringBuffer、StringBuild区别?是否线程安全?怎么做到线程安全?

String类:字符串是常量,它的值在创建之后就不能被改变了。每对String进行操作,都会生成新的String对象,不仅效率低下,而且浪费内存。

StringBuffer、StringBuild的出现是为了提高字符串的操作效率。

StringBuffer:(线程安全) 拼接方法append(),看源码相比于StringBuild每个方法都加了synchronized 关键字 ,成为了同步方法。

StringBuild:(线程不安全)

String底层也是用的StringBuilder在这里插入图片描述

StringBuilder在拼接的时候,只需要在堆内存中new一个对象就行了,然后调用append进行拼接。

在这里插入图片描述

集合

1,说说java中的集合:

集合可以分为两类:

(1)单列集合,Vector jdk1.0 最早的单列集合。底层也是一个数组和arrayList一样。Vector是同步的。同步就是单线程。(单线程就是慢)1.2后用ArrayList集合给取代了。

(2)双列集合

在这里插入图片描述

在这里插入图片描述

集合知识点学习:

Set(单列集合) 实现类: treeset 和 hashset 特点:不可以重复,存取顺序不一致。没有索引,所以不能通过普通for进行循环遍历。

Treeset 可以将元素按照规则进行排序

Hashset 底层基于hash表 hash值,Object中的方法,hashcode根据对象的地址计算hash值。 重写 hashcode方法,按照对象的属性值来计算hash值,跟对象的地址值就没有关系了。

List: 实现类: arraylist: 底层是数组结构,查询快,增删慢 , linkedlist:底层是链表结构,查询慢,增删快。

2,Comparable 和Comparator的区别,分别说出使⽤场景?

(1)自然排序 创建一个类 实现 Comparable 接口

使用:

  1. 使用空参构造创建Treeset 集合 在这里插入图片描述

  2. 自定义Student类实现Comparable 接口,

  3. 重写里面的compareTo方法

Int 为负数时,表示当前元素比较小,存左边, 为0 ,重复,不存

(2)比较器排序 Comparator

使用:让集合的构造方法接收一个Comparator的实现类对象,重写compare(T01 ,T02)方法,可以定义主要排序条件和次要排序条件

在这里插入图片描述

**比较:**comparable是需要比较的对象来实现接口(内部比较器)。这样对对象的耦合度高(需要改变对象的内部结构,破坏性大,想更改比较方式就得在类中进行修改)。Comparator只需在treeset的构造中传一个比较器就行了,解耦。还可以实现多个比较方式

3、Collection 和Collections 的区别?

Collection是集合类的上级接口,子接口有 Set、List、LinkedList、ArrayList、Vector、Stack、Set;

Collections是集合类的一个帮助类, 它包含有各种有关集合操作的静态多态方法,用于实现对各种集合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

4,HashMap 和Hashtable 的区别?

1,安全问题:

HashMap是线程不安全的,在多线程并发的环境下。会出现问题(在多线程环境下,给hashmap中存值时,会出现null值)。

Hashtable是线程安全的,它的每个方法上都有synchronized 关键字,直接对hash表进行加锁。

但是 Hashtable效率低。所以在线程安全的问题下用 ConcurrentHashMap, ConcurrentHashMap不是对整个数组进行加锁,而是使用*锁分段技术。初始化长度为16的数组,每一个元素下面还有HashEntey的小数组,加锁是加在这些H在这里插入图片描述
ashEntey的小数组上。每次最多允许16个线程同时访问( 1.7)

(1.8,CAS自旋(乐观锁)) 底层:哈希表(数组,链表,红黑树) ConcurrentHashMap1.7和1.8不同
在这里插入图片描述

机制:CAS算法,+ synchronized同步代码块。当线程操作数组中的一个元素时,以链表或红黑树的头节点作为锁对象。

对null的支持不同 :Hashtable:key和value都不能为null。 HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key 值对应的value为null。

5,如何解决Hash冲突问题?

这是数据结构中的散列表(hash表)处理散列冲突的问题:

**1,开放定址法:**一旦发生冲突,就去寻找下一个空的散列地址。只要散列表足够大。空的散列地址总能找到,并将记录存入。(mod(取模)hash数组长度,有散列函数)

根据散列函数算出地址,如果有冲突在原来的散列函数上加一个偏移量。

1,按照偏移量的不同分为线性探测,(设置增量序列 1,2,3.。。。)平方探测双散列。

2,拉链法: 每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向链表进行存储.

6,HashMap是如何实现自动扩容的?

Resize扩容方法

7,List和set,Map的区别?

List有索引 linkedlist , ArrayList 可重复

Set无索引 hashset, treeset 不可重复

Map 使用键值对存储,key不可重复,存key的其实就是一个set集合

8,ArrayList和LinkedList和Vector的区别?

List—是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承Collection。 List有两个重要的实现类:ArrayList和LinkedList。

ArrayList: 可以看作是能够自动增长容量的数组 ArrayList的toArray方法返回一个数组 ArrayList的asList方法返回一个列表 ArrayList底层的实现是Array, 数组扩容实现。

LinkList:是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于 ArrayList.当然,这些对比都是指数据量很大或者操作很频繁。

Vector jdk1.0 最早的单列集合。底层也是一个数组和arrayList一样。Vector是同步的。同步就是单线程。(单线程就是慢)1.2后用ArrayList集合给取代了。

9,arraylist和linkedlist 内存消耗谁比较大

Arrylist底层是数组实现的,数组在内存中存储需要完整的内存空间

10,collection.toarray()

返回包含此集合中所有元素的数组;

在这里插入图片描述

11, hashmap的底层原理

1.8中创建hashmap时,不会创建数组,当第一次插入数据时会创建一个16的Node[]数组;

当存入数据时,会根据数据的key的hashcode使用散列函数进行计算获得该数据在数组中的索引值:

当该索引处没有数据时,直接插入该索引处即可

当该索引处有数据时,判断两个数据的key的hashcode是否相同

当hashcode不相同时,则认为两个对象不同,将数据存入该索引的链表

当hashcode相同时,判断equals方法

当equals方法为false,则不同,将数据存入链表中

当equals方法为true,则相同,使用新的value替换旧的value

此时插入操作结束。

当插入时该链表上的节点个数大于等于8时,会判断数组长度是否大于等于64:

当数组长度小于64,则应当扩容

当数组长度大于等于64,应当将该链表修改为红黑树

扩容:1.当集合元素个数/数组长度>=加载因子0.75时,扩容

2.当某个链表长度大于等于8,且数组长度小于64,扩容

多线程

1,Mt.run() : 和 Mt.start();

Mt.run() : 在main线程中执行,属于单线程 。 Mt.start();开辟一个新的栈空间,执行run方法。

MyThread.start JVM会请求OS(操作系统)开辟一条线程。然后在jvm中创建这个线程的栈内存。然后两个线程,一个main线程,一个新线程一起抢夺cpu 的执行权。 方法在栈中执行,先开始main方法会压栈执行。一行一行执行里面的代码。

**多线程的好处:**多个线程之间互不影响(不同的栈空间) 一个报错,一个还可以运行。

2,线程创建的4种方法

(1)继承Thread类 重写run方法 然后用的时候new Thread ,thread.start

(2)实现Runnable接口 重写 run方法 避免了单继承的局限性,并且把设置任务和开启线程进行了分离(解耦)

Thread th = new Thread;

thread.start(new Runnable);

(3)实现Callable 接口重写 call方法 可以加返回值 用futureTask接收

public class Test {
	public static void main(String[] args) throws Exception {
		//创建任务
		MyCallable mc=new MyCallable();
		/**FutureTask同时实现了Runnable,Future接口。

- 它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值
  	 */
  	//交付任务管理
  	FutureTask<String> task=new FutureTask<>(mc);//可以看成FutureTask实现了runnable接口
  	Thread t=new Thread(task);
  	t.start();
  	System.out.println("获取结果:"+task.get());
  	System.out.println("任务是否完成:"+task.isDone());
  }
  }

//实现Callable接口,重写call方法
class MyCallable implements Callable {
	@Override
	public Object call() throws Exception {
		String [] str= {"apple","pear","banana","orange","grape"};
		int i=(int)(Math.random()*5);
		return str[i];
	}
}

(4)线程池

new ThreadPoolExecutor(7个参数)创建线程:核心线程数、最大线程数、空闲线程存活时间、时间单位、阻塞队列、创建线程的工厂、超出任务拒绝策略;

3,线程池的7个参数

核心线程数、最大线程数、空闲线程存活时间、时间单位、阻塞队列、创建线程的工厂、超出任务拒绝策略

1,corePoolSize 线程池核心线程大小:线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁

2,maximumPoolSize 线程池最大线程数量

一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接将任务交给这个空闲线程来执行,如果没有则会缓存到工作队列(后面会介绍)中,如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
3,keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁

4,unit 空闲线程存活时间单位

5,workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
6,threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

7,handler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,

超出任务拒绝策略:

ThreadPoolExecutor.Abortpolicy 丢弃任务,并抛出异常,默认策略

ThreadPoolExecutor.DiscardPolicy 丢弃任务,不抛出异常

ThreadPoolExecutor.DisOldestPolicy 丢弃等待时间最久的任务,把当前任务加入等待队列

ThreadPoolExecutor.CallerRunsPolicy 调用任务的run()方法绕过线程池执行。

4,java中常见的线程池,

1,FixedThreadPool :使用固定线程数的线程池

  • 创建方式:Executors.newFixedThreadPool(threadsNum)

2,CachedThreadPool

  • 创建方式:Executors.newCachedThreadPool()
  • 线程池无界实际只使用了maximumPool

3,SingleThreadExecutor

  • 创建方式:Executors.newSingleThreadScheduledExecutor()
  • 线程池中只有一个线程

4,ScheduledThreadPool

  • 创建方式:Executors.newScheduledThreadPool(corePoolSize)有固定数量的线程池,可以在给定的延迟后执行任务,或者定期执行任务。

5,线程的几种状态

线程的的状态在JDK1.5之后被定义在Thread的源码之中,有6种状态

(1)NEW 新建状态,线程被new出来,MyThread t = new MyThread();

线程刚被创建出来,但并未启动。

(2)RUNNEBLE 就绪状态, 这是我们对线程调用了start方法,此时才真正的在JVM中创建了一个线程,此时线程可以开始运行,或者在排队等待操作系统给它分配cpu资源。

(3)BLOCKED 阻塞等待锁的线程状态,当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。synchronized

(4)WAITING wait(); notify()

(5)TIMED_WAITING sleep(1000); 计时等待

(6)TERMINATED(terminated 结束) 终止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3wZALXJ-1623854587991)(C:\Users\www27\Desktop\images\1623744970598.png)]

6,线程安全问题

线程安全问题的产生,多个线程同时访问同一个资源。

解决线程安全问题的方法有3种:

(1)同步代码块: 把同步代码块锁住,只允许有一个线程在代码块中进行执行

没有获取锁的线程进入阻塞状态,一直等待使用锁的线程归还锁。

这种方式有缺点,程序需要去判断锁,获取锁,释放锁,程序的效率会降低

(2)同步方法 也可以是静态同步方法。(static synchronized )
在这里插入图片描述

定义一个方法上面加上synchronized 关键字。

同步方法的锁是new RunnableImpl 也就是this

静态同步方法的锁是本类的class文件对象

(3)lock锁机制。使用它的子类 reentrantLock(ri en tree t lock)

在这里插入图片描述

一般把unlock放到finally中

7,wait和sleep的区别;

Wait和sleep方法都能是线程处于等待状态,

区别:wait会释放锁,sleep不会,sleep属于Thread类中的方法,使线程休眠一段时间,自动唤醒进入到可运行状态。Wait属于object中的方法,一旦调用了wait方法,必须采用notify或notifyAll方法唤醒该进程。

8, notify()和 notifyAll()有什么区别?

Notify: 唤醒wait set 中等待时间最长的线程,进入调度队列(ready queue(发音Q))中

因为它当初中断的地方在同步代码块中,而此刻它又不持有锁,所以它要去尝试获取锁(可能面临其他线程的竞争),成功获取锁后,才能执行wait之后的代码。如果不成功进入entry set, 线程从waiting状态进入blocked状态。

NotifyAll: 唤醒所有 在wait set中的线程,

9, 什么是死锁?怎么防止死锁?

死锁:当锁进行嵌套时就会出现死锁。两个或多个线程互相持有对方的资源导致上方都处于等待状态。无法执行。

防止死锁,就是不要写锁的嵌套

10, 乐观锁,悲观锁

悲观锁:synchronized,从最坏的角度来看,认为每次获取共享数据的时候,都会被别的线程修改。所以给次在操作共享共享数据之前都要加锁。

乐观锁:cas算法,从乐观角度出发。假如每次获取共享数据别人都不会修改。所以不会上锁。只不过在修改共享数据的时候,会检查一下,有没有别人修改。如果修改,获取最新值。

线程的补充

多线程之间的通信:

cpu随机执行多线程,当我们需要多线程来共同完成一件任务,需要他们有规律的执行----等待唤醒机制

Wait : 线程进入 wait set 中 , 不会参与调度。等待其他线程执行notify操作。

Notify: 唤醒wait set 中等待时间最长的线程,进入调度队列(ready queue(发音Q))中

因为它当初中断的地方在同步代码块中,而此刻它又不持有锁,所以它要去尝试获取锁(可能面临其他线程的竞争),成功获取锁后,才能执行wait之后的代码。如果不成功进入entry set, 线程从waiting状态进入blocked状态。

NotifyAll: 唤醒所有 在wait set中的线程,

**注意:**wait方法和notify方法必须在同步代码块或者同步方法中执行。必须要用锁对象调用这两个方法。在这里插入图片描述

在这里插入图片描述

**死锁:**锁进行了嵌套。

**乐观锁:**cas读过来,存在自己线程的线程副本中。

**原子类:**AtomicInterger(); (饿涛妹可)

线程工具类:

CountDownLatch A线程等待B,C,D线程执行完后再进行执行

信号量Semaphore(森魔for): 有多个线程访问,一个接口,只允许1分钟内访问100次。

有参方法tryAcquire(int long timeout,TimeUnit unit)的作用是在指定的时间内尝试地获得1个许可,如果获取不到则返回false。

Semaphore semaphore = new Semaphore(1);
if (semaphore.tryAcquire(2, TimeUnit.SECONDS)) {
    System.*out*.println(Thread.*currentThread*().getName() + "执行时间:" + System.*currentTimeMillis*());
semaphore.release(2);
}

在这里插入图片描述

其他:

1,TCP与UDP的区别?

TCP:面向连接的,速度慢,传输的效率大小无限制;先建立连接,确定连接无误后,才进行数据的传输。数据传输完成断开连接,通常用于上传下载文件。

UDP: 面向用户的,速度快,传输的数据最大64K; 发送端和接收端无需建立连接。通常用于视频通话,直播。可以允许丢失包。一般有三个模式:单播,组播,广播。

TCP三次握手,四次握手

三次握手我的理解就是;(1)客户端给服务端,说我是客户端我要请求,(2)

服务端然后给客户端说可以对我进行请求,(3)客户端这时候就可以给服务端发起请求。

四次握手:

A:B 啊,我不想玩了
B:哦,你不想玩了啊,我知道了
这个时候,只是 A 不想玩了,即不再发送数据,但是 B 可能还有未发送完的数据,所以需要等待 B 也主动关闭。
B:A 啊,好吧,我也不玩了,拜拜
A:好的,拜拜

2,http和https的区别

http的缺点:

Http不安全,通信采用明文,内容可能被监听

https,采用SSL协议进行加密

得先有个域名,然后在阿里云上申请SSL证书,然后在Tomcat中进行配置

3,bigDecimal

75, 十进制小数在转换成2进制会有精度丢失。0.9在二进制存储时是11001001…底层原理就是,十进制整数在转化为二进制时不会出现精度问题,把十进制小数扩大N倍,让他在整数的维度上进行计算,保留相应的精度信息。

4,String的常用操作

(1) 截取,身份证的几位,和几位,

//如果身份证格式是没有问题的,那个打印年月日信息

​		year = IDNumber.substring(6,10);

​		month = IDNumber.substring(10,12);

​		day = IDNumber.substring(12,14);

(2) 获取字符串长度

int len = str.length();

(3) 去除字符串首尾的空格

String str = " ab cde ";
String str1 = str.trim();//str1为"ab cde"  (tri  m)

(4) 字符串分割

String[] split():根据匹配给定的正则表达式来拆分字符串,将分割后的结果存入字符数组中。

String[] split(String regex):regex为正则表达式分隔符, . 、 $、 | 和 * 等转义字符,必须得加 \;多个分隔符,可以用 | 作为连字符。
String[] split(String regex, int limit):limit为分割份数

String str = "Hello World A.B.C"
String[] res = str.split(" ");//res = {"Hello","World","A.B.C"}
String[] res = str.split(" ",2);//res = {"Hello","World A.B.C"}
String[] res = str.split("\\.");//res = {"Hello World A","B","C"}

String str = "A=1 and B=2 or C=3"
String[] res = str.split("and|or");//res = {"A=1 "," B=2 "," C=3"}

(5)字符串与byte数组的转换

byte[] Str2 = Str1.getBytes();

(6) 替换

String  str = "abc";

String s = "1";
str.replace(1,1,s);*//此时str为"a1c"*

(7) 工具类

StringUtils.isBlank("") = true 判断某字符串是否为空或长度为0或由空白符(whitespace) 构成

StringUtils.isEmpty(null) = true 判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0

5,Java的NIO和AIO、BIO java的三种io模型

学习这个之前先了解这几个名词,阻塞和非阻塞,同步和异步。

1.1阻塞和非阻塞:阻塞和非阻塞,是进程在访问数据的时候,数据缓冲区内是否准备就绪,的一种处理方式。 当数据没有准备的时候 阻塞:往往需要等待缓冲区中的数据准备好过后,进程才可以处理其他的事情。否则会一直等待在哪里。

非阻塞:当我们的进程访问我们的数据缓冲区的时候,数据没有准备好,直接返回,

1.2同步和异步

晚上竟然没有网, 自己说了:同步,在线程进行io时不能做其他的事情,阻塞就等待, 而异步,阻塞,就可以干其他的事情。

BIO就是阻塞线程,1.5之前使用

NIO 是有个Select线程进行轮询,请求资源如果没有就可以去干其他事,等待交给select线程 目前大多框架使用 Netty 框架使用,dubbo就是基于Netty



这篇关于自己总结的javaSE面试题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程