2302 java基础面试题

1.JVM、JRE、JDK的区别:

JVM:java虚拟机,是java实现跨平台的最核心部分,能够运行java语言所开发的程序

JRE:java运行环境,是运行java程序所必须的环境的集合,包括JVM+java系统类库

JDK:java开发工具包,是java的核心,包括JRE+编译、运行等命令工具

2.说一下什么是 javaBean 规范:

(1)javabean 类必须是一个公共类,用 public 修饰

(2)属性都是私有的--private

(3)提供无参构造器

(4)属性应该通过一组存取方法(setXXX 和 getXXX 方法)来访问

(5)实现序列化接口(Serializable)

3.java的8种基本数据类型是什么?(简述java的8种基本数据类型),引用类型包括什么?

基本类型

byte:字节型,用于存储整数的,占用1个字节,范围-128到127

short:短整型,用于存储整数的,占用2个字节,范围-32768到32767

int:最常用的整型,用于存储整数的,占用4个字节,范围-2^31到2^31-1

long:长整型,用于存储较大的整数,占用8个字节,范围-2^63到2^63-1

float:单精度浮点数,用于存储小数的,占用4个字节,不能表示精确的值

double:双精度浮点数,最常用的存储小数的类型,占用8个字节,不能表示精确的值

boolean:布尔型,存储true或false,占用1个字节

char:字符型,采用Unicode字符编码格式,存储单个字符,占用2个字节

引用数据类型

类(class)

接口(interface)

数组([])

枚举

2302 java基础面试题_第1张图片

 

4.访问修饰符(权限修饰符都有哪些)

private 私有的 default 默认的protected 受保护的 public 公共的

5.switch可以作用于哪些数据类型上?

byte,short,int,char,String,枚举,其余类型都不允许

6. java是值传递还是引用传递?

在java中,无论是基本类型还是引用类型,都是值传递

对于基本类型而言,传递的是具体的值的副本

对于引用类型而言,传递的是具体的地址的副本

  • 值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

  • 引用传递:指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数

实例1

public class TestOne {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;
        swap(num1, num2);
        System.out.println("num1 = " + num1);
        System.out.println("num2 = " + num2);
    }
    public static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

输出:2302 java基础面试题_第2张图片

 

为什么swap输出的值进行了交换,而main输出的却没交换?

1、首先对于基本数据类型来说,使用的是值传递。
即:t=a;a=b;b=t; 这种情况。
2、但在函数方法中,即实参传递给形参这种情况下,首先把实参复制了一份,并复制给形参。也就是得到的形参是实参的备份。
3、通过对复制出来的备份进行值的交换,并不会影响原来的数值。这也就说明了为什么swap输出的值进行了交换,而main输出的却没交换。
​

实例2

public class TestTwo {
    public static void main(String[] args) {
        Student t1 = new Student("张三", 18);
        Student t2 = new Student("李四", 19);
        swap(t1, t2);
        System.out.println(t1);
        System.out.println(t2);
    }
​
    private static void swap(Student t1, Student t2) {
        Student t = t1;
        t1=t2;
        t2=t;
        System.out.println("t1:"+t1);
        System.out.println("t2:"+t2);
    }
}
class Student {
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

输出:

2302 java基础面试题_第3张图片

原因同实例1,只不过本实例是将实参的地址复制了一份,并赋值给形参,然后进行交换,使其改变指向。
但是,注意: 这并不是引用传递,在Java里只能叫传递了对象的引用,本质上是传递了对象的引用(地址)的副本,这也算值传递。

7.break ,continue ,return 的区别及作用

break 结束当前的循环体

continue 跳出本次循环,继续执行下次循环-

return 结束当前的方法,直接返回

8.&和&&的区别

&是逻辑与,&&是短路与。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

9.面向对象三大特性

封装: 类:封装的是对象的属性和行为 方法:封装的是具体的业务逻辑功能实现 访问控制修饰符:封装的是具体的访问权限,以保护数据的安全 继承: 作用:代码复用 超类:所有派生类所共有的属性和行为 接口:部分派生类所共有的属性和行为 派生类:派生类所特有的属性和行为 单一继承、多接口实现,具有传递性 多态: 行为多态:所有抽象方法都是多态的(通过方法的重写实现的 对象多态:所有对象都是多态的(通过向上造型来实现 向上造型、强制类型转换、instanceof判断

10.重载(Overload)和重写(Override)的区别

重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类

11. ==和 equals 的区别是什么

==: 它的作用是判断两个对象的内存地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。有两种使用情况:

情况1:类没有覆盖 equals() 方法,等价于通过“==”比较这两个对象。

情况2:类覆盖了 equals() 方法。一般我们都覆盖 equals() 方法来判断两个对象的内容相等;若它们的内容相等,则返回 true

12. 实例变量与静态变量的区别:

实例变量和静态变量都属于成员变量

实例变量:是属于对象的,在创建对象时存储在内存堆中,创建多少个对象,则实例变量就会

在内存堆中存在多少份,需要通过引用变量来访问

静态变量:是属于类的,在类被加载时存储在内存方法区中,无论创建多少个对象,静态变量

在内存中都只有一份,常常通过类名点来访问

13. 抽象类与接口的区别:

联系:

(1)接口和抽象类都不能被实例化,用于被其他类实现和继承。

(2)接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现

这些抽象方法。

区别:

(1)接口只能定义静态常量,不能定义普通成员变量;抽象类则可以定义普通成员变量,

也可以定义静态常量。

(2)接口不能包含构造器,抽象类可以包含构造器。(抽象类里的构造器并不是用于创建

对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。)

(3)一个类最多只有一个直接父类,包括抽象类,但一个类可以实现多个接口,通过实

现多个接口可以弥补 java 单继承的不足。

(4)抽象类可以有不是抽象的方法。接口中所有的方法都是抽象的(JDK1.8 以后,

接口中可以有 static 修饰的实例方法)。

当用于关系比较密切的对象时用抽象类,当为不相关的类提供通用功能时用接口。

14.Instanceof 有什么作用?

Instanceof 的作用是判断一个引用类型的变量所指向的对象是否是一个类的实例。

15.接口是否可继承接口? 抽象类是否可实现接口? 抽象类是否可继承实体类?

接口可以继承接口,并且可以继承多个其它接口;

抽象类可以实现接口中的方法;

抽象类可以继承实体类。

16.函数式接口是什么?方法引用?

所谓"函数式接口",是指仅仅只包含一个抽象方法,但是可以有多个非抽象方法(默认方法)的 接口。

Java9允许通过::关键字来传递方法或构造函数的引用。

17.int 和 Integer 有什么区别

Java 是面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型,int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

Java 为每个原始类型提供了包装类型:

原始类型: boolean,char,byte,short,int,long,float,double

包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

18.成员变量与局部变量的区别有哪些

成员变量:方法外部,类内部定义的变量

局部变量:类的方法中的变量。

作用域

成员变量:针对整个类有效。

局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)

存储位置

成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。

局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。

生命周期

成员变量:随着对象的创建而存在,随着对象的消失而消失

局部变量:当方法调用完,或者语句结束后,就自动释放。

初始值

成员变量:有默认初始值。

局部变量:没有默认初始值,使用前必须赋值。

使用原则

在使用变量时需要遵循的原则为:就近原则

首先在局部范围找,有就使用;接着在成员位置找。

19.静态方法和实例方法有何不同?

静态方法实例方法的区别主要体现在两个方面:

在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。

静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制

20.构造方法有哪些特性

名字与类名相同;

没有返回值,但不能用void声明构造函数;

生成类的对象时自动执行,无需调用。

21.一个类的构造方法的作用是什么?

主要作用是创建对象时被调用,完成对类对象的初始化工作

22.String s = new String(“abc”);创建了几个字符串对象

当JVM遇到上述代码时,会先检索常量池中是否存在“abc”,如果不存在“abc”这个字符串,则会先在常量池中创建这个字符串。然后再执行new操作,在堆内存中创建一个String对象,对象的引用赋值给s。此过程创建了2个对象。

当然,如果检索常量池时发现已经存在了对应的字符串,那么只会在堆内创建一个新的String对象,此过程只创建了1个对象

23.说出String类中常用的方法有哪些

indexOf():返回指定字符的索引。

charAt():返回指定索引处的字符。

replace():字符串替换。

trim():去除字符串两端空白。

split():分割字符串,返回一个分割后的字符串数组。

getBytes():返回字符串的 byte 类型数组。

length():返回字符串长度。

toLowerCase():将字符串转成小写字母。

toUpperCase():将字符串转成大写字符。

substring():截取字符串。

equals():字符串比较

24.什么是字符串常量池?

字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

25.String为什么是不可变的吗?

简单来说就是String类利用了final修饰的char类型数组存储字符

26.String和StringBuffer、StringBuilder有什么区别

  • String 对象是不可变的对象,每次修改操作都会生成新的 String 对象,修改性能不好;

  • StringBuffer、StringBuilder 是可变字符串,可以在原有对象的基础上进行修改,修改性能好;

  • StringBuffer 和 StringBuilder 区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的;

  • StringBuilder 的性能略高于 StringBuffer,所以在单线程环境下推荐使用

  • StringBuilder,多线程环境下推荐使用 StringBuffer。

27.StringBuilder 类的常用方法?

append():追加字符串

insert():插入字符串

delete():删除字符串

replace():替换字符串

reverse():字符串反转

28.java 中 IO 流分为几种

按照流的流向分,可以分为输入流和输出流;

按照操作单元划分,可以分为字节流和字符流;

按照流的角色划分,可以分为节点流和处理流。

节点流:可以从或向一个特定的地方(节点)读写数据,直接跟数据源相接。常用的节点流有:

FileInputStream、FileOutputStream、ByteArrayInputStream、

ByteArrayOutputStream。

处理流:是对一个已存在的流的基础之上进行功能扩展。常用的过滤流有:

BufferedInputStream、BufferedOutputStream、InputStreamReader、

OutputStreamWriter、ObjectInputStream、ObjectOutputStream。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

29.BIO、NIO、AIO 有什么区别?(了解)

(1)同步阻塞BIO

一个连接一个线程。

JDK1.4之前,建立网络连接的时候采用BIO模式,先在启动服务端socket,然后启动客户端socket,对服务端通信,客户端发送请求后,先判断服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝请求,如果有的话会等待请求结束后才继续执行。

(2)同步非阻塞NIO

NIO主要是想解决BIO的大并发问题,BIO是每一个请求分配一个线程,当请求过多时,每个线程占用一定的内存空间,服务器瘫痪了。

JDK1.4开始支持NIO,适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中。

一个请求一个线程。

(3)异步非阻塞AIO

一个有效请求一个线程。

JDK1.7开始支持AIO,适用于连接数目多且连接比较长的结构,比如相册服务器,充分调用OS参与并发操作。

30.Files的常用方法都有哪些?

Files. exists():检测文件路径是否存在。

Files. createFile():创建文件。

Files. createDirectory():创建文件夹。

Files. delete():删除一个文件或目录。

Files. copy():复制文件。

Files. move():移动文件。

Files. size():查看文件个数。

Files. read():读取文件。

Files. write():写入文件。

···

31.什么叫对象序列化?什么是反序列化?实现对象序列化需要做哪些工作?

序列化:把对象转化为可传输的字节序列的过程称为序列化

反序列化:把字节序列还原为对象的过程称为反序列化

其实序列化最终的目的是为了对象数据存储,或者进行网络传输。Java实现序列化很简单,只

需要被序列化对象类实现Serializable接口,然后使用对象流进行序列化和反序列化。可以使

用ObjectOutputStream进行对象序列化,使用ObjectInputStream进行对象反序列化。

32.什么是集合,集合和数组的区别

集合:用于存储数据的容器

集合和数组的区别

数组是固定长度的;集合是可变长度的。

数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

数组是Java语言中内置的数据类型,是线性排列的,执行效率和类型检查都比集合快,集合提供了众多的属性和方法,方便操作。

33.Collection和Collections的区别:

Collection是一个集合接口,是集合类的一个顶级接口,它里面定义了集合通用的方法,List

与Set直接继承了Collection接口。

Collections是集合的一个工具类,其中提供了一系列静态方法,用于对集合中的元素进行排

序、搜索以及线程安全等操作。

34.迭代器 Iterator 是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration(枚举),迭代器允许调用者在迭代过程中移除元素。

Enumeration类 重要的遍历

Enumeration类不是一种数据结构,但是它对其他数据结构十分重要

它可以从别的数据结构获得连续的数据元素,比如遍历集合

public static void main(String [] args) {
        Hashtable hashtable = new Hashtable();
        hashtable.put(11, 12);
        hashtable.put(22, 15);
        hashtable.put(33, 45);
        hashtable.put(44, 16);
        Enumeration elements = hashtable.elements();
        while (elements.hasMoreElements()) {
            //hasMoreElements() 是检测Enumeration 对象是否还有元素,有则返回true,否则faluse
           Integer next= elements.nextElement();
            //nextElement()   如果Enumeration对象还有元素,该方法得到下一个元素
           System.out.print(next+" ");
        }
        System.out.println();
}
//结果: 16 45 15 12

这个类有两个方法

  • hasMoreElements()

这是检测Enumeration 对象是否还有元素,有则返回true,否则faluse

  • nextElement()

如果Enumeration对象还有元素,该方法得到下一个元素

35.Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

List list = new ArrayList<>();
​
Iterator it = list. iterator();
​
while(it. hasNext()){
​
 String obj = it. next();
​
 System. out. println(obj);
​
}

Iterator 的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

36.怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。

示例代码如下:

List list = new ArrayList<>();
​
list. add("x");
​
Collection clist = Collections. unmodifiableCollection(list);
​
clist. add("y"); // 运行时此行报错
​
System. out. println(list. size());

37.List、Set和Map的区别是什么?

Java 集合容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、List、Queue,Map接口不是collection的子接口。

List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。

Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。常用实现类有 HashSet、LinkedHashSet 以及 TreeSet。

Map: 是一个键值对集合,存储键和值之间的映射。Key无序,唯一;value 不要求有序,允许重复。Map没有继承Collection接口,从Map集合中检索元素时,只要给出键对象,就能返回对应的值对象。

常用实现类有HashMap、LinkedHashMap、TreeMap、HashTable

2302 java基础面试题_第4张图片

 

2302 java基础面试题_第5张图片

38.ArrayList、Vector和LinkedList的区别:

这三者都是实现集合框架中的 List 接口,也就是所谓的有序集合,因此具体功能也比较近似,比如都提供搜索、添加或者删除的操作,都提供迭代器以遍历其内容等功能。

数据结构实现:ArrayList 和 Vector 是动态数组的数据结构实现,而 LinkedList 是双向循环链表的数据结构实现。

随机访问效率:ArrayList 和 Vector 比 LinkedList 在根据索引随机访问的时候效率要高,因为 LinkedList 是链表数据结构,需要移动指针从前往后依次查找。

增加和删除效率:在非尾部的增加和删除操作,LinkedList 要比 ArrayList 和 Vector 效率要高,因为 ArrayList 和 Vector 增删操作要影响数组内的其他数据的下标,需要进行数据搬移。因为 ArrayList 非线程安全,在增删元素时性能比 Vector 好。

内存空间占用:一般情况下LinkedList 比 ArrayList 和 Vector 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,分别是前驱节点和后继节点

线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;Vector 使用了 synchronized 来实现线程同步,是线程安全的。

使用场景:在需要频繁地随机访问集合中的元素时,推荐使用 ArrayList,希望线程安全的对元素进行增删改操作时,推荐使用Vector,而需要频繁插入和删除操作时,推荐使用 LinkedList。

ArrayList 、 LinkedList、Vector的区别如下:

2302 java基础面试题_第6张图片

39.遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?

遍历方式有以下几种:

for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。

for (int i = 0; i < list.size(); i++) {
    list.get(i);
}

迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的差异,提供统一遍历集合的接口。Java 在 Collections 集合都支持了 Iterator 遍历。

Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    iterator.next();
}

foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中不能对集合进行增删操作。

for (ElementType element : list) {
}

40.说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一哈希值的数据都存在一个链表中。但当位于一个链表中的元素较多,即hash值相等的元素较多时,通过key依次查找效率偏低。而JDK1.8中,哈希表存储策略改为:数组+链表+红黑树实现,当链表长度超过阈值(大于8)时,将链表转换为红黑树,这样大大减少了查找时间。简单来讲,hash表是由数组+链表+红黑树(JDK1.8增加的红黑树)实现的

2302 java基础面试题_第7张图片

 

41.HashSet如何检查重复?HashSet是如何保证数据不可重复的?

向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,还要结合equles方法比较。HashSet 中的add()方法会使用HashMap 的put()方法。

HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V,所以不会重复

42.什么是 Map?实现类是什么?有什么区别?

Map 中存放是 Key 和 value 的键值对。

]实现类是 HashMap(查询速度快,非线程安全的)和 TreeMap(查询速度慢,元素的排 列顺序是不固定的)和 Hashtable(线程安全的,效率慢)。

遍历 key 方法:keySet(),

遍历 value 方法:values(),

遍历 entry 键值对方法: entrySet()。

43. HashMap 和 HashTable 的区别:

(1)HashMap 允许空键值对(key 和 value 都允许出现 null 值),HashTable 不允许

(2)HashMap 不是线程安全的,HashTable 是

(3)HashMap 的默认容量为 16,而 HashTable 为 11

(4)HashMap 扩容时,将容量变为原来 的 2 倍,而 HashTable 扩容时,将容量变为原来的 2 倍加 1.

44、说一下 HashMap 的实现原理?

(1)简介

HashMap基于map接口,元素以键值对方式存储,允许有null值,HashMap是线程不安全的。

(2)基本属性

初始化大小,默认16,2倍扩容; 负载因子0.75; 初始化的默认数组; size threshold。判断是否需要调整hashmap容量;

(3)HashMap的存储结构

JDK1.7中采用数组+链表的存储形式。

HashMap采取Entry数组来存储key-value,每一个键值对组成了一个Entry实体,Entry类时机上是一个单向的链表结构,它具有next指针,指向下一个Entry实体,以此来解决Hash冲突的问题。

HashMap实现一个内部类Entry,重要的属性有hash、key、value、next。

2302 java基础面试题_第8张图片

 

JDK1.8中采用数据+链表+红黑树的存储形式。当链表长度超过阈值(8)时,将链表转换为红黑树。在性能上进一步得到提升。

2302 java基础面试题_第9张图片

 

45.HashMap的put方法的具体流程

实现原理

(1)首先将k,v封装到Node对象当中(节点)。

(2)然后它的底层会调用K的hashCode()方法得出hash值。

(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。

46. Java异常体系:

顶层是Throwable,它的下面是ErrorException

  • Error:错误,表示系统级别错误,是不可恢复的错误,比如:内存溢出、栈溢出等。异常处理机制处理不了

  • Exception:异常/意外,表示程序级别错误,可以通过异常处理机制恢复,下面有很多子类型表达了不同的异常类型,分两个部分:

    • RuntimeException非检查异常:程序运行过程中可能会发生的溢出,一般为代码逻辑错误,处理不处理都可以。像:空指针异常、数组下标越界异常、类型转换异常等。

    • 检查异常:为编译期间可以检查到的异常,必须进行处理(或捕获或throws)。像:IOException、FileNotFoundException等。

2302 java基础面试题_第10张图片

 

47.final、finally、finalize的区别:

final:是关键字,被final修饰的变量初始化后不能被改变,被final修饰的方法不能被重写,

被final修饰的类不能被继承

finally:是在异常处理时的finally块,不管有没有异常被抛出、捕获,finally块都会被执行

finalize:是方法名,它是在Object类中定义的,因此所有的类都继承了它。finalize()方法是

在垃圾回收器删除对象之前对这个对象调用的。

48.try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally{}里的 code 会不会被执行,什么时候被执行,在 return前还是后?

会执行

  • 在try中return的话,会把return的值存储进临时存储变量中,然后在执行finally,最后返回的是临时变量的值。

  • 但是如果在finally中return的话,那finally的逻辑执行完才会存储进临时存储变量中,最终返回

  • return的执行优先级高于finally的执行优先级,但是return语句执行完毕之后并不会马上结束函数,而是将结果保存到栈帧中的局部变量表中,然后继续执行finally块中的语句;

  • 如果finally块中包含return语句,则不会对try块中要返回的值进行保护,而是直接跳到finally语句中执行,并最后在finally语句中返回,返回值是在finally块中改变之后的值;

49.try-catch-finally 中哪个部分可以省略?

try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。

50.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。

51.异常的处理

运行时异常不需要预处理,通过规范的代码可以避免产生这种异常 编译时异常必须预处理,否则编译报错,有两种预处理方式 :

· 捕获处理

· 抛出处理

52.throw 和 throws 的区别是什么?

Java 中的异常处理除了包括捕获异常和处理异常之外,还包括声明异常和拋出异常,可以通过 throws 关键字在方法上声明该方法要拋出的异常,或者在方法内部通过 throw 拋出异常对象。

throws 关键字和 throw 关键字在使用上的几点区别如下:

throws: 跟在方法声明后面,后面跟的是异常类名 throw: 用在方法体内,后面跟的是异常类对象名

throws: 可以跟多个异常类名,用逗号隔开 throw: 只能抛出一个异常对象名

throws: 表示抛出异常,由该方法的调用者来处理 throw: 表示抛出异常,由该方法体内的语句来处理

throws: throws表示有出现异常的可能性,并不一定出现这些异常 throw: throw则是抛出了异常,执行throw一定出现了某种异常

53.说出最常见的5个RuntimeException?

java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象

java.lang.ArrayIndexOutOfBoundsException:数组下标越界异常

java.lang.ClassCastException 数据类型转换异常

java.lang.ArithmeticException:算数运算时,被除数为 0 时触发的异常

java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常

java.lang.NoSuchMethodException 方法不存在异常

java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符

java.lang.IllegalArgumentException 方法传递参数错误

54.创建对象有哪几种方式?

4 种.

  • (1)用 new 语句创建对象

  • (2)运用反射 newInstance()方法

  • (3)调用对象的 clone()方法

  • (4)运用反序列化调用 readObject()

55.数组有没有 length()这个方法? String 有没有 length()这个方法?

数组没有 length()这个方法,有 length 的属性。String 有 length()这个方法。

56.创建线程的⼏种⽅式是什么?

  • 有4种,分别是:

    继承Thread类

    实现Runnable接口

    实现Callable接口通过FutureTask包装器来创建Thread线程

    public class MyCallable implements Callable {
        @Override
        public Integer call() throws Exception {
            int a = 6;
            int b = 9;
            System.out.println("我是通过实现 Callable 接口创建的多线程,我叫" + Thread.currentThread().getName());
            return a + b;
        }
    }
    
    class TestMyCallable {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            MyCallable myCallable = new MyCallable();
            FutureTask futureTask = new FutureTask(myCallable);
            Thread thread = new Thread(futureTask);
            thread.start();
            System.out.println("返回值为:" + futureTask.get());
        }
    }

    通过线程池创建线程,使用线程池接口ExecutorService结合Callable、Future实现有返回结果的多线程。

    前面两种【无返回值】原因:通过重写run方法,run方法的返回值是void,所以没有办法返回结果。

    后面两种【有返回值】原因:通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中。

57.守护线程是什么?

守护线程是运行在后台的一种特殊进程。

它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

在 Java 中垃圾回收线程就是特殊的守护线程。

58.说说线程的五种基本状态

新建 就绪 运行 阻塞 死亡

2302 java基础面试题_第11张图片

 

59. 进程和线程的区别

进程是资源分配的最⼩单位,线程是CPU调度的最⼩单位。操作系统执⾏程序时候,按照进程分配 内存等资源,⽽执⾏程序时候以线程为单位执⾏程序中的指令。⼀个进程内部包含多个并发执⾏的线程。在 进程内部多个线程共享⼀个进程的内存资源。

进程

一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。

线程

进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。

60.并行和并发有什么区别?

串行:多个任务在一个线程上按顺序执行。由于任务都在一个线程执行所以不存在线程不安全情况,也就不存在临界区的问题。

并发:多个任务在一个 CPU 核上按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。

并行:单位时间内,多个 CPU 同时处理多个任务,是真正意义上的“同时进行”。

做一个形象的比喻:

串行 = 一个队列和一台咖啡机。

并发 = 两个队列和一台咖啡机。

并行 = 两个队列和两台咖啡机。

61.什么是多线程,多线程的优缺点?

多线程:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务。

多线程的好处:

可以提高 CPU 的利用率。在多线程程序中,一个线程必须等待的时候,CPU 可以运行其它的线程而不是等待,这样就大大提高了程序的效率。也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

多线程的劣势:

线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;

多线程需要协调和管理,所以需要 CPU 时间跟踪线程;

线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。

62.实现线程安全的两种方式

1)synchronized 方法:通过在方法声明中加入 synchronized 关键字来声明 synchronized 方 法。

2)synchronized 块:通过 synchronized 关键字来声明 synchronized 块。

63.在 Java 程序中怎么保证多线程的运行安全?

方法一:使用安全类,比如 Java. util. concurrent 下的类。

方法二:使用自动锁 synchronized。

方法三:使用手动锁 Lock。

手动锁 Java 示例代码如下:

Lock lock = new ReentrantLock();

lock. lock();

try {

  System. out. println("获得锁");

} catch (Exception e) {

  // TODO: handle exception

} finally {

  System. out. println("释放锁");

  lock. unlock();

}

64.什么是互斥锁?

互斥锁 :

当使用synchroinzed锁住多段不同的代码片段,

但是这些同步块使用的同步监视器对象是同一个时,

那么这些代码 片段之间就是互斥的。

多个线程不能同时执行他们。

65.什么是死锁,产⽣死锁的四个条件 ,如何避免死锁呢?

1.死锁的概念线程死锁:

死锁 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

也就是两个线程拥有锁的情况下,又在尝试获取对方的锁,从而造成程序一直阻塞的情况。

好比是甲同学和乙同学在打扫卫生,甲同学拿着扫帚等乙同学的簸箕,而乙同学拿着簸箕在等甲同学的扫帚

2.死锁产生的条件

        1互斥条件:同一时刻一线程只能占用一个资源。

同一时刻,甲拿着扫帚,乙拿着簸箕。

        2请求与保持:一个线程因请求资源而阻塞时,对已获得的资源保持不放。

甲在等乙的簸箕,但甲不会让出自己的扫帚

        3不可剥夺:已获得的资源在为使用完时,其他线程不能强行剥夺。

甲拿着扫帚,但是甲不能去强抢乙拿的簸箕

        4循环等待

甲拿着扫帚在等乙的簸箕,而乙拿着簸箕等甲的扫帚,形成闭环

3.如何避免死锁呢?

        打破产生条件即可

破坏互斥条件:无法被破坏,因为锁就是通过互斥来解决线程安全问题

破坏请求与保持条件:一次申请所有需要的资源

破坏不可剥夺条件:如果线程已占用部分资源,且他还要申请其他资源,如果申请不到,就主动释放它自己占有的资源

破坏循环等待条件:按照顺序申请资源,释放资源则逆序

66.为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?

new 一个 Thread,线程进入了新建状态。调用 start() 方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。

而直接执行 run() 方法,会把 run 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

总结: 调用 start 方法方可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,还是在主线程里执行。

67.sleep() 和 wait() 有什么区别

两者都可以暂停线程的执行,调用方法时都会抛出 InterruptedException 异常

类的不同:sleep() 是 Thread线程类的静态方法,wait() 是 Object类的方法。

是否释放锁:sleep() 不释放锁;wait() 释放锁。

用途不同:wait() 方法通常被用于线程间交互/通信,sleep() 通常被用于暂停线程执行。

用法不同:wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法。或者可以使用wait(long timeout)超时后线程会自动苏醒。sleep() 方法执行完成后,线程会自动苏醒。

68.同步方法和同步块,哪个是更好的选择?

同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。

请知道一条原则:同步的范围越小越好。

69. abstract 的 method 是否可同时是 static,是否可同时是 synchronized?

都不能

70.描述一下 JVM 加载 class 文件的原理机制?

JVM中类的装载是由ClassLoader和它的子类来实现的。ClassLoader是一个重要的Java 运 行时系统组件,它负责在运行时查找和装入类文件,其实质是把类文件从硬盘读取到内存中。

71.线程池有什么优点?

降低资源消耗:重用存在的线程,减少对象创建销毁的开销。

提高响应速度。可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

附加功能:提供定时执行、定期执行、单线程、并发数控制等功能。

综上所述使用线程池框架 Executor 能更好的管理线程、提供系统资源使用率。

72.线程池有⼏种?

  • Java通过Executors(JUC)提供四种线程池,分别为:

  • newCachedThreadPool 创建⼀个可缓存线程池,如果线程池⻓度超过处理需要,可灵活 回 收空闲线程,若⽆可回收,则新建线程。

  • newFixedThreadPool 创建⼀个定⻓线程池,可控制线程最⼤并发数,超出的线程会在队 列 中等待。

  • newScheduledThreadPool 创建⼀个定⻓线程池,⽀持定时及周期性任务执⾏。

  • newSingleThreadExecutor 创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执 ⾏ 任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。

73.什么是反射

JAVA反射机制是在程序运行过程中,对于任意一个类或对象,都能够知道这个类或对象的所有属性和方法,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

  • [在Java中,反射机制主要通过以下⼏个类实现:

    • Class类:表⽰类的类型,通过该类可以获取类的构造函数、成员变量、⽅法等信息。

    • Constructor类:表⽰类的构造函数类型,通过该类可以创建类的实例。

    • Field类:表⽰类的成员变量类型,通过该类可以获取、设置类的成员变量的值。

    • Method类:表⽰类的⽅法类型,通过该类可以调⽤类的⽅法。

  • 反射机制在Java中具有⼴泛的应⽤例如:

    • 动态代理:可以通过反射⽣成实现了某个接⼝的代理类,实现动态代理。

    • 依赖注⼊:可以通过反射获取类的构造函数、成员变量等信息,实现依赖注⼊

    • 注解处理器:可以通过反射获取类的注解信息,实现注解处理器。

    • 配置⽂件解析器:可以通过反射获取类的属性信息,实现配置⽂件解析器。

    • 尽管反射机制可以⽅便地获取类的信息并进⾏操作,但是它也具有⼀定的缺点,如性能较差、代 码可读性差、安全性差等。因此,在实际开发中,应该根据实际情况谨慎使⽤反射机制。

  • 获取反射对象(类对象,构造对象,方法对象,属性对象,注解对象)

    a. 通过一个全限类名创建一个对象
        1.Class.forName("全限类名"); 例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就        行了
        2.类名.class; 获取Class<?> clz 对象 
        3.对象.getClass();   

    b. 获取构造器对象,通过构造器new出一个对象 
       1). Clazz.getConstructor([String.class]); 
       2). Con.newInstance([参数]); 

    c. 通过class对象创建一个实例对象(就相当与new类名()无参构造器) 
       1). Clazz.newInstance();

    d. 通过class对象获得一个属性对象
        1.Field c=clz.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。 
        2.Field c=clz.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类        的申明字段 

    e.  通过class对象获得一个方法对象 
        1.Clazz.getMethod("方法名",class…..parameaType);(只能获取公共的) 
        2.Clazz.getDeclareMethod("方法名");(获取任意修饰的方法,不能执行私有) 
        3.M.setAccessible(true);(让私有的方法可以执行) 

    f. 让方法执行 
        1.Method.invoke(obj实例对象,obj可变参数);-----(是有返回值的) 

    g.通过反射获取注解
        1.Annotation[] annotations = Clazz.getAnnotations();

    h.获取指定注解
        1.Fieldmi fieldmi = field.getAnnotation(Fieldmi.class);

    i.判断是否为公开方法
        1.method.getModifiers()== Modifier.PUBLIC//判断是否为公开方法

74.反射机制优缺点

优点: 运行期类型的判断,动态加载类,提高代码灵活度。

缺点:性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

75.什么是回调函数?

某个程序 S(Student.main)调用服务程序 A(Arrays)中的某个方法(sort),服务程序 A 的 sort 方法在某个时候反过来调用 S 的某个方法(compareTo),这种情况下,compareTo 叫做 S 的回调 方法。

76.java 中会存在内存泄露吗?请简单描述

答:内存泄露是指系统中存在无法回收的内存,

有时候会造成内存不足或系统崩溃。Java 存在内存泄露。

Java 中的内存泄露当然是指:存在无用但是垃圾回收器无法回收的对象。

而且即使有内存泄露问题存在,也不一定会表现出来。

自己实现堆栈的数据结构时有可能会出现内存泄露。

77. TCP/UDP的区别

  • TCP 基于连接,UDP 基于⽆连接。

  • TCP 要求系统资源较多,UDP 较少。

  • UDP 程序结构较简单。

  • TCP 保证数据正确性,UDP 可能丢包。

  • TCP 保证数据顺序,UDP 不保证。

78.三次握⼿四次挥⼿

  • 三次握⼿的原⽂是 three-way handshake,整个名词的可以翻译为:需要三个步骤才能建⽴握 ⼿/连接的机制。当然,三次握⼿也可以叫 three-message handshake,通过三条消息来建⽴的握 ⼿/连接。

  • 第⼀次握⼿:客户端什么都不能确认;服务器确认了对⽅发送正常,⾃⼰接收正常

  • 第⼆次握⼿:

    • 客户端确认了:⾃⼰发送、接收正常,对⽅发送、接收正常;

    • 服务器确认了:对⽅发送正常,⾃⼰接收正常

  • 第三次握⼿(客户端发送 ACK 报⽂给服务器):

    • 客户端确认了:⾃⼰发送、接收正常,对⽅发送、接收正常;

    • 服务器确认了:⾃⼰发送、接收正常,对⽅发送、接收正常

  • TCP 连接的释放需要发送四个包(执⾏四个步骤),因此称为四次挥⼿(Four-way handshake),客户端或服务端均可主动发起挥⼿动作。 - 通俗的来说,两次挥⼿就可以释放⼀端到另⼀端的 TCP 连接,完全释放连接⼀共需要四次挥⼿。

79.OSI 的七层模型都有哪些?

2302 java基础面试题_第12张图片

80.session 和 cookie 有什么区别?

(1)存储位置不同

cookie在客户端浏览器; session在服务器;

(2)存储容量不同

cookie<=4K,一个站点最多保留20个cookie; session没有上线,出于对服务器的保护,session内不可存过多东西,并且要设置session删除机制;

(3)存储方式不同

cookie只能保存ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据; session中能存储任何类型的数据,包括并不局限于String、integer、list、map等;

(4)隐私策略不同

cookie对客户端是可见的,不安全; session存储在服务器上,安全;

(5)有效期不同

开发可以通过设置cookie的属性,达到使cookie长期有效的效果; session依赖于名为JESSIONID的cookie,而cookie JSESSIONID的过期时间默认为-1,只需关闭窗口该session就会失效,因而session达不到长期有效的效果;

(6)跨域支持上不同

cookie支持跨域; session不支持跨域;

81、说一下 session 的工作原理?

当客户端登录完成后,会在服务端产生一个session,此时服务端会将sessionid返回给客户端浏览器。客户端将sessionid储存在浏览器的cookie中,当用户再次登录时,会获得对应的sessionid,然后将sessionid发送到服务端请求登录,服务端在内存中找到对应的sessionid,完成登录,如果找不到,返回登录页面。

82.GET和POST的区别

  • GET⽅式是通过请求⾏传递⽤户所输⼊的内容,其内容会全部显⽰的浏览器的地址栏中;

  • GET提交具有⻓度限制

  • GET是从服务器上获取数据

  • GET请求没有HTTP消息体

  • POST提交将⽤户所输⼊数据放到HTTP消息体中发送到服务器端

  • POST没有提交⻓度限制 - POST是向服务器传送数据

83.http 响应码 301 和 302 代表的是什么?有什么区别?

  • 301:永久重定向;

  • 302:暂时重定向。

  • 它们的区别是,301 对搜索引擎优化(SEO)更加有利;302 有被提示为网络拦截的风险。

84.forward 和 redirect 的区别?

  • forward 是转发 和 redirect 是重定向:

  • 地址栏 url 显示:foward url 不会发生改变,redirect url 会发生改变;

  • 数据共享:forward 可以共享 request 里的数据,redirect 不能共享;

  • 效率:forward 比 redirect 效率高。

85.JDBC执行流程

public static void main(String[] args) throws Exception{
        //1.导入jar包
        //2.注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        //3.获取连接 (连接的数据库名是db2,第二个第三个参数是连接数据库的用户名密码)
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db2","root","lichee");

        //4.获取执行者对象 (statement:表现,声明,跟程序意思不匹配)
        Statement stat = conn.createStatement();

        //5.执行sql语句,并且接收结果
        String sql = "SELECT * FROM user";
        ResultSet rs = stat.executeQuery(sql); //execute执行,query:查询,resultset:结果集

        //6.处理结果
        while(rs.next()) {
            System.out.println(rs.getInt("id") + "\t" + rs.getString("name"));
        }

        //7.释放资源
        conn.close();
        stat.close();
        conn.close();
    }

86.什么是SQL注入以及如何解决?

  • 用户往传递值的地方传递进去了SQL语句导致原有SQL语句的逻辑发生改变,这个过程称为SQL 注入

  • 通过PreparedStatement对象解决SQL注入问题

  • 因为PreparedStatement对象的预编译效果是将Statement执行SQL语句时 编译SQL语句的时 间点从执行时提前到创建对象时, 在创建对象时进行编译可以在用户值传到SQL语句之前进行 编译,这样的话就可以将SQL语句业务逻辑部分锁死, 用户传递进来的内容不管是什么都以值的 形式添加到SQL语句,这样原有SQL语句的逻辑就不会被改变,从而避免SQL注入2302 java基础面试题_第13张图片

87.Statement相关内容

  • execute(sql) 执行任意SQL语句,推荐执行DDL(数据操作语言)

  • executeUpdate(sql) 执行增删改相关SQL

  • ResultSet rs = executeQuery(sql) 执行查询相关SQL语句

88.JDBC中的Statement 和PreparedStatement的区别?

PreparedStatement 继承于 Statement

Statement 一般用于执行固定的没有参数的SQL

PreparedStatement 一般用于执行有?参数预编译的SQL语句。

PreparedStatement支持?操作参数,相对于Statement更加灵活。

PreparedStatement可以防止SQL注入,安全性高于Statement。

89.什么是数据库连接池?

数据库连接池(Database Connection Pooling)在程序初始化时创建一定数量的数据库连接对象并将其保存在一块内存区中,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个

90. 什么是JDBC

JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。我们可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。

91.数据库连接池的主要优点有哪些?

1减少连接的创建时间。

2更快的系统响应速度。

3统一的连接管理。

92.hashcode是什么?有什么作用?

Java中Object有一个方法:

public native int hashcode();

(1)hashcode()方法的作用

hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。

当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,如果table中没有改hashcode值,则直接存入,如果有,就调用equals方法与新元素进行比较,相同就不存了,不同就存入。

(2)equals和hashcode的关系

如果equals为true,hashcode一定相等;

如果equals为false,hashcode不一定不相等;

如果hashcode值相等,equals不一定相等;

如果hashcode值不等,equals一定不等;

(3)重写equals方法时,一定要重写hashcode方法

(4)小白解释

1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有
例如内存中有这样的位置
0  1  2  3  4  5  6  7  
而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类的算法。
但如果用hashcode那就会使效率提高很多。
我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID%8,然后把我们的类存放在取得得余数那个位置。比如我们的ID为9,9除8的余数为1,那么我们就把该类存在1这个位置,如果ID是13,求得的余数是5,那么我们就把该类放在5这个位置。这样,以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。

2.但是如果两个类有相同的hashcode怎么办那(我们假设上面的类的ID不是唯一的),例如9除以8和17除以8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要定义 equals了。
也就是说,我们先通过 hashcode来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。
那么。重写了equals(),为什么还要重写hashCode()呢?
想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊。

93.简述 static 和 final 的用法?

static:修饰属性,方法,代码块

(1)静态属性:也可叫类变量 类名.属性名 来访问

(共有的类变量与对象无关,只和类有关)

注意:类中的实例变量是在创建对象时被初始化的,被 static 修饰的属性,也就是类变

量,是在类加载时被创建并进行初始化,类加载的过程是进行一次。也就是类变量只会被创

建一次。

(2)静态方法:类名.方法名 直接访问

注意:static 修饰的方法,不能直接访问本类中的非静态(static)成员(包括方法和属性)

本类的非静态方法可以访问本类的静态成员(包括方法和属性),可以调用静态方法。

修饰变量,方法,类

final:修饰变量,类,方法

(1)修饰变量

被 fianl 修饰的成员变量就是常量(常量名大写),一旦赋值不能改变

修饰局部变量:修饰基本数据类型 -> 变量的值不能改变

修饰引用 -> 引用只能指向固定的对象

修饰实例变量:默认值不生效,可以再赋值

(2)修饰方法 :不能被子类覆盖

(3)修饰类:不能被继承

在一个 final 类中的所有方法,默认都是 final 的

注意:final,不能用来修饰构造方法。

94.写出冒泡排序的算法

for(int i=0;iarr[j+1]){ //每次都是和它下一个元素比 
			int t=arr[j]; 
			arr[j]=arr[j+1]; 
			arr[j+1]=t;
        } 
    } 
}

95.super 与 this 的区别?

不同点:

1、super()主要是对父类构造函数的调用,this()是对重载构造函数的调用

2、super()主要是在继承了父类的子类的构造函数中使用,是在不同类中的使用;this()

主要是在同一类的不同构造函数中的使用

相同点:

1、super()和 this()都必须在构造函数的第一行进行调用,否则就是错误的

96.GC 是什么? 为什么要有 GC?

GC 是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,

忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以自

动监测对象是否超过作用域从而达到自动回收内存的目的,

Java 语言没有提供释放已分配内存的显示操作方法。Java 程序员不用担心内存管理,因为

垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc()或

Runtime.getRuntime().gc(),但 JVM 可以屏蔽掉显示的垃圾回收调用。

垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一

个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使

用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃

圾回收。

在 Java 诞生初期,垃圾回收是 Java 最大的亮点之一,因为服务器端的编程需要有效的防止

内存泄露问题,然而时过境迁,如今 Java 的垃圾回收机制已经成为被诟病的东西。移动智

能终端用户通常觉得 iOS 的系统比 Android 系统有更好的用户体验,其中一个深层次的原因

就在于 Android 系统中垃圾回收的不可预知性。

97.解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法

答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保

存都使用内存中的栈空间;而通过 new 关键字和构造器创建的对象放在堆空间;程序中的

字面量(literal)如直接书写的 100、”hello”和常量都是放在静态区中。栈空间操作起来最

快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空

间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。

98.用最有效率的方法计算 2 乘以 8?

答: 2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)。

99.谈谈 JVM 的内存结构和内存分配?

Java 内存模型

Java 虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、 Java

栈和 Java 堆。

1、方法区是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定

不会在运行时改变。常数池,源代码中的命名常量、 String 常量和 static 变量

保存在方法区。

2、 Java Stack 是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,

也可能是不连续的。最典型的 Stack 应用是方法的调用, Java 虚拟机每调用一

次方法就创建一个方法帧(frame),退出该

方法则对应的 方法帧被弹出(pop)。栈中存储的数据也是运行时确定的。

3、 Java 堆分配(heap allocation)意味着以随意的顺序,在运行时进行存储空间分

配和收回的内存管理模型。堆中存储的数据常常是大小、数量和生命期在编译时

无法确定的。 Java 对象的内存总是在 heap 中分配。

b) java 内存分配

1、基础数据类型直接在栈空间分配;

2、方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收;

3、引用数据类型,需要用 new 来创建,既在栈空间分配一个地址空间,又在

堆空间分配对象的类变量;

4、方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当

方法调用完后从栈空间回收;

5、局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周

期结束后,栈空间立刻被回收,堆空间区域等待 GC 回收;

6、方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放;

7、字符串常量在 DATA 区域分配 , this 在堆空间分配;

8、数组既在栈空间分配数组名称, 又在堆空间分配数组实际的大小。

100.什么是内存泄漏、什么是内存溢出、二者的关系:

内存泄漏memory leak :

是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出

内存溢出 out of memory :

指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。

二者的关系:

  • 内存泄漏的堆积最终会导致内存溢出

  • 内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误。

  • 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。就相当于你租了个带钥匙的柜子,你存完东西之后把柜子锁上之后,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。

  • 内存溢出:一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那我就报错。

101.九九乘法表Java代码如下

for (int i = 1; i <= 9; i++) {
			for (int j = 1; j <= i; j++) {
				System.out.print(i+"*"+j+"="+j*i+"\t");
			}
			System.out.print("\n");
		}

102.什么是单例模式

保证某个类在程序中只存在一份实例,而不会创建多个实例,这样就会提高效率。

在单利模式中一般只提供一个getInstance()方法来获取实例对象,不提供setInstance()方法,目的是为了避免再实例化出其他实例对象。

其中单例模式中有两种模式一种是饿汉模式,一种是懒汉模式。

一、饿汉模式

饿汉模式就是在类加载的时候立刻会实例化,后续使用就只会出现一份实例。

//饿汉模式
public class HungrySingle {
//在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}

多线程是否线程安全

在类加载的时候就已经实例化了,所以该实例化没有涉及到实例化的修改操作,只是进行读取操作。在多线程情况下是线程安全的。

二、懒汉模式

在类加载的时候没有直接实例化,而是调用指定实例方法的时候再进行实例化,这样就能保证不想使用的时候也不会实例化。一般来说比饿汉模式的效率高。

单线程情况下的懒汉模式

//单线程的懒汉模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }

多线程情况下的懒汉模式

在多线程的情况下,由于可能两个线程都会得到一份instance=null,这是因为如果线程1修改了自己线程中的instance后还没来得及修改主内存中的instance,所导致线程2也实例化出了一份instance对象,这时候也就不再是单例模式了。主要导致该问题的是由于这里面涉及到了对instance的修改操作,失去了原子性,为了保证原子性,我们想到了加锁,从而实现线程安全问题。

//多线程安全下的懒汉模式
public class SecurityLazyModle {
    private LazySingle() {
    }
    private static volatile SecurityLazyModle instance = null;//保证内存可见性,防止编译器过度优化(指令重排序)
    public static SecurityLazyModle getInstance() {
        if(instance == null) {
            synchronized (SecurityLazyModle.class) {
                if(instance == null) {
                    instance = new SecurityLazyModle();
                }
            }
        }
        return instance;
    }
}

                                              部分资料来源于互联网,如有侵权,请告知

你可能感兴趣的:(jvm,java,面试)