天天看点

java常见面试题——持续更新中java常见面试题

java常见面试题

1 说说你关于常量的认识

常量是用final修饰的变量,定义的时候就要赋值,并且值不能被修改,通常在定义的时候需要大写,然后多个字母之间用下划线分割。
           

2 说说关于++ 和 --的认识

++和–分别是自增和自减运算符,通常放在整型变量前后,运算方向从左往右

m=2 m的值 表达式的值 分析
m ++ 3 2 ++在变量的后面,先参与运算,然后在进行自增运算
++m 3 3 ++在变量的前面,先进行自增运算,然后再参与运算
m– 1 2 –在变量的后面,先参与运算,然后再进行自减运算
–m 1 1 –在变量的前面,先进行自减运算,然后再参与运算

3 解释短路的概念

  1. &&短路与:全都为真才为真,一旦有假全为假,在一个短路与逻辑表达式里,如果有一个表达式为假,那么后面的所有的表达式都不参与运算,因为发生了短路,整个表达式的值为假,即false;如果是最后一个表达式是假的,则不发生短路
  2. ||短路或:有真则为真,在一个短路或逻辑表达式中,如果有一个表达式为真,那么后面的所有表达式都不参与运算,即发生了短路,整个表达式的值为真,即为true;如果是最后一个表达式是真的,则不发生短路

4 说出8大基本数据类型及其包装类

  1. 数字类型

    整数类型:byte、short、int、long(输出时需要加L,如100L)

    浮点类型:float(输出时需要加F,如3.14F)、double(浮点类型默认是double型)

  2. 字符类型:char(本身是一个整型,单输出的是一个字符,很特殊!!!输出的对应的是ASCII码)
  3. 布尔类型:boolean,输出的结果为true或者是false

    (注):string不是基本类型)

5 请说出==和equals的区别

  1. ==对于基本类型比较的是直接值,对于引用类型比较的是内存地址
  2. equals是一个方法,在字符串比较中,是比较的字符串的内容;在对象之间的比较时,根据equals方法中的逻辑的不同,得到不同的结果

== :运算符

  1. 可以使用在基本数据类型变量和引用数据类型变量中
  2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)

    如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

    补充: == 符号使用时,必须保证符号左右两边的变量类型一致。

equals()方法的使用:

  1. 是一个方法,而非运算符
  2. 只能适用于引用数据类型
  3. Object类中equals()的定义:

public boolean equals(Object obj) {

return (this == obj);

}

说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
           
  1. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是

    两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

  2. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们

    就需要对Object类中的equals()进行重写.

    重写的原则:比较两个对象的实体内容是否相同.

6 如何定义个数组,定义数组的4个关键元素是什么

定义数组:
①int[] arr = {1,2,3}; //直接赋值
②int[] arr = new int[5];//5代表数组长度
③int[] arr = new int[]{};
数组中的4个关键元素:数组类型、数组名、数组元素、元素下标
           

7 写出常见异常

数组下标越界:`ArrayIndexOutOfBoundException` 
空指针异常:`NullPointerException`
处理数字转换异常:`NumberFormatExcepthion`
           

索引越界异常:

java.lang.IndexOutOfBoundsException

数字格式异常:

java.lang.NumberFormatException

运行时异常:

RuntimeException

8 手写冒泡排序

//降序从前往后排序
    System.out.print("降序从前往后排序后的数组为:");
    for(int i = 0; i < length - 1; i ++){
    	for(int j = 0; j< length -1 -i; j ++){
    		if(nums1[j] < nums1[j + 1]){
    			int temp = nums1[j];
       		    nums1[j] = nums1[j + 1] ;
       			nums1[j + 1] = temp;
    		}
   		}
   	}
   	System.out.println(Arrays.toString(nums1));
    	
    	//降序从后往前排序
    	System.out.print("降序从后往前排序后的数组为:");
    	for(int i = 0; i < length - 1; i ++){
    		for(int j = length - 1; j < i; j ++){
    			if(nums1[j] > nums1[j - 1]){
    				int temp = nums1[j];
        		    nums1[j] = nums1[j - 1] ;
        			nums1[j - 1] = temp;
    			}
    		}
    	}
    	System.out.println(Arrays.toString(nums1));
    	
    	//升序从前往后排序
    	System.out.print("升序从前往后排序后的数组为:");
    	for(int i = 0; i < length - 1; i ++){
    		for(int j = 0; j< length -1 -i; j ++){
    			if(nums1[j] > nums1[j + 1]){
    				int temp = nums1[j];
        		    nums1[j] = nums1[j + 1] ;
        			nums1[j + 1] = temp;
    			}
    		}
    	}
    	System.out.println(Arrays.toString(nums1));
    	
    	//升序从后往前排序
    	System.out.print("升序从后往前排序后的数组为:");
    	for(int i = 0; i < length - 1; i ++){
    		for(int j = length - 1; j < i; j ++){
    			if(nums1[j] < nums1[j - 1]){
    				int temp = nums1[j];
        		    nums1[j] = nums1[j - 1] ;
        			nums1[j - 1] = temp;
    			}
    		}
    	}
    	System.out.println(Arrays.toString(nums1));	
           

9 jvm内存的5个组成部分

堆:存储被new出来的Java对象实例和数组
方法区:它用于存储已被虚拟机加载的类信息,常量,静态变量 
虚拟机栈:虚拟机栈中执行每个方法的时候,则用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
本地方法栈:本地方法栈为虚拟机使用的Native方法服务
程序计数器:指示Java虚拟机下一条需要执行的字节码指令。
           

10 简述一下面向对象你的理解

面向对象包括三大特征:封装、继承和多态
           

面向对象也就是说,对重复的东西不用多次定义,只需调用同类型的类即可。把事物的属性和行为抽象成一个类,使其属性私有化,方法(也就是行为)公开化,提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。

11 成员变量和临时变量的区别和作用域

  1. 成员变量:定义在类中,方法之外的变量,其存储在对内存的对象中,作用域是整个类
  2. 局部变量:定义在方法中或者{}语句里面的变量,其存储在栈内存的方法中,作用域是其所在的方法

12 方法的签名四要素,方法返回值的限制

签名四要素:作用域,返回值,方法名(参数列表)
           

如果方法具有返回值,方法中必须使用关键字return返回该值,返回值类型为该值的类型,返回值只能有一个,返回值类型可以是基本类型也可以是对象类型,如果方法没有返回值,返回值类型为void。

13 方法的形参和实参

  1. 形参:在定义方法的时候,在方法的参数列表中写入的叫形参
  2. 实参:在方法调用的时候,在调用方法的地方传入的参数叫实参

14 方法参数的值传递和引用传递

  1. 值传递:在基本数据类型中,传递的是变量的值,改变一个变量的值不会影响另一个变量的值
  2. 引用传递:引用数据类型(类、数组和接口,统称为引用类型),赋值是把原对象地址传递给另一个引用,其中任何一个发生改变,都会影响到其他所有的引用

15 什么是方法的重载

同一个类中,方法名相同,参数列表不同(个数或类型)与返回值、访问修饰符无关
           

16 什么是构造方法

构造方法是类的一种特殊方法,用来初始化类的一个新的对象,在创建对象之后自动调用
类中默认就有一个空参构造方法,在构造方法中只有修饰符和方法名,方法名和类名相同,有无参数列表都行
但是如果有参数列表,则在创建队形的时候就需要按照顺序给出参数对应的值
           

17 this关键字和super关键字

  1. this关键词主要用于构造方法中,指的是当前被创建的对象,用this关键字来调用当前对象的属性变量。当类中存在成员变量和局部变量同名的时候为了区分,就需要使用this关键字。
  2. super关键字主要用于代表父类的引用,用于访问父类的属性、方法和构造器

    访问父类的属性,不能访问private属性,在子类中用super.属性名

    访问父类的方法,不能访问父类的private方法,在子类中用super.方法名(参数列表)

    访问父类的构造器:super(参数列表),只能放在构造器的第一句

18 简述java中的选择结构和循环结构

选择结构有:if(){}else{}和switch选择,都用来处理多分支的结构
	if括号里为真,则执行花括号里的,如果为假,则执行else后大括号里的
	Switch选择,是等值选择,根据switch括号里的表达式值去跟case后的值进行比较来进行选择
循环结构:有while(){}、do{}while()、for循环三个循环
		都包含循环条件,循环体,可用break来跳出整个循环
		用continue来结束当前本次循环,循环变量需要初始化
           

19 什么是继承

继承发生的前提是,某一些类具有一些相同的属性和方法,我们把这些具有的相同的属性和方法抽取出来,放在同一个类中,让这些类通过extends关键字继承这个具有共同属性和方法的类,得到共有的属性和方法,这种行为,我们称之为继承。

其中继承只能继承public和protected标注的方法和属性,这样需要子类和父类在同一个包中,若继承默认权限修饰符修饰的属性和方法,子类和父类必须在同一个包中,不能继承private标注的方法和属性。当父子类有继承关系的时候,创建子类对象会自动调用父类的无参构造方法。

20 什么是封装

属性私有化,方法公开化,这样属性不会任意被改变,设置不合理的值。
属性用private来声明,用公共的get方法获取属性,用公共的set方法传值
不对外暴露的私有的方法、单例模式等等..
           

21 什么是多态

多态是同一个引用类型,使用不同的实例而执行不同的操作。即不同的子类在继承父类后分别都重写覆盖了父类的对象,即父类同一个方法,在继承的子类中表现出不同的形式。
关键点:父类引用指向子类对象
	   其中用instanceof来判断某个对象是否是某个类型
           

多态发生的条件(继承,重写,父类引用指向子类对象)

22 什么是方法的重写

1.重写方法的方法名称、参数列表必须与原方法的相同,返回类型可以相同也可以是原类型的子类型(从Java SE5开始支持)。
2.重写方法不能比原方法访问性差(即访问权限不允许缩小)。
3.重写方法不能比原方法抛出更多的异常。
4.被重写的方法不能是final类型,因为final修饰的方法是无法重写的。
5.被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
6.被重写的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足重写条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足重写条件,但是仍然不会发生重写,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。
7.重写是发生在运行时的,因为编译期编译器不知道并且没办法确定该去调用哪个方法,JVM会在代码运行的时候作出决定。
           

23 介绍一下抽象类和抽象方法,与普通类和普通方法的相同和不同

关键字abstract
           
  1. 抽象类:public abstract class 类名,和普通方法相比,有相同的属性和方法,抽象方法不同。
  2. 抽象方法:public abstract void 方法名(Pet pet),抽象方法没有方法体,抽象方法必须在抽象类中,抽象方法必须在子类中被实现,除非子类是抽象类。普通类继承抽象类必须实现抽象方法,即重写抽象方法,抽象类继承抽象类,可以重写也可以不重写。

24 介绍一下接口

接口的关键字是interface用于定义一个接口,implements,用户实现一个接口。
先继承后实现,顺序不能改变。
           

特点:接口不可以被实例化,实现类必须实现接口的所有的方法,实现类可以实现多个接口,多个接口用逗号隔开。接口中的变量都是静态常量,public static final……

25 try catch finally的执行顺序,如果catch中出现了return语句,会发生什么情况

  1. 先执行try的代码块,然后执行catch对异常进行捕获,如果有多个catch块时,其中的异常类型需要前面的是子类异常后面的是父类异常,然后按顺序逐个匹配,无论前面有没有捕获到异常,都会执行finally。
  2. 如果catch中出现了return语句,会先执行finally然后再去执行catch中的return语句。

26 list和set的区别和联系

  1. list接口存储不唯一,有序的对象,也就是可以重复,有序,list只能存储对象类型的数据,不能存储基础类型数据,可以使用加强for循环
  2. set接口存储唯一,无序的对象。也就是不能重复,无序,不能使用加强for循环

27 ArrayList和LinkList的区别

1、ArrayList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高。查询快、增删慢
2、LinkedList采用链表存储方法,插入、删除元素时效率比较高。增删快,查询慢
           

28 什么是序列化和反序列化

1、序列化:将对象某个时间的状态通过流存储起来,具体指的是过程不是结果,如果要实现序列化,必须实现Serializable

2、反序列化:反序列化则是从特定的流中获取数据重新构建对象的过程,意思是,将存储起来的序列化信息还原成对象。

29 创建线程的方法有哪些,如何启动一个线程

1、继承Thread类并且重写run(),然后在main方法中,创建线程对象,调用线程对象的

//start方法来启动一个线程
//创建线程类对象:
MyThread thread2 =new MyThread();
//调用线程对象的start方法:  
a.start( )
           

2、实现Runnable接口,在类中覆盖Runnable接口中的run方法,在main方法中,创建此类的对象然后再创建线程对象,并且以此类对象作为线程对象中的参数传入进去,也是用线程对象调用start()方法来启动线程。

//创建MyRunnable对象
MyRunnable thread = new MyRunnable();
//创建当前类对象
Student student = new Student();
//创建线程类对象 
Thread  t  =  new Thread(student );
//调用线程对象的start方法:       
t.start( )  
           

30 说说你关于进程和线程的认识

  1. 进程:应用程序的执行实例,每一个进程都有自己的地址空间,即进程是资源分配的最小单位。
  2. 线程:CPU调度和分派的基本单位,是操作系统能够进行运算调度的最小单位,可完成一个独立的顺序控制流程,其中一个进程中可以并发多个线程。

31 什么是多线程

多线程:如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”。多个线程交替占用CPU资源,而非真正的并行执行,线程每次执行时长由分配的CPU时间片长度决定。

多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。多线程是在同一时间需要完成多项任务的时候实现的。

32 线程运行的5个状态,简单论述他们之间的关系

创建状态:创建线程对象
就绪状态:启动线程
运行状态:抢到了cpu资源
阻塞状态:没有抢到cpu资源(join或者sleep)
死亡状态:程序正常结束或者外部干涉终止
           

关系:

1、正常情况下是没有发生意外,创建线程后,进入就绪状态启动线程,然后开始抢占CPU资源,抢到了则进行运行状态,运行结束则进入死亡状态。

2、另一种情况则是没有抢到CPU资源或者是程序进入了休眠则进入阻塞状态,当阻塞状态解除后,则继续抢占CPU资源,抢到了就继续运行,运行结束后则进入死亡状态。

33 创建对象的三种方式

  1. new关键字创建对象
  1. 通过调用类的newInstance方法可以创建对象(反射的方法)
  1. 对象流的方式输入

34 sleep,yield为什么是静态方法

Tread类的sleep()和yield()将在当前正在执行的线程上运行,主要针对当前线程进行操作,在其他处于等待状态的线程上调用这些方法是没有意义的。可以在当前正在执行的线程中工作,并且避免我们会错误的认为其可以在其他非运行线程调用这些方法。

35 谈谈对索引的认识

索引主要分为主键索引,唯一索引,常规索引,全文索引。建立索引主要是为了加快查询速度,同时有索引也可以对数据库进行优化,提高系统的性能。但是不要对经常变动的数据加索引,比如我们人的身份证号是唯一标识我们的,不会随意变动,所以可以作为索引,此外小数据量的表建议不要加索引。对于一张表中有很多个字段,可以把一张表分为两张或多张表,通过给各个表加索引来关联各个表,如果表很多,甚至可以把一个数据库分为多个数据库。

36 什么是事务,事务的acid原则

事务就是一个完整的增删改查的行为,完成的多个增删改查统称为一个事务

事务的acid原则:

原子性:是指一个事务要么全部执行,要么不执行。

一致性:事务的运行,如果改变了数据库中的一个数据,那么其他数据也随之改变。

独立性:两个或者多个事务均是独立执行的,不会交叉执行,彼此互不影响。

持久性:一个事务执行成功以后,对数据库中的数据的更改所保存的数据是具有持久性,不会无缘无故回滚。

37 如何优化数据库

优化数据库主要是通过给数据库加索引来实现的,给不经常更改的字段添加索引更有助于数据的查询,此外小数据量的数据表不建议加索引。对于一张表中有很多个字段,可以把一张表分为两张或多张表,通过给各个表加索引来关联各个表,如果表很多,甚至可以把一个数据库分为多个数据库。这样分表分库更有助于数据的查询。

38 session和cookie的区别

不同点:

cookie可以设置作用域,该作用域向下兼容,session作用域是整个服务器

cookie在浏览器中使用,session在服务器中使用

cookie存储的信息较少,session存储的信息较多

相同点:都可以存储出数据,都可以确认使用范围,都可以设置生命周期

39 转发和重定向的区别

答:转发的实现通过request.getRequestDispatcher(“login.jsp”).forward(request, response)实现的

重定向的实现是通过response.sendRedirect(“url”),将用户请求重新定位到一个新的URL,重定向会丢失原来存在request中数据

二者的区别是:转发URL不会变化,重定向则是湖重新定位到一个新的URL中;转发则是会携带当前发出的请求,不会重新发出请求,而重定向则是丢弃了当前的请求,重新发出一个请求;转发只适用本Web应用下,重定向可以适用于任意URL。

40 request和session的相同和不同

答:相同点:都可以存储属性

不同点:request中存储的数据仅在一个请求中可用,session中存储的数据在一个会话的有效期内可用。

41 servlet的定义

答:servlet是一个框架,是为了解决java程序的通信问题,用java语言写的一堆程序的集合,servlet提供了很多可以在网络调用的接口,这些能调用的接口被称为api,api本质是方法,他可以传参,可以有返回值;如果放在网络上,那么参数可以在网络提供,返回值可以在网络上获得,实现网络通信

42 简述servlet的生命周期

答:1.加载和实例化:当Servlet容器启动或者容器检测到客户端请求时

2.初始化:实例化后,容器调用Servlet的init()初始化对象

3.处理请求:得到客户端请求并做出处理时

4.销毁:当程序中的Servlet对象不再使用的时候,或者Web服务器停止运行的时候

43 什么是单例模式,如何实现单例模式,懒汉模式/饿汉模式

答: 单例模式:系统运行期间,有且仅有一个实例,就叫单例模式。其中只提供私有构造器,定义静态的该类私有对象,必须自行向整个系统提供这个实例,提供一个静态的公有方法,返回创建或者获取本身的静态私有对象。

懒汉模式:在类加载时不创建实例,采用延迟加载的方式,在运行调用时才创建实例,类加载的较快,但获取对象速度较慢。懒汉模式会导致线程不安全,解决同步安全问题。

饿汉模式:在类加载的时候,就完成初始化,所以类加载的较慢,但获取对象速度较快。饿汉模式线程安全,不具备延迟加载特性。

44 请介绍mybatis的一级缓存和二级缓存

答:一级缓存:Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。除非sql改变。

二级缓存:当会话被关闭的时候,这个会话对应的一级缓存被清除;但当我们开启二级缓存的时候,这个缓存会被存入二级缓存中。新的会话查询信息,可以从二级缓存中获取内容。不同的mapper查询的数据会放在自己对应的mapper中。

45 请介绍mybatis如何设置延迟加载,延迟加载的效果是什么

答:在config.xml中配置

<settings>
        <setting name="lazyLoadingEnabled" value="true"/>
 </settings>
           

延迟加载的效果:可以不访问某些数据表,尽量减少 SQL 的执行,从而达到提高速度的目的。