面试(一)之java基础

1. JDK 和 JRE 有什么区别?

  • JDK:Java 开发工具包,提供了 Java 的开发环境和运行环境
  • JRE:Java 运行环境,为 Java 的运行提供了所需环境。

具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。

2."==" 和 equals 的区别是什么?

"=="解读:

对于基本类型和引用类型 == 的作用效果是不同的:

  • 基本类型:比较的是值是否相同;
  • 引用类型:比较的是引用是否相同;
"equals"解读

equals 本质上就是 “==”,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较

首先来看默认情况下 equals 比较一个有相同值的对象

public class User {
	private String name;

	public User(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public static void main(String[] args) {
		User u1 = new User("zzc");
		User u2 = new User("zhangsan");
		
		System.out.println(u1.equals(u2));  // false
	}
}

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

【注意】:原来 equals 本质上就是 ==(即:User类并没有重写object类中的equals()方法)。

那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:

String s1 = new String("zzc");
String s2 = new String("zzc");
System.out.println(s1.equals(s2)); // true

同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:

	public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较

总结:== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

3.hasCode() 和 equals() 的区别是什么?

  1. 方法返回值不一样:hasCode()方法返回一个整型,表示对象的内存地址;而equals()方法返回一个boolean类型
  2. 比较的内容不一样:重写的equals()里一般比较的比较全面比较复杂(效率低);而对于hashCode()只要生成一个hash值进行比较就可以了(效率高)

那么hashCode()既然效率这么高为什么还要equals()呢?

扫描二维码关注公众号,回复: 9671323 查看本文章

        因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:

  1. equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
  2. hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。

【总结】:所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!

        这种大量的并且快速的对象对比一般使用的hash容器中,比如hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。

        然而hashCode()和equal()一样都是基本类Object里的方法,而和equal()一样,Object里hashCode()里面只是返回当前对象的地址,如果是这样的话,那么我们相同的一个类,new两个对象,由于他们在内存里的地址不同,则他们的hashCode()不同,所以这显然不是我们想要的,所以我们必须重写我们类的hashCode()方法,即一个类,在hashCode()里面返回唯一的一个hash值

        所以如果我们的对象要想放进hashSet,并且发挥hashSet的特性(即不包含一样的对象),则我们就要重写我们类的hashCode()和equal()方法了。像String,Integer等这种类内部都已经重写了这两个方法。

        当然如果我们只是平时想对比两个对象 是否一致,则只重写一个equal(),然后利用equal()去对比也行的。

哈希码

        哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况

下面给出几个常用的哈希码的算法:

  1. Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
  2. String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。
  3. Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。

4.java中,变量使用前必须进行初始化吗?

        java中有两种变量,局部变量和成员变量。局部变量使用前必须初始化,否则编译报错,成员变量可以不初始化,虚拟机会给他默认值。

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

可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。

6.switch语句能否作用在byte上,能否作用在long上?

switch语句中表达式的值必须是整型(byte、short都可以隐式转换为Int型)、字符型、字符串类型和枚举类型

7. final 在 Java 中有什么作用?

  1. final 修饰的类叫最终类,该类不能被继承
  2. final 修饰的方法不能被重写。
  3. final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

8.使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

9.静态变量和实例变量的区别

  1. 语法定义:静态变量前要加static关键字,而实例变量前则不加
  2. 程序运行时:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。

10.short s1= 1; s1 = 1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

对于short s1= 1; s1 = s1 + 1;由于s1+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s1时,编译器将报告需要强制转换类型的错误

对于short s1= 1; s1 += 1;由于 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。

11.Integer与int的区别

  1. int是java提供的8种基本数据类型之一;而Integer是java为int提供的封装类
  2. int的默认值为0,而Integer的默认值为null
  3. Integer提供了多个与整数相关的操作方法

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

  • ceil:天花板,该方法就表示向上取整。Math.ceil(11.3)的结果为12
  • floor:地板,该方法就表示向下取整,Math.floor(11.6)的结果为11
  • round:算法为Math.floor(x+0.5)

13.String属于基础的数据类型吗

String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。

14.Java 中操作字符串都有哪些类?它们之间有什么区别?

操作字符串的类有:String、StringBuffer、StringBuilder。

  • String 字符串常量:String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象
  • StringBuffer 字符串变量(线程安全)
  • StringBuilder 字符串变量(非线程安全)

【注意】:

String s1 = "hello "

String s2 = "hello " + "world"
String s3 = s1 + "word"

s2与s3不一样:s2中,jvm会对字符串拼接进行优化

15.接口与抽象类的区别

  1. 抽象类可以有构造方法,接口中不能有构造方法
  2. 抽象类中可以有普通成员变量,接口中没有普通成员变量(常量)
  3. 抽象类中可以包含非抽象的普通方法;jdk8之前,接口中的所有方法必须都是抽象的,jdk8中,出现了静态方法和默认方法
  4. 一个类可以实现多个接口,但只能继承一个抽象类。

16.抽象类必须要有抽象方法吗?

不需要,抽象类不一定非要有抽象方法。只需要给类添加关键字“abstract”即可

public abstract class Father {
	...
}

17.普通类和抽象类有哪些区别?

  • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
  • 抽象类不能直接实例化,普通类可以直接实例化。

18.抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

19.抽象的方法可以是静态的吗?

  1. 抽象类是不能实例化的,即不能被分配内存;而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:抽象类不能被分配内存,而static方法必须被分配内存。所以抽象类中不能有静态的抽象方法。
  2. 定义抽象方法的目的是重写此方法,但如果定义成静态方法就不能被重写。

20.Java 中 IO 流分为几种?

按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。

字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

21.BIO、NIO、AIO 有什么区别?

  • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

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

finally{}中的语句是一定会执行的,在return之前

23.error和exception有什么区别?

        error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。

24.Java 中,throw 和 throws 有什么区别

  • throw 用于抛出 java.lang.Throwable 类的一个实例化对象
  • hrows 的作用是作为方法声明和签名的一部分,方法被抛出相应的异常以便调用者能处理

25.java中会存在内存泄漏吗?

内存泄漏:一个不再被程序使用的对象或变量一直被占据在内存中

26.什么是反射?

在程序运行时,能够动态地访问、修改java对象本身的信息

27.什么是 Java 序列化?什么情况下需要序列化?

将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象

以下情况需要使用 Java 序列化:

  • 想把的内存中的对象状态保存到一个文件中或者数据库中时候;
  • 想用套接字在网络上传送对象的时候;
  • 想通过RMI(远程方法调用)传输对象的时候。

28.动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。

动态代理的应用有 spring aop、rpc,Java注解对象获取等。

29.怎么实现动态代理?

JDK 原生动态代理和 cglib 动态代理。JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。

30.throw 和 throws 的区别?

  • throw:是真实抛出一个异常。
  • throws:是声明可能会抛出一个异常。

31.final、finally、finalize 有什么区别?

  • final:是修饰符
  • finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但如果 finally 部分存在,则一定会执行 finally 里面的代码。
  • finalize: 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。

32.try-catch-finally 中哪个部分可以省略?

try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。

33.常见的异常类有哪些?

  • NullPointerException 空指针异常
  • ClassNotFoundException 指定类不存在
  • NumberFormatException 字符串转换为数字异常
  • IndexOutOfBoundsException 数组下标越界异常
  • ClassCastException 数据类型转换异常
  • FileNotFoundException 文件未找到异常
  • NoSuchMethodException 方法不存在异常
  • IOException IO 异常
  • SocketException Socket 异常

发布了78 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Lucky_Boy_Luck/article/details/102877685