面试准备:Java常见面试题汇总(一)

文章目录

1.面向对象的特点/特性有哪些?

面向对象四大特性包括了:抽象、封装、继承、多态。

  • 抽象
    抽象是一种思维方式,抽象出客观事物的数据和行为,以封装的方式聚合成类。
  • 封装:
    将客观事物封装成类,类中包含了属性和方法以及对这些属性、方法的不同级别的控制访问。
  • 继承
    基于现有的类的数据和功能进行拓展,继承包含了实现继承、接口继承。实现继承可以直接使用父类的属性和方法,接口继承要求子类提供实现。
  • 多态
    多态就是相同方法在不同实现下的不同表现形式,也就是不同的类虽然实现不同,但是可以共享相同的外部接口。具有解耦和复用性。

2.接口和抽象类的相同点和不同点?

相同点:

  1. 都不能被实例化。
  2. 都可以包含抽象方法。

不同点:

  1. 接口里只能包含抽象方法,静态方法和默认方法,抽象类可以包含普通方法。
  2. 接口不能包含构造器、初始化块,而抽象类可以包含构造器和初始化块。
  3. 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口。
  4. 接口中声明的变量默认都是public static final的,接口中的成员函数默认是public abstract的。抽象类则没有要求。

接口类:default方法属于实例,static方法属于类。
抽象类:可以在不提供实现的情况下继承接口。
抽象类:抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。

3.重载和重写有什么区别?

  • overload(重载)
    参数类型、个数、顺序至少有一个不相同。
  • override(重写)
    存在于父类和子类关系中。
    子类方法不能缩小父类方法的访问权限。
    子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。

4.基本数据类型有哪些?为什么需要基本数据类型?

参考:Java类型和类

5.为什么需要包装类?什么是自动拆装箱?

  • 因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。
  • 包装类就属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换。

参考:Java类型和类

6.Java类的实例化顺序?

1. 父类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
2. 子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
3. 父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
4. 父类构造方法
5. 子类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
6. 子类构造方法

结论:对象初始化的顺序,先静态方法,再构造方法,每个又是先基类后子类。

7.什么是值传递和引用传递?

值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。

8.String和StringBuilder、StringBuffer的区别?

相同点:

  1. 三者都是final关键字限定的,不能被继承。
  2. 都使用了char数组来存储。

1、String 字符串常量(final修饰,不可被继承),String是常量,当创建之后即不能更改。(可以通过StringBuffer和StringBuilder创建String对象(常用的两个字符串操作类)。)

2、StringBuffer 字符串变量(线程安全),其也是final类别的,不允许被继承,其中的绝大多数方法都进行了同步处理,包括常用的Append方法也做了同步处理(synchronized修饰)。其自jdk1.0起就已经出现。其toString方法会进行对象缓存,以减少元素复制开销。

public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
     return new String(toStringCache, true);
}

3、StringBuilder 字符串变量(非线程安全)其自jdk1.5起开始出现,也是final类别的。与StringBuffer一样都继承和实现了同样的接口和类,方法除了没使用synch修饰以外基本一致,不同之处在于最后toString的时候,会直接返回一个新对象

public String toString() {
// Create a copy, don’t share the array
return new String(value, 0, count);
}

9.Java集合框架的基础接口有哪些?集合框架的优点是什么?

Collection:
为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java平台不提供这个接口任何直接的实现。

Set:
是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。

List:
是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List更像长度动态变换的数组。

Map:
是一个将key映射到value的对象.一个Map不能包含重复的key:每个key最多只能映射一个value。

一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。

集合框架的部分优点如下:

  • 它经过了严格的测试,具有复用性和可操作性,并且某些集合框架还是线程安全的。

10.HashMap 与HashTable有什么区别?

  • HashTable
    底层数组+链表实现,无论key还是value都不能为null线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
    初始size为11,扩容:newsize = olesize*2+1
    计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
  • HashMap
    底层数组+链表实现,可以存储null键和null值线程不安全
    初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
    扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
    插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
    当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
    计算index方法:index = hash & (tab.length – 1)

11.ArrayList 和 LinkedList 有什么区别?

ArrayList和LinkedList都实现了List接口,有以下的不同点:

  1. ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
  2. 相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
  3. LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。

12.简单介绍Java异常框架?Error与Exception有什么区别?

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。

Error 表示应用程序本身无法克服和恢复的一种严重问题,程序只有死的份了,例如,说内存溢出和线程死锁等系统问题。

Exception表示程序还能够克服和恢复的问题,其中又分为

  • unchecked异常
    派生自RuntimeException的异常类。使用throw语句可以随时抛出这种异常对象(也可以不必抛出)。例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException)。RuntimeException是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉
  • checked异常
    直接派生自Exception的异常类,必须被捕获或再次声明抛出。例如输入输出异常(IOException)或者数据库异常(SQLException)等等。

在这里插入图片描述

13.throw 和 throws关键字有什么区别?

throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常

throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)

14.列举几个常见的运行时异常?

常用的RuntimeException如:

java.lang.ClassNotFoundException 类不存在异常

java.lang.NullPointerException 空指针异常

java.lang.IndexOutOfBoundsException 数据下标越界

java.lang.IllegalArgumentException 参数异常

java.io.FileNotFoundException 文件不存在异常

15.final, finally, finalize有什么区别?

  • final:
    Java并发编程实战——你真的了解final吗?
    注意:final重排序规则的作用是:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保障。

  • finally:
    其作用就是保证在try块中的代码执行完成之后,不管try块中是否抛出异常,必然会执行finally中的语句。

  • finalize:
    方法名。 finalize是在对象回收前做一些清扫工作,当对象不可达的时候,要经过至少两次标记的过程才真正宣告这个对象的死亡。

finalize()方法可以被子类对象所覆盖,然后作为一个终结者,当GC被调用的时候完成最后的清理工作(例如释放系统资源之类)。这就是终止。默认的finalize()方法什么也不做,当被调用时直接返回。

  • 对象在进行可达性分析后被发现不可达,它将会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法:当对象没有覆盖finalize()方法或者finalize()方法已经被JVM调用过,那么就没必要执行finalize()方法;如果被判定为有必要执行finalize()方法,那么此对象将会放置在一个叫做F-Quenen的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalize线程去触发这个方法。
  • 稍后GC将对F-Queue中的对象进行第二次小规模的标记,虚拟机会触发一个Finalize()线程去执行,此线程是低优先级的。然后该对象就会等待回收。
  • 如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关系即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时它将被移出“即将回收”集合;finalize()方法是对象逃脱死亡的最后一次机会,如果对象这时候还没有成功逃脱,那他就会真的被回收了。

16.描述Java内存模型?

参考JVM虚拟机八问

17.Java中垃圾收集的方法有哪些?

参考JVM虚拟机八问

18.如何判断一个对象是否存活?(或者GC对象的判定方法)

参考JVM虚拟机八问

19. Minor GC、Major GC和Full GC之间的区别?

参考JVM虚拟机八问

19.Java GC是在什么时候,对什么东西,做了什么事情?

参考JVM虚拟机八问

20.分别写出堆内存溢出与栈内存溢出的程序

# 栈内存溢出
public void f() {
        f();
    }
# 堆内存溢出
public void testd() {
        Listlist = new ArrayList<>(); 
        int i = 0; 
        while (true) {
            list.add(new String(i + ""));
            i++;
        }
    }

21.Java 8 内存模型进行了哪些改进?

在 jdk1.8 中对内存模型中方法区的实现永久代(Perm Gen space)进行了移除,取而代之的是元空间(Metaspace)。

原因是在方法区中实现垃圾回收的条件比较苛刻,因此存在着内存溢出的风险。在 jdk1.8 之后,当方法区内存使用较多时,元空间会使用物理内存,减少了风险。

22.简述java内存分配与回收策率以及Minor GC和Major GC

(1)对象优先在堆的Eden区分配。

(2)大对象直接进入老年代.

(3)长期存活的对象将直接进入老年代.

当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GC.Minor Gc通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生Gc的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。

23.描述Java类加载机制?

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。

类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它

类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。

  • 加载:查找并加载类的二进制数据。
    加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:

    1. 通过一个类的全限定名获取该类的二进制流(也就是字节码文件)。
    2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。
    3. 在内存中生成该类的Class对象,作为该类的数据访问入口。
  • 验证:确保被加载的类的正确性

  • 准备:为类的静态变量分配内存,并将其初始化为默认值

//在准备阶段value初始值为0 。在初始化阶段才会变为123 。
public static int value=123;
  • 解析:把类中的符号引用转换为直接引用
    符号引用就是一组符号来描述目标,可以是任何字面量。
    直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
    符号引用转换为直接引用:比如class.NAMETYPE这种形式的字符串转为具体的方法在内存中的地址。

  • 初始化:对类变量进行赋值及执行静态代码块。

类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下:

  1. 创建类的实例,也就是new的方式。
  2. 初始化某个类的子类,则其父类也会被初始化。
  3. 调用类的静态方法或者访问静态变量
  4. 反射(如 Class.forName(“com.shengsiyuan.Test”))
  5. Java虚拟机启动时被标明为启动类的类( JavaTest),直接使用 java.exe命令来运行某个主类。

24.什么是双亲委派模型?

双亲委派模型,简单说就是类加载器试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载Java类型。

25.类加载器有哪些?

实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。
在这里插入图片描述
主要有一下四种类加载器:
1、 启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。

2、 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

3、 系统类加载器(system class loader,也称为Application class Loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

4、用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。

26.JVM,JDK和JRE有什么区别与联系?

  • JVM:
    Java虚拟机能够识别.class类文件的字节码并解释成机器码交给本地系统去执行。
    通过源程序到字节码,再到对应平台的机器语言,所以Java能够进行一次编译,处处运行。

  • JRE:
    JRE是java runtime environment(java运行环境)的缩写。光有JVM还不能让class文件执行,因为在解释class的时候JVM会调用解释所需要的基本类库。

  • JDK:
    JDK是java development kit(java开发工具包)的缩写,它集成了 jre 和一些好用的小工具。总的来说JDK是用于java程序的开发,而jre则是只能运行class而没有编译的功能。
    小工具:

    • javac.exe(javac命令用于编译Java源文件)
    • java.exe(ava命令用于运行Java程序,它会启动Java虚拟机,Java虚拟机加载相关的类,然后调用主程序main()方法)
    • jar.exe(jar命令能够把Java应用打包成一个文件,jar命令可以打包任意文件,但通常情况下我们只把编译后的.class文件打包成JAR包)

eclipse、idea等其他IDE有自己的编译器而不是用JDK bin目录中自带的,所以在安装时你会发现他们只要求你选jre路径就ok了。

27.Java 反射机制的作用?优缺点?

java反射机制的作用:

(1)在运行时判断任意一个对象所属的类

(2)在运行时构造任意一个类的对象

(3)在运行时判断任意一个类所具有的成员变量和方法

(4)在运行时调用任意一个对象的方法

反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为Java反射机制。

优点:
可以动态的创建对象和编译,最大限度发挥了java的灵活性。

缺点:
对性能有影响。使用反射基本上一种解释操作,告诉JVM我们要做什么并且满足我们的要求,这类操作总是慢于直接执行java代码。

28.反射创建实例的方法

  1. 通过全限定类名获取Class
Class<?> clz=Class.forName("String.class");
# 或者
String s="";
Class<? extends String> clz = s.getClass();
# 或者
Class<String> clz = String.class;
  1. 生成对象
# 通过构造器生成对象
Constructor<?> constructor = clz.getConstructor();
Object o = constructor.newInstance();
# 或者
# 直接生成对象
Object o = clz.newInstance();

29.哪些项目中用到了Java反射机制?

jdbc中有一行代码:Class.forName(‘com.MySQL.jdbc.Driver.class’).newInstance();

Spring IOC依赖注入时也用到了。

30.线程同步的方法有哪些?

synchronized 方法
synchronized 代码块
volatile
ReentrantLock
CountDownLatch
CyclicBarrier
ThreadLocal

31.解释一下锁的一些基本概念:可重入锁、可中断锁、公平锁、读写锁、乐观锁

  1. 可重入锁

如果锁具备可重入性,则称作为可重入锁。像synchronized和ReentrantLock都是可重入锁,可重入性在我看来实际上表明了锁的分配机制:基于线程的分配,而不是基于方法调用的分配。

synchronized和Lock都具备可重入性。

  1. 可中断锁

可中断锁:顾名思义,就是可以相应中断的锁。

在Java中,synchronized就不是可中断锁,而Lock是可中断锁。如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。在前面演示lockInterruptibly()的用法时已经体现了Lock的可中断性。

  1. 公平锁

公平锁:即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。

非公平锁:即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。

在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。

而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。

  1. 读写锁

读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。

正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。

ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。

可以通过readLock()获取读锁,通过writeLock()获取写锁。

  1. 乐观锁

CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
以及ABA问题,可以通过版本号解决。

32.synchronized什么情况下会释放锁?

1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
2)线程执行发生异常,此时JVM会让线程自动释放锁。
3).调用wait方法,在等待的时候立即释放锁,方便其他的线程使用锁.

33. synchronized和ReentrantLock有什么区别?

Lock和synchronized有以下几点不同:

1、ReetrantLock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

2、synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

3、Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

4、通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

5、Lock可以提高多个线程进行读操作的效率。

在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

6、Lock可以设置等待锁的时间,而synchronized不行

34.线程池的作用有哪些?

线程池的作用: 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。
常用线程池:ExecutorService 是主要的实现类,其中常用的有

Executors.newSingleThreadPool(),
 
newFixedThreadPool(),
 
newCachedTheadPool(),
 
newScheduledThreadPool()

35. 列举几个设计模式

设计模式是经常被问到的题型,需要了解几种常用的概念、应用场景、java的实现方式、以及在jdk及一些开源项目(如:spring,tomcat)中的应用

36.Java元注解有哪些,都有什么作用?

注解的注解,称为元注解。

  1. @Retention

定义注解的保留策略,由RetentionPolicy定义,包括以下3种策略:
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。
1.一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解,比如@Deprecated使用RUNTIME注解
2.如果要在编译时进行一些预处理操作,比如生成一些辅助代码(比如Android中的Butter knife),就用 CLASS注解;
3.如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,使用SOURCE 注解。

  1. @Target

定义注解的使用对象,注解可以用在类上、方法上、属性上等,由ElementType枚举类定义。

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    /** 用于描述类、接口(包括注解类型) 或enum声明 */
    TYPE,
 
    /** Field declaration (includes enum constants) */
    /** 用于描述域 */
    FIELD,
 
    /** Method declaration */
    /** 用于描述方法 */
    METHOD,
 
    /** Formal parameter declaration */
    /** 用于描述参数 */
    PARAMETER,
 
    /** Constructor declaration */
    /** 用于描述构造器 */
    CONSTRUCTOR,
 
    /** Local variable declaration */
    /** 用于描述局部变量 */
    LOCAL_VARIABLE,
 
    /** Annotation type declaration */
    /** 用于描述注解,比如注解A描述注解B */
    ANNOTATION_TYPE,
 
    /** Package declaration */
    /** 用于描述包 */
    PACKAGE,
 
    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
     /** 用来标注类型参数 */
    TYPE_PARAMETER,
 
    /**
     * Use of a type
     *
     * @since 1.8
     */
     /** 能标注任何类型名称 */
    TYPE_USE
}
  1. @Inherited
  • 类继承关系中@Inherited的作用
    类继承关系中,子类会继承父类使用的注解中被@Inherited修饰的注解

  • 接口继承关系中@Inherited的作用
    接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰

  • 类实现接口关系中@Inherited的作用
    类实现接口时不会继承任何接口中定义的注解

  1. @Documented

javadoc工具会使用该注解生成文档。

37.jdk自带了哪些注解,有什么作用

@Overried
告诉编译器要检查该方法是重写父类的方法

@Deprecated
标记某个类或方法等已经废弃,不推荐使用,保留仅为兼容以前的程序

@SuppressWarnings
抑制编译器警告

@FunctionalInterface
用来指定该接口是函数式接口

@SafeVarargs
处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}

@SafeVarargs注解,只能用于标记构造函数和方法,由于保留策略声明为RUNTIME,所以此注解可以在运行时生效。
使用的时候要注意:@SafeVarargs注解,对于非static或非final声明的方法,不适用,会编译不通过。
对于非static或者非final声明的方法一般使用@SuppressWarnings(“unchecked”)

public class SafeVarargsAnnotation<S>{

    private S[] args;

    //构造函数可以使用@SafeVarargs标记
    @SafeVarargs
    public SafeVarargsAnnotation(S... args){
        this.args = args;
    }

    //此处不能使用@SafeVarargs,因为此方法未声明为static或final方法,如果要抑制unchecked警告,可以使用@SuppressWarnings注解
    @SuppressWarnings("unchecked")
    //@SafeVarargs
    public void loopPrintArgs(S... args){
        for (S arg : args) {
            System.out.println(arg);
        }
    }

    //final方法可以使用@SafeVarargs标记
    @SafeVarargs
    public final void printSelfArgs(S... args){
        for (S arg : this.args) {
            System.out.println(arg);
        }
    }
    //static方法可以使用@SafeVarargs标记
    @SafeVarargs
    public static <T> void loopPrintInfo(T ... infos){
        for (T info : infos) {
            System.out.println(info);
        }
    }

}

38.char 型变量中能不能存贮一个中文汉字,为什么?

Java中编译成的class使用的编码是Unicode,它是16位的,所以存储的中文汉字也是16位的。因为char也是16位的,所以可以。

如果使用utf8编码,它是3个字节的,char无法存储。

39.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。

当然,你未必要按照Java规定去做,你可以使得相同对象有不同的HashCode,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

40.原生JDBC操作数据库流程?

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/*
 * jdbd原生开发步骤,
 */
public class Test {
    public static void main(String[] args) throws Exception {
        //注册驱动,反射方式加载
        Class.forName("com.mysql.jdbc.Driver");
        //设置url
        String url = "jdbc:mysql://127.0.0.1:3306/day08";//person是数据库名,连接是数据库须要开启
        //设置用户名
        String username = "root";
        //设置密码
        String password = "root";
        //获得连接对象
        Connection con = DriverManager.getConnection(url, username, password);
        //System.out.println(con);
        //获得执行者对象
        String sql = "select * from phones";
        PreparedStatement ps = con.prepareStatement(sql);
        //获得结果集
        ResultSet rs = ps.executeQuery();
        //结果集处理,
        while(rs.next()){
            System.out.println(rs.getString("id")+"  "+rs.getString("pinpai")+"  "+rs.getString("xinghao")+"  "+rs.getString("jiage"));
        }
        //释放资源
        rs.close();
        ps.close();
        con.close();
    }
}

1、class.forName()加载数据驱动

2、DriverManager.getConnection()获取数据库连接对象。

3、根据SQL或sql会话对象,有两种方式Statement、PreparedStatement。

4、执行sql处理结果集,如果有参数就设置参数。

5、关闭结果集,关闭会话,关闭资源。

41.构造器(constructor)是否可被重写(override)?

不能,因为构造器不能被继承。
构造器能被重载Overload。

42.Java8十大新特性?

参考Java8新特性

发布了431 篇原创文章 · 获赞 329 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/105028086