Java面试题——自己整理(动态更新)

  1. final关键字
    (1) final修饰类表示该类不能被继承,final类中的成员变量可以根据需要设置final,final类中的成员方法都被指定为final类型,String、System都是final修饰的类;
    (2) final修饰的方法不能被重写;
    (3) final修饰的成员变量若是基本数据类型,必须在定义时或构造器中初始化赋值,且不能被修改,若是引用数据类型,不能再引用其他对象,但是对象内容可以改变。

  2. static关键字
    (1) static关键字修饰成员变量为全局静态成员变量,修饰的代码块为静态代码块,修饰的方法为静态方法;
    (2) 静态代码块是当Java类加载到JVM内存中而执行的代码块,由于类的加载在JVM运行期间只会发生一次,所以静态代码块也只会执行一次。因为静态代码块的主要作用是用来进行一些复杂的初始化工作,所以静态代码块跟随类存储在方法区的表现形式是静态代码块执行的结果存储在方法区,即初始化量存储在方法区并被线程共享。
    (3) 静态变量跟代码块类似,在类加载到JVM内存中,JVM会把静态变量放入方法区并分配内存,也由线程共享。访问形式是:类名.静态成员名。(为什么不能修饰局部变量?因为将变量声明为static意在延长变量的生命周期,生命成员变量就可以,类在,static在)
    (4) 静态方法可以直接调用类的静态变量和其他静态方法,不能直接调用成员变量和实例方法(除非通过对象调用)。
    (5) static关键字虽然不能修饰普通类,但可以用static关键字修饰内部类使其变成静态内部类。static关键字本身的含义就是共享,而Java类加载到JVM内存的方法区,也是线程共享的,所以没必要用static关键字修饰普通类。

  3. 描述进程控制块PCB,进程控制块中进程的哪些信息

    进城的状态,进程的调度信息(进程的优先级,调度策略),标识符(识别不同进程),进程通信有关信息(信号量),进程链接信息(程序创建的进程有父子关系,一个进程能创建几个子进程),时间(进程的生存期)

  4. 排序算法
    (1)冒泡排序

	public static int[] sort(int arr[]){
		//循环比较的轮数
		for(int i = 1 ; i < arr.length ; i ++){
			//设定一个标记,若为true,则此次没有进行交换,待排序序列已经有序
			boolean flag = true;
			//进行每一轮的比较
			for(int j = 0 ; j < arr.length-i ; j ++){				
				if(arr[j] > arr[j+1]){
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
					//flag为false,此次进行了交换
					flag = false;
				}
			}
			if(flag){
				break;
			}
			//每轮排序的结果
			System.out.print("第"+i+"轮的排序结果为:");
			display(arr);
		}		
		return arr;		
	}

(2)选择排序

	public static int[] sort(int[] arr){
		//循环找最小元素的轮数:每次从序列中选择最小的,放在起始位置,需要找N-1次
		for(int i = 0 ; i < arr.length-1 ; i ++){			
			int min = i;
			//循环比较的次数
			for(int j = i + 1 ; j < arr.length ; j++){				
				if(arr[j] < arr[min]){
					min = j;//目前能找到的最小元素的下标
				}
			}
			//如果找到的最小元素不是 **待排序序列** 的第一个元素,将其和第一个互换			
			if(arr[min] != arr[i]){
				int temp = arr[i];
				arr[i] = arr[min];
				arr[min] = temp;				
			}
			int k = i+1;
			System.out.println("第"+k+"轮交换后的数组:");
			display(arr);
		}		
		return arr;		
	}

(3)插入排序

public static int[] sort(int arr[]){
		int j;
		// 循环插入的次数 N次,从下标为1的元素开始选择合适的位置插入
		// 因为下标为0的只有一个元素,默认有序
		for(int i = 1 ; i < arr.length ; i ++){			
			//记录要插入的元素
			int temp = arr[i];
			j = i;
			//循环每一次插入比较 :每次放一个元素在数组中,比较插入元素和数组里的元素的大小
			while(j > 0 && temp < arr[j-1]){//从已经排序的序列最右边开始比较,找到比其小的数
				arr[j] = arr[j-1];//向后挪动				
				System.out.println("i="+i);
				System.out.println("j="+j);				
				j--;
			}
			arr[j] = temp;//存在比其小的数,插入
		}		
		return arr;		
	}

(4)快速排序

	private static void quickSort(int[] arr, int start, int end) {
		if (start < end) {
			// 把数组中的第0个数字作为标准数
			int stard = arr[start];
			// 记录需要排序的下标
			int low = start;
			int high = end;
			// 循环找比标准数大的数和比标准数小的数
			while (low < high) {
				// 右边的数比标准数大
				while (low < high && stard <= arr[high]) {
					high--;
				}
				// 如果右边的数比标准数小
				// 用high指向的数字替换左面的数字
				arr[low] = arr[high];
				// 如果左边的数字比标准数小
				while (low < high && arr[low] <= stard) {
					low++;
				}
				// 如果左面的数比标准数大
				// low指向的数字替换high指向的数字
				arr[high] = arr[low];
			}
			// 把标准元素赋给low和high重合的元素
			arr[low] = stard;
			// 处理所有比标准数小的数字
			quickSort(arr, start, low);
			// 处理所有比标准数大的数字
			quickSort(arr, low + 1, end);
		}
	}
  1. 什么情况下要用什么排序算法?

  2. java 接口和抽象类、为什么java要有抽象类和接口这两种?
    (1) 抽象类是对事物的抽象,对类的抽象,接口是对行为的抽象。
    (2) 比如有飞机和鸟,他们都会飞,可以把飞机和鸟建成两个抽象类,飞这个行为不能写成类,只能定义成接口,其他类根据需求调用这个接口。
    (3) 抽象类实现了多态性。
    (4) 区别:
    a 只可以继承一个抽象类,但可以实现多个接口。
    b 实现接口要实现接口中的所有方法,抽象类不需要。
    c 接口中声明的变量都是final类型的,抽象类中可以包含非final类型变量。
    d 接口中的成员函数默认都是public,抽象类可以是private、protected、public。
    e 抽象类中可以有构造函数,接口中不能。

  3. http请求/响应的报文结构
    (1) 请求:请求行、请求头、空行、请求数据
    a 请求行:请求方法字段、URL字段、HTTP协议版本字段
    b 请求头部:对于POST,必须有Content-Length,请求消息正文的长度;Host,主机名;Cookie(客户机通过这个头可以向服务器带数据)
    c 空行:通过一个空行,告诉服务器请求头部到此为止 d) 请求数据:若方法字段是GET,则此项为空,没有数据;
    若方法字段是POST,则通常来说此处放置的就是要提交的数据。
    (2) 响应:相应行、响应头、响应体
    a 响应行:版本协议、状态码及其描述
    HTTP/1.1 200 OK
    b 响应头:描述服务器的基本信息,以及数据的描述;Allow:服务器支持哪些请求方法;Content-
    Type:文档MIME类型(text/html application/json)
    c 响应体:响应的消息体

  4. http与https的区别
    (1) http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
    (2) http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
    (3) http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

  5. 客户端与服务端通过https进行交互的过程

  6. Java中注解
    @Override

  7. SQL命令:在数据存在时进行更新数据,数据不存在的话插入数据
    (1) replace into table() values();
    (2) 将要判断的字段设置为unique索引

   INSERT INTO tb_addrbook(num,name,mobile)
   VALUE('01','bo','110') 
   ON DUPLICATE KEY 
   UPDATE name='bo',mobile='111'
  1. 单例模式、工厂模式、装饰者模式、观察者模式

  2. ConcurrentHashMap的实现原理
    (1) 为什么用? 在并发编程中使用HashMap进行put操作可能会导致死循环(是因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,就会产生死循环)。
    而使用线程安全的HashTable效率又低下(HashTable使用synchronized来保证线程的安全,但是在线程竞争激烈的情况下HashTable的效率非常低下。当一个线程访问HashTable的同步方法,其他方法访问HashTable的同步方法时,会进入阻塞或者轮询状态。如果线程1使用put进行元素添加,线程2不但不能用put方法添加于元素同是也无法用get方法来获取元素,所以竞争越激烈效率越低)。
    (2) ConcurrentHashMap的锁分段技术 1.7
    a) HashTable容器在竞争激烈的并发环境效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,假如容器有多把锁,每一把锁用于锁住容器中一部分数据,那么多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问率,这就是ConcurrentHashMap的锁分段技术。
    b) 将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据的时候,其他段的数据也能被其他线程访问。
    c) ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作。第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。
    (3) 数组+链表+红黑树 采用CAS操作 1.8
    链表节点数量大于8时,会将链表转化为红黑树进行存储
    a) CAS
    i. 乐观锁(悲观锁是将资源锁住,等之前的一个线程释放锁之后,下一个线程才能访问;而乐观锁采取了一种宽泛的态度,通过某种不加锁得方式处理资源);
    ii. CAS 操作包含三个操作数 ——
    内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么就将内存里面的值更新成B。CAS是通过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能机会执行。
    b) Node
    使用Node:保存key,value及key的hash值的数据结构。其中value和next都用volatile修饰,保证并发的可见性。

  3. 乐观锁*

  4. 红黑树*

  5. 反转链表

	public static ListNode rev(ListNode head){
		ListNode first = head;
		ListNode newnode = null;
		while(first != null){
			ListNode sec = first.next;//先处理第1个节点,
			first.next = newnode;//将first放到新链表的头部
			newnode = first;//移动新链表头指针,让他始终指向新链表头部
			first = sec;//继续处理原链表的节点,即之前指针存放的后继,循环
		}
		
		return newnode;
	}
  1. 两个一组翻转链表
  2. GC
  3. 线程池
  4. 为什么会产生死锁
  5. java并发 wait 和sleep的区别
  6. git 常用命令
$ git remote add origin git@github.com:xxxx/xxxx.git         # 配置远程git版本库
$ git pull origin master                                          # 下载代码及快速合并 
$ git push origin master                                          # 上传代码及快速合并
$ git fetch origin                                                # 从远程库获取代码
$ git clone <url>                 # 克隆远程版本库
$ git init                        # 初始化本地版本库
$ git status                      # 查看状态
$ git diff                        # 查看变更内容
$ git add .                       # 跟踪所有改动过的文件
$ git add <file>                  # 跟踪指定的文件
$ git mv <old> <new>              # 文件改名
$ git rm <file>                   # 删除文件
$ git commit -m “commit message”  # 提交所有更新过的文件
$ git log                         # 查看提交历史
$ git branch                      # 显示所有本地分支
$ git checkout master             # 切换到master分支

  1. mysql 常用命令
  2. mysql索引底层
  3. 添加索引的时候要注意什么
  4. 索引优化以及在使用索引的时候要注意什么
  5. Java常用锁 synchronized 作用域
  6. 主线程等待子线程执行完的实现方式
  7. Linux 常用命令,vi如何设置使其显示行数
 :set number :set nonumber
  1. linux如何查看每个文件的总行数
 more logfile.txt |wc -l
  1. linux中怎么统计一个文件中各个单词出现的次数
 more list | grep -o test | wc -l
  1. TCP 为什么需要四次挥手
  2. HTTP 状态码
    502 Bad Gateway:tomcat没有启动起来
    503 - Service Unavailable 服务不可用,服务器由于维护或者负载过重未能应答
    504 Gateway Time-out:
    网关超时,由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答
    1xx 响应信息提示
    2xx 成功
    3xx 重定向
    4xx
    客户端错误
    5xx 服务器错误
  3. 二叉树的高度
public int height(BinaryTreeNode p) {  //p是一个二叉树根节点的引用
    if(p == null){
       System.out.println("高度为0")
       return 0;
     }else{
       return 1 + max(height(llink),height(rlink));  //这个LLINK 和RLINK分别是p的两个指针,指向左子树和右子树
     }
}

  1. 判断俩字符串组成字母是否相等(用map)
    思路:
    利用Map集合key的唯一性,遍历第一个字符串,将字符作为key,字符出现的次数作为value,若遇到重复字符则将value+1。之后遍历第二个字符串,遇到字符就将对应的value-1,若value值为1时,就将该字符remove掉。最后判断map是否为空,为空则说明两字符串相同。
	public static boolean compare(char[] a,char[] b){
       int aLen = a.length;
       int bLen = b.length;
       if(aLen!=bLen){
           return false;
       }
       Map<Character,Integer> map = new HashMap<Character,Integer>();
       for(int i=0;i<aLen;i++){
           if(map.containsKey(a[i])){
               map.put(a[i], map.get(a[i])+1);
           }else{
               map.put(a[i], 1);
           }
       }
       for(int j=0;j<bLen;j++){
           if(map.containsKey(a[j])&&map.get(a[j])==1){
               map.remove(a[j]);
           }else{
               map.put(a[j], map.get(a[j])-1);
           }
       }
       return map.isEmpty();
 	}
  1. 栈实现队列代码

  2. 数据库联合索引的最左前缀原理,有联合索引ABC,在sql语句中,where后面是 CBA,可以用到索引吗?(能)

  3. tcp和udp能共用80端口吗?
    TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立。

  4. 单例模式
    synchronized 实现懒汉模式

public class Singleton{
	private static Singleton sg;
	private Singleton(){}
	public static getInstance(){
		if(sg==null){
			synchronized(Singleton.class){ //只有在新创建单例时才有必要加锁
				if(sg==null){//双检索避免重复创建单例
					sg = new Singleton();
				}
			}
		}
		return sg;
	}
}

  1. 为什么用内部类是线程安全的?
  2. 哪几种IO类型
  3. JVM类加载机制
  4. 如何实现双向链表
  5. 多进程与多线程的区别
  6. 如何判断一个数是2的幂
 private static boolean judge(int a) { 
 	int b = a - 1; 
 	return (a & b) == 0; 
 }
  1. mysql的左右内连接区别
    (1)左连接:只要左边表中有记录,数据就能检索出来,而右边有的记录必要在左边表中有的记录才能被检索出来
    (2)右连接:右连接是只要右边表中有记录,数据就能检索出来
  2. 事务隔离级别
  3. mysql的锁级别
  4. 聚簇索引和非聚簇索引的区别以及数据结构
  5. 如果在循环中删除数组元素,会出现什么异常(快速失败)
  6. run和start的区别
    调用run方法,若方法中有异常,在主线程中能否捕获
  7. volatile的特性,底层实现,指令重排序;哪些方式也可以实现可见性
  8. 过滤器和拦截器的区别和应用场景
  9. 怎样检查链表是否有环
  10. 数据库的视图,为什么要用视图?
    视图其实就是select查询语句 通过关联查询或者其他查询组建起来的,他是多个表的查询结果集,使用视图可以提高一个程序的SQL效率,比平常使用select
    更加便捷,我们可以直接select * from 视图VIEW 来获取,数据库也更容易维护更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值