Java基础面试题

1.接口和抽象类的区别
1.接口中只能定义静态常量,抽象类中可以定义普通成员变量也可定义静态常量
2.JDK1.8之前接口中只有抽象方法,但JDK1.8 允许接口中有静态方法和默认方法,默认方法需要用default修饰,并可为这两类方法提供方法实现,静态方法通过接口名调用,默认方法:实现该接口的类可以根据自身需求选择性的重写默认方法(也可以不重写)。抽象类中可以含有抽象方法,也可以没有抽象方法。也可以含有普通成员发法。
3.接口中不能含有非静态代码块,抽象类中可以
4.接口中没有构造方法,抽象类可以有,抽象类中的构造方法是提供给其子类通过super关键字调用,来完成属于父类的初始化操作。
5.一个类继承一个抽象类,如果没有全部实现抽象类中的所有抽象方法,该子类也是一个抽象类不具有创建对象的功能,只有当全部实现其父类中的所有抽象方法,该类才可以创建对象。
​
应用场景
​
2.==和equals区别
== 如果两边是数字的话则比较数值,如果比较的是对象则比较的是对象的地址
​
使用equals比较事,如果使用equals的对象没有重写equals方法,则equals与==结果一样,因为在Object基类中equals方法的就是由==实现的,如果重写了equals方法则有可能比较数值或地址
3.String,StringBuffer,StringBuilder区别
String:常量,不可修改,赋值时即把数据放入常量池中
StringBuffer:多线程安全,因为在Java源代码中StringBuffer中的方法被sync....修饰,所以可以同步,但效率低
StringBuilder:多线程不安全,但效率高,推荐在单线程    情况下使用
4.重写和重载的区别
重写
    1.重写发生在继承关系中
    2.子类重写父类的方法时,如果父类的方法被private修饰,则不能被重写,即使子类中有完全相同的方法,也只是新定义了一个方法,不能称之为重写
    3.子类重写父类方法时,不能抛出比父类更多的异常(可以不抛出异常)
    4.方法返回值、方法名、方法参数相同
    5.子类不能缩小父类的访问权限
    6.被final修饰的方法不能被重写
重载
    1.发生在同一个类中
    2.方法名必须相同,参数类型、参数数量、参数位置必须不一样
    3.异常的数目、种类,不影响重载
    
5.什么叫面向对象
1.封装
2.继承
3.多态
4.抽象
6.arraylist与linkedlist区别
Arraylist
1.底层维护的是Object类型的数组,默认容量为10
2.查找快:可以根据下标,直接找到对应元素地址
3.增删慢:因为增加可能会调用grow()方法,对数组扩容,会产生大量的数据移动与拷贝 
        删除慢是因为需要将删除位置之后的数据往前移动一位,会产生大量的数据移动
Linkedlist
1.底层维护的是一个链表
2.查找慢:需要遍历链表
3.增删快:直接修改链表元素的指向
7.怎么在不使用clear()方法的情况下删除一个arraylist中所有的数据
三种
​
普通for循环倒序删除
for(int i = arraylist.size() - 1; i >= 0; i--) {
    arraylist.remove(i);
}
​
增强for循环
​
迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
   it.next()
   it.remove()//使用的是Iterator中的remove()方法,如果list.removed()会报错ConcurrentModificationException,
    }
}
8.线程和进程的区别
1、线程的基本概念
  概念:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。 
  好处:
(1)易于调度。
(2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
(3)开销少。创建线程比创建进程要快,所需开销很少。
(4)利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。
​
进程和线程的区别
(1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元
(2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程。
(3)进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束
(4)处理机分给线程,即真正在处理机上运行的是线程。因为它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的
(5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源
​
9.解释内存中的栈(stack)、堆(heap)和静态存储区的用法
堆区:专门用来保存对象的实例(new 创建的对象和数组),实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中)
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身.
3.一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
​
​
栈区:对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
4.由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.
​
​
静态区/方法区:
1.方法区又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
3.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
10.start()和run()的区别
1) start:
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
2) run:
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
​
总结:调用start方法方可启动线程,不可重复调用,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
11.sleep()和wait()的区别
调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁
方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间.因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
12.启动多线程的方式
多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有五种,分别是synchronized、wait与notify、sleep、suspend、join
synchronized: 一直持有锁,直至执行结束
wait():使一个线程处于等待状态,并且释放所持有的对象的lock,需捕获异常。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,需捕获异常,不释放锁。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
13.Java是值传递还是引用传递
Java是值传递
14.servlet的生命周期是什么样的
1.实例化   默认第一次访问时tomcat容器实例化该对象,可以在web.xml中配置<load-on-startup>,服务器启动时即实例化,在整个生命周期仅实例化一次
2.初始化   调用init()方法初始化,在整个生命周期仅初始化一次
3.就绪,服务
4.销毁    服务器关闭,调用destory()方法
15.转发与重定向的区别
1.转发页面发生跳转但路径不变,重定向页面跳转路径也随之改变
2.转发只能转发到本应用内的其他页面,重定向可以跳转本应用之外的页面
3.转发只产生一次请求,转发的多个页面共用一个request对象,重定向的多个页面产生多个请求,不是同一个request对象
4.转发性能比重定向好
16.Get与Post的区别
1.参数长度不同,get有限制,但post没有
2.参数类型不同,get只能传递ASCII编码字符,post则可以传递多种类型
3.安全性,get的数据直接拼接在url后面不安全,post的数据是放在请求体中
4.回退,get回退时无害,post回退时会再次提交请求
5.能否缓存,get可以缓存,post不能
6.性能不同,get轻量但不安全
7.使用场景不同,get用于获取数据,post用于提交数据
17.请求和响应的组成部分分别是什么
请求:
    请求行:http版本号,请求方式,路径
    请求头:键值对,cookie键值对
    空行
    请求体:存放post数据
响应:
    状态行:http版本号,状态码,状态标志
    消息报头:
    空行
    响应体:
18.Request常用方法
getRequestURL() 请求时的完整路径
getRequestURI() 请求时的完整资源名
getRemoteAddr() 获得客户端地址
getRemotePort() 获得客户端端口号
getRemoteHost() 获取客户端完整主机号
getMethod() 获取请求方式
getLocalAddr() 获得服务器地址
getRealPath()
setCharacterEncoding()
​
20.Cookie和Session的区别
1.Cookie数据存放在客户端浏览器上,Session数据存放在服务器上
2.Cookie存在长度限制和个数限制
3.本地浏览器能够阻止Cookie写入,重要数据不建议存入Cookie
4.机密数据存入Cookie时要进行加密
21.session的实现原理
浏览器发送请求
​
服务器读取请求头Cookie键值对中,是否含有JSESSIONID
​
    否:证明是当前是会话的第一次请求。服务器开辟内存空间,创建session对象,放入session集合中,因服务器中有许多session,所以为每一个session对象创建一个唯一的sessionid,session通过创建一个cookie对象,键就是"JSESSIONID"值就是sessionid,cookie存放到响应response中到达客户端浏览器,浏览器会创建cookie,键值就是JSESSIONID和sessionid
​
    是:证明本次请求不是会话的第一次请求。读取JSESSIONID对应的值,然后根据id在session集合中找到当前会话的session对象。因为session是保存在服务器上的,如果浏览器长时间不访问,那么服务器就会销毁session对象,然后在重新创建新的session对象和新的sessionid
​
22.事务的特点
1.原子性   不可分割的工作单位,要么全部成功,要么全部失败2.一致性   底层数据库的一致性,数据库的改变符合业务逻辑,一致性关注数据的可见性,中间状态的数据对外部不可见,只有最初状态和最终状态的数据对外可见3.隔离性   事务之间相互隔离,互不干涉4.持久性   事务一旦提交,对数据库产生的影响是持久的
23.String 常用方法
trim()  去掉字符串两边空格
equals() 比较两字符串是否相等
equalsIgnoreCase()
substring() 截取子字符串
split() 分割字符串返回字符串数组
indexOf() 返回指定字符在字符串中出现的第一次位置
lastIndexOf() 指定字符在字符串中最后一次出现的位置
endsWith() 判断是否已指定字符结尾
startsWith() 判断是否以指定字符开始
charAt() 获取字符串指定位置的字符
toUpperCase() 转换成大写
toLowerCase() 转换成小写
compareToIgnoreCase() 忽视大小写比较
isEmpty() 判断字符串是否为空
length() 字符串长度
replace()
 
24.重写与重载的区别
重写Override:
    在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
   1、方法名、参数、返回值相同。
​
   2、子类方法不能缩小父类方法的访问权限。
​
   3、子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)
​
   4、存在于父类和子类之间。
​
   5、方法被定义为final不能被重写。
   
   6、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
   
重载Overload:
     Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。
     1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float) 但是不能为fun(int, int));
​
     2、不能通过访问权限、返回类型、抛出的异常进行重载;
​
     3、方法的异常类型和数目不会对重载造成影响;
25. 下面代码的执行结果是什么?请解释
class Demo {
    static Demo d1 = new Demo();
    static Demo d2 = new Demo();
    {
        System.out.println("构造代码块");
    }
    
    static {
        System.out.println("静态代码块");
    }
    
    public static void main(String[] args) {
        Demo d = new Demo();
    }
}
答:
执行结果:
构造代码块
构造代码块
静态代码块
构造代码快
解释:
    构造代码块在每次创建对象时都会执行
    代码块和构造方法在创建对象时执行
    static Demo d1 = new Demo(); 创建对象,构造代码块执行一次,输出  构造代码块
    static Demo d2 = new Demo(); 创建对象,构造代码块执行一次,输出  构造代码快
    然后顺序执行
    static {
        System.out.println("静态代码块"); 静态代码块在类加载时执行,且只会执行一次,主要用于初始化静态变量,输出  静态代码块
    }
    最后执行
    public static void main(String[] args) {
        Demo d = new Demo();
    }
    创建对象,构造代码块执行一次,输出  构造代码块
​
26. static修饰的静态成员方法能不能使用成员变量?解释原因
答: 
不能使用非static修饰的成员变量,没有对象。
static修饰的静态成员方法 先于对象的创建而创建,晚于对象的销毁而销毁
可以使用static修饰的成员变量
27. abstract修饰的方法有什么特征?列出最少三条
答:
1,abstract修饰的方法 只有方法声明,没有方法体,最后应以分号结尾
2,一个子类必须完成父类中abstract修饰的方法
3,
​
1.abstract修饰类:会使这个类成为一个抽象类。
​
Ø  abstract修饰符在修饰类时必须放在类名前。
​
Ø  将不能生成对象实例,
​
Ø  可以作为对象变量声明的类型,也就是编译时类型,
​
Ø  抽象类就像当于一类的半成品,需要子类继承并覆盖其中的抽象方法。
​
2.abstract修饰方法,会使这个方法变成抽象方法。
​
Ø  也就是只有声明(定义)而没有实现,实现部分以";"代替。
​
Ø abstract修饰方法就是要求其子类覆盖(实现)这个方法。
​
解释:调用时可以以多态方式调用子类覆盖(实现)后的方法,即抽象方法必须在其子类中实现,需要子类继承实现(覆盖)。除非子类本身也是抽象类。
​
注意:
​
1,有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体方法。
​
2,父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都实现(覆盖)了,子类才有创建对 象的实例的能力,否则子类也必须是抽象类。
​
3,抽象类中可以有构造方法,是提供给子类通过super(实际参数)来完成属于抽象类的初始化操作。
​
4,final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰符
​
解释:因为abstract修饰的方法是必须在其子类中实现(覆盖),才能以多态方式调用,以上修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能够继承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方法,因为调用的是父类的方法,而父类的方法又是抽象的方法,又不能够调用,所以上的修饰符不能放在一起。
​
抽象(abstract)方法代表了某种标准,定义标准,定义功能,使用场景:
​
一:在子类中去实现功能(子类继承了父类并需要给出从父类继承的抽象方法的实现)。
二:方法一时间想不到怎么被实现,或有意要子类去实现而定义某种标准,这个方法可以被定义为抽象。(abstract)
​
抽象类要注意的细节:
1. 如果一个函数没有方法体,那么该函数必须要使用abstract修饰,把该函数修饰成抽象 的函数。。
2. 如果一个类出现了抽象的函数,那么该类也必须 使用abstract修饰。
3. 如果一个非抽象类继承了抽象类,那么必须要把抽象类的所有抽象方法全部实现。
4. 抽象类可以存在非抽象方法,也可以存在抽象的方法.
5. 抽象类可以不存在抽象方法的。 
6. 抽象类是不能创建对象的。
​
疑问:为什么抽象类不能创建对象呢?
​
因为抽象类是存在抽象方法的,如果能让抽象类创建对象的话,那么使用抽象的对象调用抽象方法是没有任何意义的。
​
7. 抽象类是存在构造函数的,其构造函数是提供给子类创建对象的时候初始化父类的属性的。
刚开始整理,内容有点乱,后期会不断添加和修改。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值