欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java基础面试题

程序员文章站 2022-05-05 18:35:02
...

J2SE基础

面向对象是一种思想,能让复杂问题简单化,程序员不需要了解具体的实现过程,只需要使用特定对象去实现功能即可。面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用。
面向对象是相对面向过程而言
面向对象和面向过程都是一种思想
面向过程强调的是功能、行为
面向对象:将功能封装进对象,强调具备了功能的对象
面向对象是基于面向过程的

类是一组具有共同属性和行为的事物的抽象,简单理解,类就是对【事物】的一种【描述】
描述事物,则需要【属性】和【行为】
属性:事物具备的各个特征,例如->手机这个事物的特征(品牌,价格.)行为:事物能执行的操作,例如->(打电话,发短信)

对象代表客观存在的事物
类是对象的抽象(描述),对象是类的实体
在程序中需要先有类,才能创建出对象!

创建对象的四种方式:new 、 对象反序列化 、反射、 clone

一个.java文件内 只有一个public修饰的外部类

面向对象的特征

封装 最常见的是把属性私有化,封装 到一个类里面,只能通过方法去访问调用

继承 子类继承父类,从而继承了父类的方法和属性

抽象 比如一个用户类,抽象出了name,age这些属性,使得开发过程中更加易于理解

多态 多态分为操作符的多态和类的多态,类的多态指父类引用指向子类对象,并且有继承,有重写。

Java应用程序的入口函数是 main函数

常见问题
子类存在与父类相同的静态方法 叫做隐藏 不叫方法的覆盖
方法的覆盖只针对于非静态方法

接口可以继承extends接口 不可以实现implements接口
抽象类里面可以有抽象方法 也可以有带具体实现的方法

使用方式:
抽象类只能通过继承(extends)被使用
接口必须通过实现(implements)被使用
实现方式:
抽象类不仅可以提供抽象方法,也可以提供实现方法
接口只能提供抽象方法,不能提供实现方法,但是在Java8版本开始,接口可以提供实 现方法了,前提是要在方法前加上一个default修饰符

float f=0.1; 错误 正确写法 float f=0.1f;

short i=1; i=i+1;错误 因为i加1之后会自动转换成int型数据 再赋给short型的i 会报类型转换错误

short i=1; i+=1; 正确 此语句相当于i=(short)(i+1);

super关键字 可访问父类被隐藏的方法和字段

this关键字 可用于在局部方法(方法内含有与本类相同中命名相同的字段时) 访问本类中定义的字段可以使用this.字段名

this super不能和static共存 因为static是类级别的 super和this是对象级别的

引用数据类型: 类 接口 数组 引用数据类型又称之为对象类

对象都存在于堆空间内

Object ob1=new Object();
Object ob2=new Object();
ob1.equals(ob2); 返回false
因为在Object中的equals()方法本身和 == 相同 都是比较对象的内存地址
官方建议每个类都去覆写equals()方法不去比较内存地址,而去比较我们关心的数据
在String类中覆盖了equals方法 改成了比较字符串内容是否相同
String字符串 本质上是Char[]数组
toString()方法 将一个对象转换成字符串
打印对象时其实打印的就是对象的toString方法
System.out.print(ob); 等价于System.out.print(ob.toString());
默认打印对象 实际上打印的是对象的16进制HashCode值,但是我们更关心对象中存储的数据 所以官方建议每个类都去覆盖toString()方法 然后去打印我们所关心的数据

string是类类型,不是基本数据类型

基本数据类型有八种

  • 整数型:byte,short,long ,int
  • 浮点型:float,double
  • 字符型:char
  • 布尔型:boolean

int是基本数据类型,32位长度的整数
Integer是类类型,是int的封装类
int和Integer之间可以通过自动装箱,拆箱,互相转换

String和StringBuffer的区别?
String 是 immutable(不可改变的)其内容一旦创建好之后,就不可以发生改变。
StringBuffer是可以变长度的,内容也是可以发生改变的
改变的原理是StringBuffer内部采用了字符数组存放数据,在需要增加长度的时候,创建新的数组,并且把原来的数据复制到新的数组这样的方法来实现的
StringBuffer的方法是有synchronized修饰的是线程安全的类,而StringBuilder就是非线程安全的类

运行时异常与一般异常有何异同?
运行时异常又叫做非可查异常,在编译过程中,不需要必须进行显示捕捉(比如,空指针异常:NullPointerException 下标越界异常:ArrayIndexOutOfBoundsException 类找不到异常:ClassNotFoundException等)
一般异常又叫做可查异常,在编译过程中,必须进行处理,要么try catch捕捉,要么通过throws抛出去

说出ArrayList,Vector,LinkedList的存储性能和特性
先说ArrayList和Vecor
两者都继承了抽象类AbstractList,但是Vector是线程安全的(其方法是使用Synchronized修饰的),而ArrayList是非线程安全的
再说ArrayList和LinkedList
ArrayList是数组结构,所以定位很快,但是插入和删除很慢
LinkedList是双向链表结构,所以插入和删除很快,但是定位很慢

Collection和Collections的区别
Collection 是接口,是List和Set的父接口
Collections 是工具类,提供了反转(reverse)排序(sort),
混淆(shuffle)交换(swap),滚动(rotate),线程安全化(synchronizedList)等实用的方法

&和&&的区别
&:有两个作用,分别是位与,和逻辑与
&&:就是逻辑与
作为逻辑与,&和&&分别表示为长路与和短路与
长路与& 两侧都会被运算
短路与&& 只要第一个是false,第二个直接短路不在进行运算

HashMap和HashTable的区别

HashMap和HashTable都实现了Map接口,都是键值对方式保存数据
区别1:
HashMap(key和value)可以存放为null
HashTable(key和value)不可以存放为null
区别2:
HashMap不是线程安全的类
HashTable是线程安全的类

Object类里的方法?
hashCode(),toString(),finallize(),clone(),notify(),wait().
equals().

final,finally,finalize的区别
final:修饰类,方法,基本类型变量,其引用时候分别有不同的意思
修饰类 表示该类不能被继承
修饰方法 表示该方法不能被重写
修饰基本类型变量 表示该变量只能被赋值一次 数据内容不可变
修饰引用 表示该引用哦只有一次指向对象的机会 地址不可变 内容可变
修饰成员变量时 成员变量无默认值 必须为成员变量手动赋初值
finally:
适用于异常处理时,无论是否有异常抛出,表示总是执行
finalize:
finalize是Object的方法,所有类都继承了该方法。
当一个对象满足垃圾回收的条件,并且被回收的时候,其finalize()方法就会被调用

OverLoad和Override的区别,Overloaded的方法是否可以改变返回值的类型?
overload 是方法重载的意思,指的是同一个类里面,方法名一样,但是参数列表不一样
不可以通过只改变返回值类型而实现重载改方法

override 是方法重写的意思,指得是子类继承父类的某个方法后,又重写了一遍,方法名相同,参数列表相同

Error和Exception有什么区别?

Error和Exception都实现了Throwable的接口
Error指的是JVM层面上的错误,比如,内存不足,OutOfMemoryError
Exception指的是代码逻辑的异常,比如下标越界,OutOfIndexException

abstract class 抽象类和interface接口有什么区别?

使用方式:
抽象类只能通过继承(extends)被使用
接口必须通过实现(implements)被使用
实现方式:
抽象类不仅可以提供抽象方法,也可以提供实现方法
接口只能提供抽象方法,不能提供实现方法,但是在Java8版本开始,接口可以提供实现方法了,前提是要在方法前加上一个default修饰符

heap和stack有什么区别?

heap:堆
stack:栈(堆栈)
存放的内容不一样:
heap:是存放对象的
stack:是存放基本类型(int,float,boolean等等),引用(对象地址),方法调用
存取方式不一样:
heap:是自动增加大小的,所以不需要指定大小,但是存取相对较慢
stack:是固定大小的,并且是先入后出的顺序,并且存取速度比较快

GC是什么?为什么要用GC?

GC是Garbage Collection的缩写,即垃圾回收
这里所谓垃圾回收,指的是那些不再被使用的对象,JVM的垃圾回收机制释放内存资源
开发人员可以更加专注的进行业务功能的开发,而资源回收的工作交由给更加专业的垃圾回收机制自动完成。

Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math.round的意思是+0.5 取整数
所以,Math.round(11.5)即11.5+0.5=12; Math.round(-11.5)即-11.5+0.5=-11

String s = new String(‘xyz’);创建了几个String Object?

String s = new String(‘xyz’);
首先构造方法 new String(‘xyz’)中的“xyz”;这本身就是一个字符串对象
然后new关键字一定会创建一个对象,所以总共创建了两个String对象

Java有没有goto?

有,goto是关键字,但是是保留字,并不具备功能性

接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可以继承实体类(concreate class)?

接口可以继承接口,比如List就可以继承接口Collection
抽象类可以实现接口,比如 MouseAdapter鼠标监听适配器是一个抽象类,并且实现了MouseListener接口
抽象类可以继承实体类,所有抽象类,都继承了Object类

List,Set,Map是否都继承Collection接口?

List和Set继承了Collection接口
但是Map和Collection之间没有继承关系,因为一个是键值对容器,一个是单值容器,无法兼容

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

都不可以
数组有没有length()这个方法,String有没有length()这个方法?

数组获取长度:.length属性 记住这个是属性不是方法
String获取长度:length()方法
集合获取长度: size()方法
文件获取长度:length()方法

把一个字符串反转输出的方法

方法一 Stringbuffer

public static String reverse(String s) {
return new StringBuffer(s).reverse().toString();
}

public class Reverse {
//方法二:递归+字符串截取;不断的进行二分截取,递归返回;
/*
* 【时间复杂度:】渐渐跟下去就是n,n/2,n/4,…n/2^k,其中k就是循环的次数
由于你n/2^k取整后>=1
即令n/2^k=1
可得k=log2n,(是以2为底,n的对数)
所以时间复杂度可以表示O()=O(logn)
*/
public static String reverse1(String s) {
int length = s.length();
if (length <= 1)
return s;
String left = s.substring(0, length / 2);
String right = s.substring(length / 2, length);
return reverse1(right) + reverse1(left);
}

//方法三:字符串拼接
/*
* 【时间复杂度:】O()=O(n)
*/
public static String reverse2(String s) {
int length = s.length();
String reverse = “”;
for (int i = 0; i < length; i++){
reverse = s.charAt(i) + reverse;
}
return reverse;
}

Set里的元素是不能重复的,那么用什么方法来区分是否重复呢?

以HashSet为例,判断重复的逻辑是:
HashSet没有自身的实现,而是在里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复
1.首先看hashcode是否相同,如果不同,就是不重复的
2.如果hashcode一样,再比较equals,如果不同,就是不重复的,否则就是重复的

构造器Constructor是否可被override? 是否可以继承String类?

子类不能继承父类的构造方法,所以就不存在重写父类的构造方法(注:super()表示子类调用父类的构造方法,这不能叫继承父类的构造方法)
String是final修饰的,所以不能够被继承

switch是否能作用在byte上,能否作用在long上,能否作用在string上?

switch可以作用在byte,short,int,string,Enum(枚举)上,但是不能作用在long上面(注:switch 作用在String上从JDK1.7开始支持,实质是编译时将字符串替换为了其对应的hash值)

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

会执行finally里面的code Try里面的return语句是在finally执行过后才执行的

若finally里和 try里都有return语句 则只执行finally里面的return语句

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

Java规定
(1)如果两个对象相同(equals 方法返回 true),那么它们的hashCode 值一定要相同;
(2)如果两个对象的 hashCode 相同,这两个对象并不一定相同。

垃圾回收的优点和原理,并考虑两种回收机制

与C语言开发人员需要手动进行内存资源的释放不同,java提供回收机制,自动进行GC,将开发人员从容易犯错的内存资源管理中解放出来。

原理:当某一个对象,没有任何引用指向它的时候,那么它就满足垃圾回收的条件,在适当的时候,JVM虚拟机进行GC将其回收,释放空间,以供后续在利用
两种常见的回收机制:
1.定时回收
每隔30分钟进行一次回收,这种机制的弊端是如果垃圾产生的比较快,有可能30分钟之内垃圾已经把内存占用光了,导致性能变慢
2.当垃圾占到某个百分比的时候,进行回收
比如,当垃圾占到70%的时候,进行回收,这种机制的弊端是,如果垃圾产生的频率很快,那么JVM久必须高频率的进行回收,而在垃圾回收的过程中,JVM会停顿下来,只做垃圾回收,而影响业务功能的正常运行、
一般说来,JVM会采用两种机制结合的方式进行垃圾回收。

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

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

你所知道的集合类都有哪些?主要方法?
常见的集合:
ArrayList,LinkedList,HashSet,HashMap,TreeSet等等
常见方法:
size(),add(),remove()等等

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

char 是16位的,占两个字节,汉字通常使用GBK或者UNICODE编码,也是使用两个字节,所以可以存放汉字

解析XML文档有哪几种方式?

主要是两种方法,SAX和DOM,SAX就是逐行读取,直到找到目标数据为止
DOM是完全文档加载,然后读取

关键字:throws,throw,try,catch,finally,分别代表什么意义?在try块中可以抛出异常么?

throws:用在方法声明上,表示该方法有可能抛出某个异常
throw: 抛出一个指定的异常
try catch:在try中有可能会抛出某个异常,一旦某个异常抛出后,就会在catch中进行捕捉
finally:表示无论是否捕捉异常,都会执行

一个“java”源文件中是否可以包括多个类(不是内部类)?有什么限制?

可以包括多个类,但是只能出现一个public修饰的类,但是可以出现多个非public修饰的类

java中有几种类型的流?

Java中所有的流都是基于字节流,所以最基本的流是输入输出字节流
InputStream OutputStream
在字节流的基础上,封装了字符流
Reader Writer
进一步,有封装了缓存流
BufferedReader PrintWriter
以及数据流
DataInputStream
DataOutputStream
对象流
ObjectInputStream
ObjectOutputStream

java中会存在内存泄露么?请简单描述

因为Java是自动进行垃圾回收管理的,所以不存在 C语言中同等概念的内存泄漏,但是存在Java特色的内存泄漏
当某些对象不被使用,但是又有非直接引用指向的时候,那么就不满足垃圾回收的条件,而形成内存泄漏。
比如代码中的例子,每个Object创建的时候,有一个引用o指向,接着就被放进了集合al中。 下一个Object创建的时候,上一个Object就没有引用指向了。
这些Object都没有引用指向,但是却放在ArrayList中,而这个Arraylist忘记了回收,那么里面的所有对象,都会一直存活下去,虽然不再被使用了。
package j2se;

import java.util.ArrayList;

public class MemoryLeak {
static ArrayList al = new ArrayList();

public static void main(String[] args) {

    for (int i = 0; i < 100; i++) {
        Object o = new Object();
        al.add(o);
    }

}

}

java中多态的机制是什么?

父类(接口)引用指向子类对象
方法有重写

静态变量和实例变量的区别?
静态变量直接通过类就可以访问,无需实例
实例变量 比如同构类的某个具体实现,才可以访问

什么是java序列化,如何实现java 序列化?
序列化指的是把一个Java对象,通过某种介质进行传输,比如Socket输入输出流,或者保存在一个文件里,实现java序列化的手段是让该类实现接口Serializable,这个接口是一个标志性的接口,没有任何方法,仅仅用于表示该类可以序列化

是否可以从一个static方法内部发出对非static方法的调用?
不行,因为非static方法需要一个具体的实例才可以调用,而调用static方法的时候,不一定存在一个实例

在java中,如何跳出当前的多重嵌套循环?
在外部循环的前一行,加上标签 ,在break的时候使用标签,即能达到结束多重嵌套循环的效果
public class HelloWorld {
public static void main(String[] args) {

    //打印单数    
    outloop: //outloop这个标示是可以自定义的比如outloop1,ol2,out5
    for (int i = 0; i < 10; i++) {
          
        for (int j = 0; j < 10; j++) {
            System.out.println(i+":"+j);
            if(0==j%2) 
                break outloop; //如果是双数,结束外部循环
        }
          
    }
      
}

}

List,Map,Set三个接口,存取元素时,各有什么特点?
List是有顺序的,并且可以重复
Set是无序的,不可以重复
Map是键值对方式保存

Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以 implements(实现)interface(接口)?

匿名内部类本质上就是在继承其他类,实现其他接口

如例:
匿名类1,就是继承了Thread
匿名类2 ,就是实现了Runnable接口
package j2se;

public class HelloWorld {

public static void main(String[] args) {

    // 匿名类1
    new Thread() {
        public void run() {

        }
    };

    // 匿名类2
    new Runnable() {
        public void run() {

        }
    };

}

}

内部类可以引用外部类的成员么?有没有什么限制?
可以使用,如果是非静态内部类,可以使用外部类的所有成员 如果是静态内部类,只能使用外部类的静态成员

多线程有几种实现方法,都是什么?
1.继承一个Thread类
2.实现一个Runnable接口
3.匿名内部类
注:启动线程是start()方法,run()并不能启动一个新的线程

sleep()和wait()有什么区别?
首先sleep和wait之间没有任何关系
sleep是Thread类的方法,指的是当前线程暂停
wait是Object类的方法,指的是占用当前对象的线程临时释放当前对象的占用,以使得其他线程有机会占用当前对象,即线程wait()之后释放其所占的CPU资源,而sleep()不会释放当前cpu资源。所以调用wait方法一定是在synchronized 中进行的

说出数据连接池的工作机制是什么?

数据库连接池的原理:
因为创建连接和关闭连接的行为是非常耗时的,会显著降低软件的性能表现。解决办法就是先创建n条数据库连接Connection,循环使用,但是不进行关闭,这样再执行SQL语句,就不需要额外创建连接了,直接使用现成的连接就可以了,从而节约了创建连接和关闭连接的时间开销。

简述synchronized和java.util.concurrent.locks.Lock的异同?
1.Lock是一个接口,而Synchronized是java中的关键字,synchronized是内置的语言实现,Lock是代码层面的实现
2.Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃,synchronized不行,会一根筋一直获取下去,借助Lock的这个特性,就能够规避死锁。synchronized必须通过谨慎和良好的设计,才能减少死锁的发生
3.synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放,所以如果忘记了释放锁,一样会造成死锁

Class.forName的作用?为什么要用?
Class.forName常见的场景是在数据库驱动初始化时调用
Class.forName本身的意义是加载类到JVM中,一旦一个类被加载道JVM中,它的静态属性就会被初始化,在初始化的过程中就会执行相关代码,从而达到“加载驱动的效果”

当一个线程进入另一个线程的一个synchronized方法后,其他线程是够可以进入此对象的其它方法

这个要看情况而定,如果该对象的其它方法也是有synchronized修饰的,那么其他的线程会被挡在外面,否则其他线程就可以进入其他方法

给我5个你常见的runtimeexception

NullPointerException 空指针异常
ArithmeticException 算术异常,比如除数为零
ClassCastException 类型转换异常
ConcurrentModificationException 同步修改异常,遍历一个集合的时候,删除集合的元素,就会抛出该异常
IndexOutOfBoundsException 数组下标越界异常
NegativeArraySizeException 为数组分配的空间是负数异常
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 例如: Integer.parseInt(“abc”);

单例类必须满足以下两个条件:

  1. 该类的构造器必须使用private修饰;

  2. 必须实现创建对象的缓存机制

写一个单例类
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例。

Java语言中克隆针对的是类的实例

通过阅读Cloneable接口的注释,可以得知Java实现克隆需要遵循以下规则:

必须实现Cloneable接口
实现Cloneable的类应该重写clone(),重写时该方法的修饰符为public。
实际上,克隆调用的是Object类的clone()方法,clone()是一个本地方法,默认的修饰符是protected。

克隆的目的:快速创建一个已有对象的副本。

克隆的步骤:

创建一个对象
将原有对象的数据导入到新创建的数据中

public class ShadowClone implements Cloneable{

private int a;   // 基本类型
private int[] b; // 非基本类型
// 重写Object.clone()方法,并把protected改为public
@Override
public Object clone(){
    ShadowClone sc = null;
    try
    {
        sc = (ShadowClone) super.clone();
    } catch (CloneNotSupportedException e){
        e.printStackTrace();
    }
    return sc;
}
public int getA()
{
    return a;
}
public void setA(int a)
{
    this.a = a;
}
public int[] getB() {
return b;
}
public void setB(int[] b) {
this.b = b;
}  

}
Java基础面试题
不写修饰符 就默认是default

什么是线程,什么是进程,二者的关系是什么?

进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位,每一个进程都有它自己的内存空间和系统资源

线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序

进程作为资源分配的基本单位
线程作为资源调度的基本单位,是程序的执行单元,执行路径(单线程:一条执行路径,多线程:多条执行路径)。是程序使用CPU的最基本单位。

  1. 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
  2. 线程的划分尺度小于进程,使得多线程程序的并发性高。
  3. 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
  4. 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  5. 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

相关标签: JavaSE基础面试题