1.面向对象特征有哪些?
封装:把对象的属性和方法结合为一个独立的整体,尽可能的隐藏对象内部的实现细节,增加安全性。
继承:子类继承父类的属性和方法,并可以根据自己的需求扩展出新的行为,提高代码的复用性。
多态:不同对象对统一消息做出响应 ,一类事物的多种形态。
抽象:对问题领域进行分析、设计中得出得抽象的概念,用abstract关键字来修饰
2.java的基本数据类型有哪些?
整型:byte、short、int、Long
浮点型:float、double
布尔型:boolean
字符型:char
3.jdk、jre、jvm的区别
jdk是java开发工具包,是整个Java的核心,包括了java运行环境jre、java工具和java基础类库。
jre是java运行环境,包括了java虚拟机和java的一些核心类库。
jvm是Java虚拟机,是整个jav实现跨平台最核心的部分。
4.重载和重写的区别
重载:是指在发生一个类中,方法名必须相同,参数的顺序、个数、类型可以不同、方法返回值和访问修饰符也可以不同,发生在编译的时候。
重写:是发生在子父类中,方法名、参数必须相同,返回值的范围和抛出的异常范围必须小于父类,返回修饰符的范围必须大于或等于父类。
5.java中==和equals的区别
==:如果两边是基本类型的话比较的是值;如果两边是引用类型的话比较的是两边的地址。
equals:引用类型,默认情况下比较的是地址,但是像String、Integer、Date这些类库中equals被重写了,比较的是内容而不是地址。
6.String、StringBuffer、StringBuilder三者之间的区别
String:字符串常量,是线程安全的;适用于操作少量数据。
StringBuffer:字符串变量,对方法加了同步锁,所以是线程安全的;适用于多线程操作字符串缓冲区下的大量数据。
StringBuilder:字符串变量,没有对方法加同步锁,所以是非线程安全的;适用于多线程操作字符串缓冲区下的少量数据。
7.接口和抽象类的区别
(1)抽象类的子类使用extends来继承它;接口必须使用implements来实现它。
(2)抽象类中可以有main方法;但接口中不能有main方法。
(3)抽象类中可以有构造函数;接口中不能有构造函数。
(4)抽象类中的方法可以使任意的访问修饰符;但接口中的方法默认使用public来修饰。
8.String的常用方法有哪些?
indexOf():返回指定字符的索引。
charAt():返回指定索引出的字符。
replace():字符串替换。
trim():去掉字符串两边的空白。
split():分割字符串,会返回一个分割好的字符串数组。
length():返回字符串长度。
toLowerCase():将字符串转为小写字母。
toUpperCase():将字符串转为大写字母。
substring():截取字符串。
equals():字符串比较。
9.什么是单例模式,单例模式有几种?
单例模式:是指某个类的实例在多线程的环境下,只会被创建出一次。单例模式有饿汉式、懒汉式和双检锁三种。
饿汉式:线程安全,一开始就初始化。
饿汉式:非线程安全,延迟初始化。
双检锁:线程安全,延迟初始化。
10.什么是反射?获取class对象的方法有哪些?那个最常用?
反射:是指在运行状态中,任意一个类都能够获取这个类的方法、属性;对于任意一个对象,都能够调用他任意一个方法,这种动态获取数据以及动态调用对象方法的功能被称为java的反射机制。
获取class对象的三种方法:
(1)调用某个对象的.getClass()方法:
Person p = new Person();
Class class = p.getClass();
(2)调用某个类的class属性:
Class class = Person.class;
(3)使用Class类中的forName()静态方法:(最常用,因为最安全、性能最好)
Class class = Class.forName(“类的全路径”);
11.jdk1.8的新特性有哪些?
(1)Lambda表达式:()->{方法体}。
(2)方法引用:直接应用已有java类或对象的方法或构造方法。
(3)函数式接口:有且仅有一个抽象方法的接口
(4)接口允许定义一个或多个默认非抽象方法和静态方法
(5)Stream流
(6)日期和时间的改进(LocalDate、LocalTime、LocalDateTime)
(7)Optional类:Optional类可以是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
12.谈一下java中的异常
Throwable:是所有java程序中错误处理的父类,有两种子类分别是Error和Exception。
Error:表示JVM所知测到的无法预期的错误,书瑜JVM层次的严重错误,是不可捕捉的,只能显示错误信息。
Exception:表示可恢复的异常,可捕捉到的。它又分为运行时异常和非运行时异常。
运行时异常:是指RunTimeException类及其子类异常,如空指针异常、下标越界异常等。这种异常的特点是java编译器不回去检查它,也就是说程序没有捕获或抛出它,也会编译通过。
非运行时异常:是RunTimeException以外的异常,如IO异常、SQL异常等。特点是必须进行处理的异常,否则程序不能让编译通过。
常见的RunTimeException有:
①NullPointerException:空指针异常
②ClassCastException:类型强制装换异常
③IllegalArgumentException:传递非法参数异常
④ArithmeticException:算数运算异常
⑤IndexOutOfBoundsExection:下标越界异常
⑥NumberFormatException:数字格式异常
⑦UnsupportOperationException:不支持的操作异常
13.BIO、NIO、AIO的区别是什么?
BIO:同步阻塞式IO,是传统IO;特点是模式简单、使用方便,并发处理能力低。
NIO:同步式非阻塞IO,是对传统IO的升级;特点是客户端与服务端通过通道通讯,实现了多路复用。
AIO:异步非阻塞式IO,是NIO的升级;它的特点是基于时间和回调机制。
14.Thraedlocal的原理
Treadlocal:为共享变量在每个线程中创建一个副本,每个线程都可以访问自己内部的副本变量,通过Treadlocal保证线程的安全性。其实,在Threadlocal类中有一个静态内部类ThreadlocalMap,用键值对的形式存储每一个线程的变量副本,ThreadlocalMap中的key为当前Threadlocal对象,而value对应线程的变量副本。
15.谈一下同步锁、死锁、乐观锁、悲观锁
同步锁:当多个线程同时访问同一个数据时,很容易出现问题,为了避免这种情况,我们要保证线程同步互斥,也就是并发的执行多个线程,在同一时间内只允许一个线程访问共享数据。可以使用synchronized关键字获取一个对象的同步锁。
死锁:多个线程同时被阻塞,他们中的一个或多个全部都在等待某个资源的释放。
乐观锁:总是假设最好的情况,每次取数据都会认为不会修改,所以不会上锁,但在更新时会判断在这个期间内有没有更新这个数据,可以使用版本号机制和CAS实现。不会产生阻塞,进行自旋。
悲观锁:总是假设最坏的情况,每次拿数据都会认为会被修改,所以每次拿数据的时候都会上锁,这样别的线程拿数据的时候都会阻塞,直到它拿到锁。典型悲观锁:synchronized。
16.说一下synchronized底层实现原理
synchronized可以保证方法或代码块在运行时,同一时刻只有一个方法可以进入临界区,同时它还可以保证共享变量的内存可见性。
Java中每一个对象都可以作为锁:
普通同步方法:锁是当前实例对象
静态同步方法:锁是当前类的class对象
同步方法块:锁是括号里的对象
17.synchronize与volatile的区别是什么
(1)volatile只能使用在变量级别;synchronized可以使用在变量、方法和类的级别。
(2)volatile只能实现变量的修改可见性,不能保证原子性;synchronized则可以保证变量的修改可见性和原子性。
(3)volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
(4)volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
18.synchronized与Lock的区别
(1)synchronized是java内置关键字,来自jvm;Lock是一个java类,来自jdk。
(2)synchronized无法判断是否获取锁的状态;Lock可以判断是否获取到锁。
(3)synchronized会自动释放锁;Lock不能自动释放锁,需要在finally中手动释放锁。
(4)synchronized锁中多个线程有一个获得锁,其他线程进行等待,如果获得锁的线程阻塞,那么其他线程会一直等待下去;而Lock锁中就不一定会等待下去,如果尝试获取不到锁,就结束了。
(5)synchronized锁可重入、不可中断、非公平;Lock锁可重入、可判断、可公平。
(6)synchronized锁适合代码少量同步问题;Lock适合代码大量同步问题。
19.手写冒泡排序
public class Sort{
public static void sort(){
Scanner input = new Scanner(System.in);
int sort = new int[10];
int temp;
//给数组输入数据
for(int=0;i<sort.length;i++){
sort[i] = input.nextInt();
}
//遍历数组排序
for(int i=0;i<sort.length-1;i++){
for(int j=0;j<sort.length-i-1;i++){
if(sort[j]<sort[j+1]){
temp = sort[j];
sort[j] = sort[j+1];
sort[j+1] = temp;
}
}
}
for(int i = 0;i<sort.length;i++){
System.out.print(sort[i]);
}
}
}