Java后端面试(四)

1、Java 中能创建 volatile 数组吗?

        能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。

        如果改变引用指向的数组,将会受到 volatile 的保护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前的保护作用了。

2、怎么将 byte 转换为 String?

        使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

3、Java 中怎样将 bytes 转换为 long 类型?

String接收bytes的构造器转成String,再Long.parseLong

4、Java 中 ++ 操作符是线程安全的吗?

        不是线程安全的操作。

        它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。

5、a = a + b 与 a += b 的区别

+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。

byte a = 127;

byte b = 127;

b = a + b; // error : cannot convert from int to byte

b += a; // ok

(因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)

6、3*0.1 == 0.3 将会返回什么?true 还是 false?

false,因为有些浮点数不能完全精确的表示出来。

7、Java 中堆和栈有什么区别?

JVM 中堆和栈属于不同的内存区域,使用目的也不同。

栈常用于保存方法帧和局部变量,而对象总是在堆上分配。

栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。 Difference between stack and heap memory in Java

8、“a==b”和”a.equals(b)”有什么区别?

        a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。

        例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。

9、a.hashCode() 有什么用?与 a.equals(b) 有什么关系?

hashCode() 方法是相应对象整型的 hash 值。它常用于基于 hash 的集合类,如 Hashtable、HashMap、LinkedHashMap等等。它与 equals() 方法关系特别紧密。根据 Java 规范,两个使用 equal() 方法来判断相等的对象,必须具有相同的 hash code。

10、简述面向对象的特性

        ①封装:建议成员变量私有,然后提供公有的getter/setter方法来获取值/赋值,封装的核心思想是合理隐藏,合理暴露,可以提高安全性,实现代码的组件化。

        ②继承:一种子类到父类的关系,是“is a”关系,可以提高代码的复用性,相同代码可写到父类,子类的功能更加强大,不仅得到了父类的功能,还有自己的功能。

        ③多态:同一个类型的对象执行相同的行为,在不同的状态下表现出不同的特征。多态可以降低类之间的耦合度,右边对象可以实现组件化切换,业务功能随之改变,便于扩展和维护。

11、类和对象有什么区别?

        类是一个抽象的概念,是具有相同特征的事物的描述,是对象的模板。对象是一个个具体的存在,是类的实例。

12、列举Object类的方法

        ①equals(Object obj):判断其他对象是否与当前对象相等。

        ②toString():打印当前对象的字符串表示。

        ③wait():导致当前线程等待,等待其他线程唤醒,会释放锁。

        ④notify()/notifyAll():随机唤醒一个/全部线程。

        ⑤hashCode():返回当前对象的hashCode值。

        ⑥finalize():当垃圾回收器要回收对象前调用。⑦clone():创建并返回对象的一个副本。

13、方法重载和方法重写的区别?

        ①方法重载是同一个类中具有不同参数列表的同名方法(无关返回值类型),方法重写是子类中具有和父类相同参数列表的同名方法,会覆盖父类原有的方法。

        ②重载的返回值类型和权限修饰符,异常抛出类型没有要求,重写方法的返回值类型小于等于父类被重写方法的返回值类型,修饰符权限大于等于父类被重写方法权限修饰符,抛出的异常类型小于等于父类被重写方法抛出的异常类型。

14、接口和抽象类有什么区别?

        ①接口中只能定义public staic final修饰的常量,抽象类中可以定义普通变量。

        ②接口和抽象类都不能实例化,但接口没有构造器,抽象类有构造器。

        ③接口可以多实现,抽象类只能单继承。

        ④接口在JDK1.8之前只能定义public abstract修饰的方法,JDK1.8开始可以定义默认方法和静态方法,JDK1.9开始可以定义私有方法,抽象类中的方法没有限制。

15、什么时候应该使用接口,什么时候应该使用抽象类?

        ①如果知道某个类应该成为基类,那么第一选择应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。

        ②在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。

16、内部类有什么作用?有哪些分类?

        ①内部类有更好的封装性,有更多的权限修饰符,封装性可以得到更多的控制。

        ②静态内部类:由static修饰,属于类本身,只加载一次。类可以定义的成分静态内部类都可以定义,可以访问外部类的静态变量和方法,通过new 外部类.静态内部类构造器来创建对象。

        ③成员内部类:属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可以访问外部类的所有内容,通过new 外部类构造器.new 成员内部类构造器来创建对象。

        ④局部内部类:定义在方法、构造器、代码块、循环中。只能定义实例成员变量和实例方法,作用范围仅在局部代码块中。

        ⑤匿名内部类:没有名字的局部内部类,可以简化代码,匿名内部类会立即创建一个匿名内部类的对象返回,对象类型相当于当前new的类的子类类型。

17、泛型和泛型擦除是什么?

        ①泛型的本质是参数化类型,泛型提供了编译时类型的安全检测机制,该机制允许程序在编译时检测非法的类型。

        ②在编译阶段采用泛型时加上的类型参数,会被编译器在编译时去掉,这个过程就被称为类型擦除,因此泛型主要用于编译阶段,在编译后生成的Java字节代码文件中不包含泛型中的类型信息。

18、泛型标记的规范了解吗?

        ①E:值Element,在集合中使用,表示在集合中存放的元素。

        ②T:指Type,表示Java类,包括基本的类以及自定义类。

        ③K:指Key,表示键,例如Map集合中的Key。

        ④V:指Value,表示值,例如Map集合中的Value。

        ⑤N:指Number,表示数值类型。

        ⑥?:表示不确定的Java类型。

19、泛型限定是什么?

        ①类型通配符使用?表示所有具体的参数类型,在使用泛型的时候,如果希望将类的继承关系加入泛型应用中就需要对泛型做限定,具体的泛型限定有对泛型上限的限定以及对泛型下限的限定。

        ②对泛型上限的限定使用<? extends T>,它表示该通配符所代表的类型是T类的子类型或T接口的子接口。

        ③对泛型下限的限定使用<? super T>,它表示该通配符所代表的类型是T类的父类型或T接口的父接口。

20、异常有哪些分类?出现的原因是什么?

        ①Throwable是所有错误和异常的父类,Throwable分为Error和Exception。

        ②Error指Java程序运行错误,出现Error通常是因为系统的内部错误或资源耗尽,Error不能在运行过程中被动态处理,如果程序运行中出现Error,系统只能记录错误的原因和安全终止。        

        ③Exception指Java程序运行异常,即运行中发生了不期望的情况,分为RuntimeException和CheckedException。RuntimeException指在Java虚拟机正常运行期间抛出的异常,可以被捕获并处理,例如空指针异常,数组越界等。CheckedException指编译阶段强制要求捕获并处理的异常,例如IO异常,SQL异常等。

22、有哪些异常处理方式?

        ①抛出异常:遇到异常不进行具体处理,而是将异常抛出给调用者,由调用者根据情况处理。抛出异常有2种形式,一种是throws,作用在方法上,一种是throw,作用在方法内。

        ②使用try/catch进行异常的捕获处理,try中发生的异常会被catch代码块捕获,根据情况进行处理,如果有finally代码块无论是否发生异常都会执行,一般用于释放资源,JDK1.7开始可以将资源定义在try代码块中自动释放减少代码。

23、简述一下集合主要有哪些类和接口,各自有什么特点?

答:①主要有两个接口Collection和Map,其中Collection又包括List、Set和Queue。②List是有序的,主要包括ArrayList,LinkedList和Vector,ArrayList底层通过数组实现,线程不安全,Vector是线程安全的ArrayList,但效率较低,LinkedList底层通过双向链表实现,与ArrayList相比增删快查询慢。③Set是唯一且无序的,主要包括HashSet,LinkedHashSet和TreeSet。HashSet底层其实就是HashMap,利用了key来保证元素的唯一性。LinkedHashSet可以按照key的操作顺序排序,TreeSet支持按照默认或指定的排序规则排序。④Queue是队列结构,主要有ArrayBlockingQueue基于数组的阻塞队列、LinkedBlockingQueue基于链表的阻塞队列等。⑤Map以key-value键值对的形式存储元素,主要包括HashMap、LinkedHashMap和TreeMap。HashMap底层通过数组+链表/红黑树实现,LinkedHashMap可以按照key的操作顺序对集合排序,TreeMap可以按照默认或指定的排序规则对集合排序。

24、HashMap是线程安全的吗?

        ①HashMap是线程不安全的,可以使用ConcurrentHashMap保证线程安全。        

        ②ConcurrentHashMap基于减小锁粒度的思想,通过使用分段锁来实现线程安全,内部细分为很多Segment数据段,默认情况下为16个,对每个Segment的数据都单独进行加锁操作,Segment的个数为锁的并发度。ConcurrentHashMap是由Segment数组和HashEntry数组组成的,Segment继承了可重入锁,HashEntry用来存储键值对数据。

        ③Segment的结构和HashMap类似,是数组和链表结构,每个Segment里面都包含一个HashEntry数组,每个HashEntry都是一个链表结构的数据要对其进行i修改必须先获得对应的Segment锁。

        ④多线程下只要加入的数据hashCode映射的数据段不一样就可以做到并行的线程安全。

25、List、Set、Map有什么区别?

        ①List是有序、可重复、有索引的集合,继承了Collection集合全部功能 除了Collection的三种遍历方式外,可用索引遍历。

        ②Set是无序,不可重复的集合,Set的实现类LinkedHashSet和TreeSet是有序的,LinkedHashSet可以按照元素插入的顺序排序,也可以按照元素操作的时间排序,TreeSet可以按照默认的比较规则或者自定义的比较规则排序。

        ③Map是无序、以key-value的键值对形式存储元素的集合,键不可重复,值无要求,重复的键对应的值会覆盖之前的值。

26、HashSet是如何去重的?

        ①对于基本类型的包装类,可以直接按值进行比较。

        ②对于引用数据类型,会先比较hashCode()返回值是否相同,如果不同则代表不是同一个对象,如果相同则继续比较equals()方法返回值是否相同,都相同说明是同一个对象。

        ③如果希望内容相同的对象就代表对象相同,那么除了重写equals()方法还要重写hashCode()方法,因为内容相同的对象hashCode()值不一定相同,因为只有hashCode()和equals()都相同才说明是同一个对象。

27、Collection和Collections有什么区别?

        ①Collection是一个集合接口,它包括List有序集合、Set无序集合、Queue队列等。        

        ②Collections则是Collection的一个工具类,为Collection类型的对象提供了很多方便的方法,例如addAll可以直接对Collection集合批量添加元素,shuffle可以随机打乱List集合的元素顺序,sort可以对List集合进行默认或按比较器进行排序。

28、迭代器是什么?

        ①迭代器实现了Iterator接口,是用于遍历Collection集合元素的一个指针。

        ②主要有三个方法:通过iterator()获得集合的迭代器;通过hasNext()判断集合当中是否还有元素,如果有返回true,没有则返回false,初始时迭代器位于第一个元素之前;通过next()获取集合的下一个元素,并向后移动一个元素的单位。

29、在使用foreach循环遍历集合元素时能否添加或删除元素?

        使用foreach循环遍历元素集合时不能修改或删除元素,通过java -c查看字节码可以发现foreach循环实际上是用Iterator迭代器实现的

        如果进行添加或删除元素会抛出ConcurrentModificationException异常,因为添加或删除元素会改变modCount的值,modCount是集合类的一个成员变量,代表集合的修改次数,当modCount的值和预期的exceptedModCount值不一致时就会抛出ConcurrentModificationException异常。

30、存储过程和函数是什么?有什么区别?

        ①存储过程和函数是 事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。

        ②两者的区别在于函数必须有返回值,而存储过程没有返回值。

31、触发器是什么?

        ①触发器是与表有关的数据库对象,指在 insert/update/delete 之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作 。

        ②使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。

32、优化SQL的步骤了解吗?

        ①查看SQL执行频率。

        ②定位低效率执行SQL。可以通过以下两种方式:慢查询日志 : 通过慢查询日志定位那些执行效率较低的 SQL 语句。show processlist : 慢查询日志在查询结束以后才记录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,同时对一些锁表操作进行优化。

        ③通过以上步骤查询到效率低的 SQL 语句后,可以通过 EXPLAIN或者 DESC命令获取 MySQL如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。

        ④Mysql从5.0.37版本开始增加了对 show profiles 和 show profile 语句的支持。show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里了。

        ⑤MySQL5.6提供了对SQL的跟踪trace, 通过trace文件能够进一步了解为什么优化器选择A计划, 而不是选择B计划。打开trace , 设置格式为 JSON,并设置trace最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能够完整展示。

33、了解JDBC吗?

        ①JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库(java.sql,javax.sql),使用这些类库可以以一种标准的方法方便地访问数据库资源。

        ②JDBC为访问不同的数据库提供了统一的途径,为开发者屏蔽了一些细节问题。③JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

34、JDBC的操作步骤?

        ①导入相应的jar包。

        ②加载、注册sql驱动。

        ③获取Connection连接对象。

        ④创建Statement对象并执行SQL语句。

        ⑤使用ResultSet对象获取查询结果集。

        ⑥依次关闭ResultSet、Statement、Connection对象。

35、简述事务的ACID属性

        ①Atomicity表示原子性,事务中的所有操作都是不可分割的原子单位,要么全部成功,要么全部失败。

        ②Consistency表示一致性,无论正常执行还是异常退出,事务执行前后数据的完整性必须保持一致,比如转账前后双方的总金额是不变的。

        ③Isolation表示隔离性,并发操作中不同事务是互相隔离的,之间不会互相影响。

        ④Durability表示持久性,事务操作完成后数据就会被持久化修改到永久存储中。

35、简单讲讲Redis的含义

        ①Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。

        ②Redis数据库中的数据间没有必然的关联关系,内部采用单线程机制进行工作,性能比较高,支持持久化存储。

        ③支持多种数据类型,包括字符串类型 string、列表类型 list、散列类型 hash、集合类型 set、有序集合类型 sorted_set。

36、Redis有哪些应用场景?

        ①为热点数据加速查询(主要场景),如热点商品、热点新闻、热点资讯、推广类等高访问量信息等。

        ②应用于任务队列,如秒杀、抢购、购票排队等。

        ③即时信息查询,如排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等。

        ④时效性信息控制,如验证码控制、投票控制等。

        ⑤分布式数据共享,如分布式集群架构中的 session 分离以及消息队列、分布式锁等。

37、创建线程有哪几种实现方式?分别有什么优缺点?

        ①继承Thread类,重写run()方法即可。编码简单,缺点是不能继承其他类,功能单一。

        ②实现Runnable接口,重写run()方法,并将该实现类作为参数传入Thread构造器。优点是可以继承其他类,避免了单继承的局限性;适合多个相同程序代码的线程共享一个资源(同一个线程任务对象可被包装成多个线程对象),实现解耦操作,代码和线程独立。缺点是实现相对复杂。

        ③实现Callable接口,重写call()方法,并包装成FutureTask对象,再作为参数传入Thread构造器。优点是相比方式二可以获取返回值,缺点是实现复杂。

        ④可以通过线程池创建。

38、线程有哪些状态?

        ①New:用new操作创建一个新线程,此时程序还未开始运行线程中的代码。

        ②Runnable:调用start()方法后进入可运行状态。

        ③Blocked:阻塞状态,内部锁(不是juc中的锁)获取失败时进入阻塞状态。

        ④Waiting:等待其他线程唤醒时进入等待状态。

        ⑤Timed Waiting:计时等待,带超时参数的方法,例如sleep(long time)。

        ⑥Terminated:终止状态,线程正常运行完毕或被未捕获异常终止。

39、什么是线程安全问题,如何解决?

        当多个线程对同一个共享变量进行操作时可能会产生的问题。

        解决方法:

                ①使用内部锁synchronized,可以使用同步代码块,如果是实例方法可用this作为锁对象,如果是静态方法,可以用类.class作为锁,或者使用同步方法底层和同步代码块一样,如果是实例方法默认用this作为锁,如果是静态方法默认使用类.class。

        ②使用java.util.concurrent包中的锁,例如ReentrantLock。

40、多线程不可见问题的原因和解决方式?

        ①不可见的原因是每个线程有自己的工作内存,线程都是从主内存拷贝共享变量的副本值。每个线程都是在自己的工作内存操作共享变量的。

        ②解决方式:加锁:获得锁后线程会清空工作内存,从主内存拷贝共享变量最新的值成为副本,修改后刷新回主内存,再释放锁;使用volatile关键字:被volatile修饰的变量会通知其他线程之前读取到的值已失效,线程会加载最新值到自己的工作内存。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值