Java面试题

1、Java中 == 和equals()和hashC偶的()的区别?
(1)== 是运算符,a == b 比较的是两个对象是否相等,比较的值是对象a和对象b的内存地址是否相等,== 可以用来比较对象是由于语法糖的原因。
(2)equals()是一个Object类的一个方法,默认情况比较两个对象是否是同一个对象,源码如下
public boolean equals(Object obj) { return (this == obj); }
如果想比较两个对象的其他内容,可以通过重写equals()方法,例如String类就重写了equals()方法,改成了判断对象的内容是否相等。
(3)hashCode也是Object类的一个方法,返回值是该对象的哈希值,同一个对象的哈希值一定相等,不同对象的哈希值可能相等。
(3)hashCode()与equals()的关系:在没有重写equals方法时,如果两个对象的equals()比较相等,那么这两个对象的hashCode()方法比较一定相等,如果两个对象的equals()比较不相等,那么这两个对象的hashCode()方法比较可能相等,也可能不相等。

**2、JDK和JRE的区别**

JDK(Java Development Kit):包括JRE和
javac – 编译器,将源程序转成字节码
jar – 打包工具,将相关的类文件打包成一个文件
javadoc – 文档生成器,从源码注释中提取文档
jdb – debugger,查错工具
java – 运行编译后的java程序(.class后缀的)
JRE(Java Runtime Environment):Java运行环境,包括JVM(Java虚拟机)和Java基础类库
JVM:将字节码文件转成具体系统平台的机器指令。
关系图
3、.final 在 java 中有什么作用?
final关键字可以用于三个地方。用于修饰类、类属性和类方法。
被final关键字修饰的类不能被继承;
被final关键字修饰的类属性必须在声明时进行赋值;
被final关键字修饰的 类方法不能被覆盖(重写);
final关键字不能和abstract关键字同时使用;
按照Java代码惯例,final变量就是常量,而且通常常量名要大写
将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
优点:
1、final关键字提高了性能。JVM和Java应用都会缓存final变量。
2、final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
3、使用final关键字,JVM会对方法、变量及类进行优化。

4、 Math.round(-1.5) 是多少?
实际上,Math.round()方法准确说是“四舍六入”,5要进行判断对待。
Math.round()的原理是对传入的参数+0.5之后,再向下取整得到的数就是返回的结果,返回值为long型。这里的向下取整是说取比它小的第一个整数或者和它相等的整数。

因此Math.round(-1.5)的结果是-1.5 + 0.5 再向下取整,即-1.0取整,结果是-1.
Math.round(-1.4)的结果是 -1.4 + 0.5 即-0.9 向下取整,结果是-1。
同理,Math.round(1.5)即为 1.5 + 0.5 再向下取整,结果是2

5.String 属于基础的数据类型吗?
不属于,String类型是引用数据类型。
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。

数据类型默认值占用空间取值范围
byte08位 − 2 7 − 2 7 − 1 -2^7-2^7-1 27271
short016位 − 2 15 − 2 15 − 1 -2^{15}-2^{15}-1 2152151
int032位 − 2 31 − 2 31 − 1 -2^{31}-2^{31}-1 2312311
long0L64位 − 2 63 − 2 63 − 1 -2^{63}-2^{63}-1 2632631
float0.0F32位 − 3. 4 38 − 3. 4 38 -3.4^{38}-3.4^{38} 3.4383.438
double0.0D64位 − 1.7 9 308 − 2 1 . 7 9 308 -1.79^{308}-2^1.79^{308} 1.7930821.79308
char空字符,’\u0000’16位0-65535间的整数
booleanfalse8位true \ false

java虚拟机处理基础类型与引用类型的方式是不一样的,对于基本类型,java虚拟机会为其分配数据类型实际占用的内存空间,而对于引用类型变量,他仅仅是一个指向堆区中某个实例的指针。

6、Java中的不可变类和不可变对象?
不可变类指该类的实例一旦创建完成后,就不能改变其成员变量值。如Interger、Long和String等。
优点:
1、线程安全,不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因为对象的值无法改变。可以降低并发错误的可能性,因为不需要用一些锁机制等保证内存一致性问题也减少了同步开销。
2、易于构造、使用和测试
设计原则:

  1. 类添加final修饰符,保证类不被继承。
    如果类可以被继承会破坏类的不可变性机制,只要继承类覆盖父类的方法并且继承类可以改变成员变量值,那么一旦子类以父类的形式出现时,不能保证当前类是否可变。
  2. 保证所有成员变量必须私有,并且加上final修饰
    通过这种方式保证成员变量不可改变。但只做到这一步还不够,因为如果是对象成员变量有可能再外部改变其值。所以第4点弥补这个不足。
  3. 不提供改变成员变量的方法,包括setter
    避免通过其他接口改变成员变量的值,破坏不可变特性。
    4.通过构造器初始化所有成员,进行深拷贝(deep copy)
    如果构造器传入的对象直接赋值给成员变量,还是可以通过对传入对象的修改进而导致改变内部变量的值。

7、Java中的反射机制
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码文件对象的三种方式。
  1、Class clazz1 = Class.forName(“全限定类名”);  //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
  2、Class clazz2 = Person.class // 当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
  3、Class clazz3 = p.getClass();    //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段
  有了字节码文件对象才能获得类中所有的信息
  
8、Java序列化
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。一个类要想序列化成功,该类必须实现 java.io.Serializable 对象。 当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名。
将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。

9、Object类的方法有哪些?
众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。

10、java 中操作字符串都有哪些类?它们之间有什么区别?
答:String、StringBuffer、StringBuilder

区别:String是不可变的对象,对每次对String类型的改变时都会生成一个新的对象,StringBuffer和StringBuilder是可以改变对象的。

对于操作效率:StringBuilder > StringBuffer > String

对于线程安全:StringBuffer 是线程安全,可用于多线程;StringBuilder 是非线程安全,用于单线程

不频繁的字符串操作使用 String。反之,StringBuffer 和 StringBuilder 都优于String
11、String str="i"与 String str=new String(“i”)一样吗?

答:不一样,因为他们不是同一个对象。
String str = “i”;直接将字符串常量赋值给String变量,JVM首先在常量池中查找该字符串,如果找到,则返回引用;如果未找到则在常量池中创建该字符串对象并返回引用。
String str = new String(“i”);使用String类的构造方法初始化,new关键字是在堆空间新开辟了内存,存放着字符串常量的引用。
12、字符串反转的方法

  1. 利用 StringBuffer 或 StringBuilder 的 reverse 成员方法:
public static String reverse1(String str) {
    return new StringBuilder(str).reverse().toString();
  }

2、利用 String 的 toCharArray 方法先将字符串转化为 char 类型数组,然后将各个字符进行重新拼接:

	public static String reverse2(String str) {
	    char[] chars = str.toCharArray();
	    String reverse = "";
	    for (int i = chars.length - 1; i >= 0; i--) {
	      reverse += chars[i];
	    }
	    return reverse;
	  }
  1. 利用 String 的 CharAt 方法取出字符串中的各个字符:
public static String reverse3(String str) {
	    String reverse = "";
	    int length = str.length();
	    for (int i = 0; i < length; i++) {
	      reverse = str.charAt(i) + reverse;
	    }
	    return reverse;
	  }

13、String 类的常用方法都有那些?
String类的常见方法
1、字符串与字符数组的转换

public static void main(String[] args) {
	String string = "abcdef";
	char[] c = string.toCharArray();
	for (int i = 0; i < c.length; i++) {
		System.out.println(c[i]);
	}
}

结果:

a
b
c
d
e
f

2、字符串取指定位置的字符

public static void main(String[] args) {
	String string = "abcdef";
	System.out.println(string.charAt(4));
}

结果:

e

3、字符串去空格

public static void main(String[] args) {
	String string = " abc def ";
    System.out.println(string.trim());
    System.out.println(string.strip());
}

结果:

abc def
abc def

4、字符串截取

public static void main(String[] args) {
	String string = "abcdef";
    System.out.println(string.substring(4));//从第5个开始截取
    System.out.println(string.substring(2, 5));//截取第3-5个
}

结果:

ef
cde

5、字符串拆分

public static void main(String[] args) {
	String string = "abc.def";
    String[] spilt = string.split("\\.");
    for (int i = 0; i < spilt.length; i++) {
		System.out.println(spilt[i]);
	}
}

结果:

abc
def

6、字符串大小写转换

public static void main(String[] args) {
	String string = "abCdef";
    String string2 = string.toUpperCase();
    System.out.println(string2);
    String string3 = string.toLowerCase();
    System.out.println(string3);
}

结果:

ABCDEF
abcdef

14、抽象类必须要有抽象方法吗? 
抽象类,用abstract修饰的类为抽象类;用abstract修饰的方法是抽象方法,抽象类可以不包含任何抽象方法。
15、普通类和抽象类有哪些区别?
1.抽象类不能被实例化。抽象类包含抽象方法,抽象方法只有声明,没有方法体,不能被调用。
2.抽象类可以有构造函数,被继承时子类必须继承父类一个构造方法,抽象方法不能被声明为静态。
3.抽象方法只需申明,而无需实现,抽象类中可以允许普通方法有主体
4.含有抽象方法的类必须申明为抽象类
5.抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也必须声明为抽象类。
.16、抽象类能使用 final 修饰吗?
抽象类不能被final修饰,被final修饰的类不能被继承,而抽象类必须被子类继承并实现抽象父类的所有抽象方法。
17、接口和抽象类有什么区别?
都可以作为引用数据类型

区别点接口抽象类
含义接口通常用于描述一个类的外围能力,不是核心特征抽象类定义了后代的核心特征
方法接口只提供方法声明抽象类可以提供完整方法、默认构造方法以及用于覆盖的方法声明
变量只包含public static final常量,常量必须在声明时初始化可以包含实例变量和静态变量
多实现/重继承一个类可以实现多个接口一个类只能继承一个抽象类
实现类类可以实现多个接口类只从抽象类派生
添加功能为接口添加新的方法,必须查找所有实现该接口的类,并为他们逐一提供该方法的实现为抽象类提供一个方法,可以提供一个默认的实现,那么所有已存在的代码不需要修改就可以继续工作
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值