下面25个基础面试题
(1)java中==和equals和hashCode的区别
1,==是运算符,用来比较两个值、两个对象的内存地址是否相等;
2,equals是Object类的方法,默认情况下比较两个对象是否是同一个对象,内部实现是通过“==”来实现的。
如果想比较两个对象的其他内容,则可以通过重写equals方法,
3, 例如:String类就重写了equals方法,改成了对象的内容是否相等。hashCoed也是Object类里面的方法,返回值是一个对象的哈希码,同一个对象哈希码一定相等,
但不同对象哈希码也有可能相等。
如果两个对象通过equals方法比较相等,那么他的hashCode一定相等;
如果两个对象通过equals方法比较不相等,那么他的hashCode有可能相等;
System.out.println("AaAa".hashCode());//2031744
System.out.println("BBBB".hashCode());//2031744
(2)int、char、long各占多少字节数
1.字节:byte:用来计量存储容量的一种计量单位;位:bit
2.一个字节等于8位 1byte = 8bit
char占用的是2个字节 16位,所以一个char类型的可以存储一个汉字。
整型:
byte:1个字节 8位 -128~127
short :2个字节 16位 (-2^15~2^15-1)
nt :4个字节 32位 (-2^31~2^31-1)
long:8个字节 64位 (-2^63~2^63-1)
浮点型:
float:4个字节 32 位
double :8个字节 64位
注:默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的。
char类型:
char:2个字节。
Boolean 类型:
boolean: (true or false)( 1字节 )
(3)int与integer的区别
1.Integer是int的包装类,int则是java的一种基本的数据类型;
2.Integer变量必须实例化之后才能使用,而int变量不需要实例化;
3.Integer实际是对象的引用,当new一个Integer时,实际上生成一个指针指向对象,而int则直接存储数值
4.Integer的默认值是null,而int的默认值是0。
(4)谈谈对java多态的理解
1,多态存在的三个必要条件,
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
2,多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。
实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,
由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,
computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
(5)String、StringBuffer、StringBuilder区别
(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。
(6)什么是内部类?内部类的作用
定义
在一个类里面在写定义一个类
一共分为四种: A:成员内部类 B:局部内部类 C:静态内部类D:匿名内部类
A:成员内部类
public class Outer {
private String s1 = "this is s1 in Outer";
private String s2 = "this is s2 in Outer";
public void method1() {
// 外部类可通过内部类的对象调用内部类的私有成员变量或方法
System.out.println(new Inner().s1);
System.out.println(new Inner().method2());
}
private String method2() {
return "this is method2 in Outer";
}
public class Inner {
private String s1 = "this is s1 in Inner";
public final static String s2 = "this is s2 in Inner";
public void method1() {
// 内部类可直接使用外部类的私有成员变量或方法
System.out.println(s2);
// 内部类和外部类有同名变量和方法时
System.out.println(s1);
System.out.println(Outer.this.s1);
System.out.println(method2());
System.out.println(Outer.this.method2());
}
private String method2() {
return "this is method2 in Inner";
}
}
}
(3)局部内部类是指在一个方法中定义的内部类
public class Test {
public void method() {
class Inner {
// 局部内部类
}
}
}
C:静态内部类
public class TestClass {
public static class TestClass1{
public void run(){
System.out.println("TestClass1 run");
}
}
public static class TestClass2{
public void run(){
System.out.println("TestClass2 run");
}
}
}
D,匿名内部类:匿名内部类就是没有名字的内部类
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
class TEST{
匿名类实现HelloWorld接口
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
}
作用
1.隐藏你不想让别人知道的操作,也即封装性。
2.一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!
(7)抽象类和接口区别
1,抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
2,抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型;
3,接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
4,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
(8)抽象类的意义
意义:
1,为子类提供一个公共的类型;
2,封装子类中重复内容(成员变量和方法);
3,定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。
(9)抽象类与接口的应用场景
接口(interface)的应用场合:
1,类与类之前需要特定的接口进行协调,而不在乎其如何实现。
2,作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。
3,需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。
4,需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。
抽象类(abstract class)的应用场合:
1,一句话,在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可以使用它。最常见的有:
2,定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以用abstract class定义一组方法体,甚至可以是空方法体,然后由子类选择自己所感兴趣的方法来覆盖。
3,某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。
4,规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状态来实现特定的功能
(10)抽象类是否可以没有方法和属性?
可以
(11)接口的意义
接口的作用就是把使用接口的人和实现接口的人分开,实现接口的人不必要关心谁去使用,
而使用接口的人也不用关心实现的细节。
(12)泛型中extends和super的区别
<? extends T>:是指 “上界通配符(Upper Bounds Wildcards)
<? super T>:是指 “下界通配符(Lower Bounds Wildcards)
https://www.zhihu.com/question/20400700
(13)父类的静态方法能否被子类重写,为什么?
JAVA的静态方法形式上可以重写,但是本质上不是JAVA的重写,所以答案是不能。
静态方法只与类有关,不与实例有关,重写只适用于实例方法,不适用于静态方法。
非静态方法,按重写规则,调用相应的类的实现方法,而静态方法只与类有关。
因为静态方法是程序一运行就已经分配好了内存地址,而且该地址是固定的,所有引用到该方法的对象(父类或者子类)所指向的始终是同一个内存地址中的数据,即该静态方法。如果子类定义了相同名称的静态方法,只会新增一个内存地址,并不会重写。
(14)进程与线程的区别
进程是资源分配的最小单位,线程是CPU调度的最小单位
https://www.zhihu.com/question/25532384
1,线程在进程下行进(单纯的车厢无法运行)
2,一个进程可以包含多个线程(一辆火车可以有多个车厢)
3,不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
4,同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
5,进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
6,进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
7,进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
8,进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-"互斥锁"
9,进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量”
(15)final、finally与finalize的区别
答案:https://www.cnblogs.com/ktao/p/8586966.html
扩展: https://www.cnblogs.com/fsjohnhuang/p/4040785.html
1.1 修饰类
当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰,但要注意:
final类中所有的成员方法都会隐式的定义为final方法。
1.2 修饰方法
使用final方法的原因主要有两个:
(1) 把方法锁定,以防止继承类对其进行更改。
(2) 效率,在早期的java版本中,会将final方法转为内嵌调用。但若方法过于庞大,
可能在性能上不会有多大提升。因此在最近版本中,不需要final方法进行这些优化了。
final方法意味着“最后的、最终的”含义,即此方法不能被重写。
注意:若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,
此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。
1.3 修饰变量
final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。
2. finally
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),
经常被用在需要释放资源的情况下。(×)(这句话其实存在一定的问题)
1,必须要try/catch语句块执行行了才会去执行finally。执行finally的前提是java虚拟机没有被关闭或者崩溃。
2,如果在try/cach和finally中有return语句那么最终返回的是finally里面的值。
(16)序列化的方式
答案:https://blog.csdn.net/ahuqihua/article/details/81331316
https://blog.csdn.net/u012723673/article/details/80699029
序列化和反序列化
序列化:可以将对象转化成一个字节序列,便于存储。
反序列化:将序列化的字节序列还原
优点:可以实现对象的"持久性”, 所谓持久性就是指对象的生命周期不取决于程序。
1,隐式序列化 实现Serializable接口。
通过实现Serializable接口,这种是隐式序列化(不需要手动),这种是最简单的序列化方式,
会自动序列化所有非static和 transient关键字修饰的成员变量。
class Student implements Serializable{
private String name;
private int age;
public static int QQ = 1234;
private transient String address = "CHINA";
Student(String name, int age ){
this.name = name;
this.age = age;
}
public String toString() {
return "name: " + name + "\n"
+"age: " + age + "\n"
+"QQ: " + QQ + "\n"
+ "address: " + address;
}
public void SetAge(int age) {
this.age = age;
}
public void setTransient(String address){
this.address = address;
}
}
public class Blip {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建可序列化对象
System.out.println("原来的对象:");
Student stu = new Student("Ming", 16);
System.out.println(stu);
//将序列化对象存入磁盘
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D://file.txt"));
out.writeObject(stu);
//修改相关值
Student.QQ = 6666; // 发现打印结果QQ的值被改变
stu.SetAge(18); //发现值没有被改变
stu.setTransient("RIBEN");
//从缓冲区取回被序列化的对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D://file.txt"));
Student newStu = (Student) in.readObject();
System.out.println("序列化后取出的对象:");
System.out.println(newStu);
}
}
2,显式序列化
public class Blip implements Externalizable{
private int i ;
private String s;
public Blip() {}
public Blip(String x, int a) {
System.out.println("Blip (String x, int a)");
s = x;
i = a;
}
public String toString() {
return s+i;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
System.out.println("Blip.writeExternal");
out.writeObject(s);
out.writeInt(i);
//
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
System.out.println("Blip.readExternal");
s = (String)in.readObject();
i = in.readInt();
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
System.out.println("Constructing objects");
Blip b = new Blip("A Stirng", 47);
System.out.println(b);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("D://file1.txt"));
System.out.println("保存对象");
o.writeObject(b);
o.close();
//获得对象
System.out.println("获取对象");
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D://file1.txt"));
System.out.println("Recovering b");
b = (Blip)in.readObject();
System.out.println(b);
}
}
(17)Serializable 和Parcelable 的区别
选择那个序列化方式
1,在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2,Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3,Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。
尽管Serializable效率低点, 也不提倡用,但在这种情况下,还是建议你用Serializable 。
Parcelable介绍:
1.Parcelable是android特有的序列化API,它的出现是为了解决Serializable在序列化的过程中消耗资源严重的问题,
但是因为本身使用需要手动处理序列化和反序列化过程,会与具体的代码绑定,使用较为繁琐,一般只获取内存数据的时候使用。
2.而Parcelable依赖于Parcel,Parcel的意思是包装,实现原理是在内存中建立一块共享数据块,序列化和反序列化均是操作这一块的数据,如此来实现。
(18)静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?
因为静态方法从程序开始运行后就已经分配了内存,也就是说已经写死了。
所有引用到该方法的对象(父类的对象也好子类的对象也好)
所指向的都是同一块内存中的数据,也就是该静态方法。
子类中如果定义了相同名称的静态方法,并不会重写,
而应该是在内存中又分配了一块给子类的静态方法,没有重写这一说。
(19)静态内部类的设计意图
答案:https://zhuanlan.zhihu.com/p/29623665
//www.greatytc.com/p/284b17dfce41
(20)成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用
答案:https://blog.csdn.net/JackGong1999/article/details/89644253
https://blog.csdn.net/xinzhou201/article/details/81950188
(21)谈谈对kotlin的理解
//www.greatytc.com/p/0bae35037270
(22)闭包和局部内部类的区别
局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
闭包(Closure)是一种能被调用的对象,它保存了创建它的作用域的信息。JAVA并不能显式地支持闭包,
但是在JAVA中,闭包可以通过“接口+内部类”来实现。
https://blog.csdn.net/github_37130188/article/details/94589869