面试官问题

1.ArrayList集合中的元素怎么进行排序?(元素为自定义类型)

因为Collections.sort(List<T> list)中的list参数必须要有明确的排序规则,所以要对存放了自定义对象的list集合进行排序,需要该对象实现Comparable接口,并实现接口唯一的方法compareTo(T o),按照我们自定义精酿3的规则进行排序。例如自定义Person类,按照年龄升序排序:
 

public class Person implements Comparable<Person>{
	private String name;
	private int age;
	
	public Person() {
		
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public int compareTo(Person o) {
		return this.age - o.age;//this-参数 升序
		//return o.age - this.age  降序
	}
}
public static void main(String[] args){
	ArrayList<Person> list2 = new ArrayList<>();
	list2.add(new Person("张三",32));
	list2.add(new Person("李四",12));
	list2.add(new Person("王五",23));
	Collections.sort(list2);
	for(Person p:list2) 
		System.out.println(p);
	//输出结果
	/*Person [name=李四, age=12]
	Person [name=王五, age=23]
	Person [name=张三, age=32]*/
}

第二种方法
第二种方法中的第二个参数是需要实现Comparator接口,需要实现接口中的compare(T o1,T o2)方法,一般对自定义对象排序的时候可采取这种方法。
Comparator和Comparable接口的区别在于,Comparator接口相当于第三方的裁判,对传入的两个参数进行比较;Comparable接口是用自身(this)与参数进行比较。
例子如下,先创建一个Student类

public class Student {
	private String name;
	private int score;
	
	public Student() {
	}

	public Student(String name,int score) {
		this.name = name;
		this.score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", score=" + score + "]";
	}

创建集合,在集合中存放Student对象,采用匿名内部类的方法实现Comparator接口,按照分数降序排序

public static void main(String[] args){
	ArrayList<Student> list3 = new ArrayList<>();
	list3.add(new Student("张三",75));
	list3.add(new Student("李四",91));
	list3.add(new Student("王五",89));
	Collections.sort(list3, new Comparator<Student>(){

		@Override
		public int compare(Student o1, Student o2) {
			//return o1.getScore() - o2.getScore();//升序
			return o2.getScore() - o1.getScore(); //降序
		}
		
	});
}
//输出结果
/*
Student [name=李四, score=91]
Student [name=王五, score=89]
Student [name=张三, score=75]
*/

2.对Arraylist元素进行去重

第一种方法遍历后赋值给另一个元素

List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("aaa");
list.add("aba");
list.add("aaa");
//遍历后判断赋给另一个list集合
List<String> newList = new ArrayList<String>();
for (String cd : list) {
    if (!newList.contains(cd)) {
        newList.add(cd);
    }
}
System.out.println("去重后的集合: " + newList);

第二种方法

利用set集合去重

private static void removeDuplicate(List<String> list) {
    HashSet<String> set = new HashSet<String>(list.size());
    List<String> result = new ArrayList<String>(list.size());
    for (String str : list) {
        if (set.add(str)) {
            result.add(str);
        }
    }
    list.clear();
    list.addAll(result);
}

3.B树和B+树区别

1.B+树内节点不存储数据,所有数据都存在叶节点,查询时时间复杂度为log以2为底n的对数,B树每个节点都有都有key和data,时间复杂度为O(n),最好的情况为O(1)。

2.B+树页节点是两两相连的,可以使用范围查找,B树不行。(因为根据空间局部性原理),如果存储器的某个位置被访问,那么将它附近的位置也会被访问。

3.因为B+树内节点不携带数据,所以每次IO操作,B+树获得数据量大于B树。因为每次磁盘IO大小是固定的,单个元素越小,量越大。

4.Stringbuffer,string,stringbuilder的区别

1.不可变性角度。string类被final关键字修饰,属性被final和private修饰,且没有向外暴露修改这个字符串的方法。

stringbuilder、stringbuffer是可变的,都继承自abstractStringbuilder类,这个类没有被final和private修饰,而且提供修改字符串的方法。(append insert index of)

2.线程安全性,string对象不可变,也可以理解为线程安全,stringbuffer对方法加了同步锁,所以线程安全的,stringbuider没有对方法进行同步锁,所以非线程安全。

3.性能方面:string类型改变的时候都会生成一个新的string对象,然后指向新的string对象。stringbuffer和stringbuilder对对象本身操作,但stringbuilder性能更好,但要冒对多线程不安全的风险。

总结:1.操作量少的适用string2.单线程且有大量操作用stringbuilder3.多线程且有大量操作用stringbuffer

5.类加载器加载过程

系统加载 Class 类型的文件主要三步:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析

这就得说一下双亲委派,当一个类加载器接收到一个类加载任务时,不会立即加载,而是将加载任务交由父类加载器去完成,若父类加载过则直接返回,否则一直往上抛,直到bootstrap class loader,若bootstrap classloader未加载到,则会让一直往下让子类尝试加载。

6.springboot的常用注解

7.jvm优化方法

 1.通过-Xmx  -Xms调整最大堆内存和最小堆内存,开发过程中,通常将两个参数值设置为相等,目的是为了垃圾回收机制清理完堆区后,不需要重新分割堆区大小而浪费资源。

2.调整新生代:老年代的比值为 1:4

3.调整Survivor区和Eden区的值  survivor:eden=1:1:8,即一个survivor占年轻代的十分之一

8.jvm内存区域分析

1.线程私有:程序计数器、虚拟机栈、本地方法栈

2.线程共享:堆、方法区

9.运行时常量池

运行时常量池是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池表(用于存放编译期生成的各种字面量和符号引用);

JDK1.8 hotspot 移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)

10.缓存穿透、缓存雪崩的解决方法

缓存穿透解决方案:1.在redis中缓存无效的key,并设置过期时间  2.设置布隆过滤器

缓存雪崩解决方案:1.采用redis集群,避免单机出现问题整个缓存服务都没办法使用

                                  2.限流,避免同时处理大量请求

                                   3.随即设置缓存失效时间       

11.mysql高性能优化建议

建表时把经常一起使用的列放到一个表中(避免更多的关联操作);尽可能把所有列定义为not null,索引null列需要额外的空间来保存,所以要占用更多的空间;进行比较和计算时要对null值做处理;同财务相关的金额数据必须用decimal。索引方面,限制每张表的索引数量,限制单表索引不超过五个,将经常出现在where条件中的列建立索引,索引列的基数不能太小,能建联合索引的尽量建联合索引。

写查询语句时,能用覆盖索引尽量用覆盖索引,可避免回表查询,可以把随机io变为顺序io加快查询效率。尽量避免子查询,可以把子查询优化为join操作,

建立索引目的,通过索引查找数据,减少随机IO,增加查询性能。      

12.springboot全局配置文件加载顺序

        优先加载当前项目根目录下/config包中的文件,接着是当前项目根目录下的配置文件,然后是当前项目resource下的/config中的文件,最后是resource下的配置文件。在同一目录下,若同时存在application.yml和application.properties两种不同的配置文件,默认先读取application.properties中的,如果统一配置在多个配置文件中都配置了,默认会使用第一个读取到的值,后面读取不会覆盖前面读取到的内容,而会进行互补。

13.springboot中读取配置文件的注解有哪些 ?

@value和@configurationProperties注解方式        @PropertitySource+@Value注解读取方式

14. 当服务端从单体应用升级为分布式之后,cookie+session这种机制怎么拓展?

session共享:就是将服务端的session信息保存到一个第三方中,比如Redis。

15.session和cookie的区别?

session属于服务端技术,cookie属于客户端技术;HTTP协议是无状态的协议,服务端需要记录用户的状态时,就需要用特定机制来识别具体的用户,这个机制就是session。session在服务端,有一个唯一的标识,session可以保存在内存、数据库、文件都有。集群时也要考虑session的转移。

当服务器tomcat第一次接收到客户端的请求时,会开辟一块独立的session空间,建立一个session对象,同时生成一个sessionid,通过响应头的方式保存到客户端浏览器的cookie当中,以后客户端的每次请求,都会在请求头部带上这个sessionid,这样就可以对应上服务端的一些会话的相关信息,比如用户登录状态。

总结:session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现session的一种方式。

16.synchronized和Lock锁的区别?

synchronized可以给类方法代码块加锁;而lock只能给代码块加锁。synchronized不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;而lock锁需要自己加锁和释放锁,如果使用不当没有unlock()区释放锁会造成死锁。通过lock可以知道有没有成功获取锁,而synchronized却无法办到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值