java基础面试题

1、String、StringBuffer、StringBuilder区别

1.相同点:

都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。

2.不同点

StringBuffer 线程安全,StringBuilder线程不安全!

StringBuffer

StringBuffer sb = new StringBuffer(); 

StringBuffer类创建(new StringBuffer())的字符串对象会在内存中分配一个缓冲区,当我们要对它构建的字符串对象添加字符时,会在缓冲区中进行字符的追加。若需要对字符串进行频繁的修改时,可以使用StringBuffer从而节省内存。

另外,StringBuffer实现了线程同步,可在多线程模式下使用,具有多线程安全性。

StringBuilder用法与StringBuffer相同,但是未能实现线程同步,线程不安全性,故主要使用在单线程模式下!

StringBuilder 是非线程安全。主要在单线程模式下使用,在局部变量使用效率高

3. 总结

如果是多线程的情况下使用StringBuffer和String,但是StringBuffer效率比String要高!

如果是单线程模式,StringBulder最高!

底层继承了StringBuilder和StringBuffer都继承了AbstractStringBuilder)

原因:

StringBuffer 中 append 添加了synchronized 关键字

String是一个final类,对象不可变得类,拼接字符串会产生很多对象,会浪费很多资源!

2String为什么要设置成final类型?

Final修饰的类是固定,不可变,不能被继承

1.  提高安全性

还有一个大家都知道,就是在并发场景下,多个线程同时读一个资源,是不会引发竟态条的。只有对资源做写操作才有危险。不可变对象不能被写,所以线程安全。

2. 从效率上讲

  • 设计成 final,JVM才不用对相关方法在虚函数表中查询,而直接定位到String类的相关方法上,提高了执行效率。
  • Java设计者认为共享带来的效率更高。

3、int和Integer有什么区别

  1. Integer是int的包装类,int则是java的一种基本数据类型 ;
  2. Integer变量必须实例化后才能使用,而int变量不需要 ;
  3. Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象,而int则是直接存储数据值;
  4. Integer的默认值是null,int的默认值是0;

延伸:
关于Integer和int的比较
1、由于Integer变量实际上是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远是不相等的(因为new生成的是两个对象,其内存地址不同)。

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

2、Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)

Integer i = new Integer(100);
int j = 100;
System.out.print(i == j); //true

3、非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)

Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false

4、对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false

Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

对于第4条的原因:
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:

public static Integer valueOf(int i){
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high){
        return IntegerCache.cache[i + (-IntegerCache.low)];
    }
    return new Integer(i);
}

java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了

4、JDK1.8有哪些新特性,在项目一般会哪些地方

  1. Lambda表达式;
  2. 函数式接口;
  3. 方法引用和构造器引用;
  4. Stream API;
  5. Steam (串联、并联)
  6. 接口中的默认方法与静态方法;
  7. 新时间日期API;
  8. 其他新特性。

5. ClassLoad() 和 Class.forName()区别

  1. ClassLoad 不会初始化对象

装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象;

链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)

准备:给类的静态变量分配并初始化存储空间;

解析:将常量池中的符号引用转成直接引用;

初始化:激活类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。

6、java反射原理

反射: 动态获取一个类的字节码文件对象 从而获取到对象中的所有的内容(字段 函数 构造函数等)

编译:java文件编译后生成.class字节码文件

加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例

验证:格式(class文件规范) 语义(final类是否有子类) 操作

准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。

解析:符号引用转化为直接引用,分配地址

初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。

Java的反射就是利用上面第二步加载到jvm中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。


1)获取字节码文件对象 Class

Method method = Proxy.class.getDeclaredMethod("run");

7、java中 staic 和final区别

1static

是静态修饰关键字,可以修饰变量和程序中代码以及类方法静态内部类

  1. 当定义一个 static 的变量的时候jvm在启动时会将将其分配在内存堆上,所有程序对它的引用都会指向这一个地址而不会重新分配内存;
  2. 当修饰一个程序中代码块的时候(也就是直接将代码写在static{...}中)时候,虚拟机就会优先加载静态块中代码,这主要用于系统初始化;
  3. 当修饰一个类方法时候你就可以直接通过类来调用而不需要新建对象;

Static 方法不能调用非静态方法

静态方法是属于类的,即静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存

2final

可以修饰变量、方法及类:

当定义一个final变量时,jvm会将其分配到常量池中,程序不可改变其值;

当修饰一个方法时,该方法在子类中将不能被重写;

当修饰一个类时,该类不能被继承。

1. static变量

按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量(成员变量)。两者的区别是:

对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

2. static方法

静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

8、java中重写和重载有什么区别?

1、重载(Overloading)

重载发生在本类,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关.

重载(Overload):首先是位于一个类之中或者其子类中,具有相同的方法名,但是方法的参数不同,返回值类型可以相同也可以不同。

特征

(1):方法名必须相同

(2):方法的参数列表一定不一样。

(3):访问修饰符和返回值类型可以相同也可以不同。

2、重写(Overriding)

重写发生在父类子类之间,比如所有类都是继承与Object类的,Object类中本身就有equals,hashcode,toString方法等.在任意子类中定义了重名和同样的参数列表就构成方法重写.

重写(override):一般都是表示子类和父类之间的关系,其主要的特征是:方法名相同参数相同,但是具体的实现不同。

重写的特征:

(1):方法名必须相同,返回值类型必须相同

(2):参数列表必须相同

(3):访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。

(4):子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。

(5):构造方法不能被重写,

9、java中面向对象?

封装

继承

多态

备注:对多态的理解?

10、什么是单线程模式,什么是多线程模式?

什么是单线程?
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

什么是多线程?
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


多线程的好处:
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

多线程的不利方面:
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要CPU时间跟踪线程
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
线程太多会导致控制太复杂,最终可能造成很多Bug;

12、java中==和equals的区别?

基本数据类型用==比较值相等

但是包装类型或者引用类型 new 会开盘一个新的空间,会形成新的堆内存,用==比较内存地址肯定不会相同;

1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

如果作用于引用类型的变量,则比较的是所指向的对象的地址

2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量

如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

13、抽象类和接口有什么区别?

接口(Interface)与抽象类(Abstract Class)的区别? - 简书

相同点

  1. 都不能被实例化。
  2. 接口的实现类和抽象类的子类只有全部实现了接口或者抽象类中的方法后才可以被实例化。


不同点

  1. 接口只能定义抽象方法不能实现方法,抽象类既可以定义抽象方法,也可以实现方法。
  2. 单继承,多实现。接口可以实现多个,只能继承一个抽象类。
  3. 接口强调的是功能,抽象类强调的是所属关系。
  4. 接口中的所有成员变量 为public static final, 静态不可修改,当然必须初始化。接口中的所有方法都 是public abstract 公开抽象的。而且不能有构造方法。抽象类就比较自由了,和普通的类差不多,可 以有抽象方法也可以没有,可以有正常的方法,也可以没有。

14、什么是序列化、怎么序列化、为什么序列化?

什么是序列化

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission。在默认策略下,通过 Internet 下载的代码或 Internet 代码不会授予该权限;只有本地计算机上的代码才被授予该权限。

通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。

对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码获得该权限。

为什么序列化

序列化的原因是想将对象转换成流,方便存储和在网络上传输。

java中一般将需要序列化的对象实现serializable接口。如果你想某个字段不序列化,将其声明为transient.

什么情况下会用到序列化?

  1. 当你想把内存中的对象写入到硬盘时
  2. 当你想用套接字在网络上传输对象时
  3. 当你想通过RMI调用对象时

15、java中的IO流可以划分几种类型

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

按照流的单元划分,可分为字节和字符流;

按照流的角色划分,可分为节点流和处理流,节点流即通过节点的单位量的集合,处理流即对已封装好的流进行调用处理的过程;

Java中的IO流共40多个类,其主要由InputStream/Reader、OutputStream/Write这4个抽象类基类派生出来。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值