面试专题之Java基础(四)

题目

  1. 类和对象的区别?
  2. 讲讲 static 关键字和 final 关键字
  3. BIO、NIO、AIO 区别有哪些?项目中有用到吗?Netty 了解吗?
  4. Object 类下有哪些方法?
  5. 字符串"123"转换成整型123的API是什么?整型123转换成字符串“123”的 API 又是什么?
  6. 存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为C 么?如 C = (C) B
  7. 哪个类包含 clone 方法?是 Cloneable 还是 Object?
  8. Java 中 ++ 操作符是线程安全的吗?
  9. a = a + b 与 a += b 的区别
  10. 我能在不进行强制转换的情况下将一个 double 值赋值给long 类型的变量吗?
  11. 3*0.1 == 0.3 将会返回什么?true 还是 false?
  12. int 和 Integer 哪个会占用更多的内存?
  13. 为什么 Java 中的 String 是不可变的(Immutable)?
  14. 我们能在 Switch 中使用 String 吗?
  15. Java 中的构造器链是什么?
  16. a==b”和”a.equals(b)”有什么区别?
  17. a.hashCode() 有什么用?与 a.equals(b) 有什么关系?
  18. final、finalize 和 finally 的不同之处?
  19. Java 中的编译期常量是什么?使用它又什么风险?
  20. 说出几条 Java 中方法重载的最佳实践?
  21. 在多线程环境下,SimpleDateFormat 是线程安全的吗?
  22. Java 中如何格式化一个日期?如格式化为 ddMMyyyy的形式?
  23. Java 中,怎么在格式化的日期中显示时区?
  24. Java 中 java.util.Date 与 java.sql.Date 有什么区别?
  25. Java 中,如何计算两个日期之间的差距?
  26. Java 中,如何将字符串 YYYYMMDD 转换为日期?
  27. 如何测试静态方法?
  28. 怎么利用 JUnit 来测试一个方法的异常?
  29. 你使用过哪个单元测试库来测试你的 Java 程序?
  30. @Before 和 @BeforeClass 有什么区别?
  31. 怎么检查一个字符串只包含数字?解决方案
  32. Java 中如何利用泛型写一个 LRU 缓存?
  33. 写一段 Java 程序将 byte 转换为 long?
  34. 在不使用 StringBuffer 的前提下,怎么反转一个字符串?
  35. 如何检查出两个给定的字符串是反序的?
  36. 接口是什么?为什么要使用接口而不是直接使用具体类?

答案

  1. 类和对象的区别?
    (1)定义不同
    类是现实世界或思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。
    对象是具有类类型的变量。类和对象是面向对象编程技术中的最基本的概念。
    (2)范畴不同
    类是一个抽象的概念,它不存在于现实中的时间、空间里,类知识为所有的对象定义了抽象的属性与行为。
    对象是类的一个具体。它是一个实实在在存在的东西。
    (3)状态不同
    类是一个静态的概念,类本身不携带任何数据。当没有为类创建任何数据时,类本身不存在于内存空间
    对象是一个动态的概念,每一个对象都存在着有别于其它对象的属于自己的独特的属性和行为,属性可以随着它自己的行为而发生改变。

  2. 讲讲 static 关键字和 final 关键字

final:
final可以修饰:属性,方法,类,局部变量(方法中的变量)
final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变。
final修饰的属性跟具体对象有关,在运行期初始化的final属性,不同对象可以有不同的值。
final修饰的属性表明是一个常数(创建后不能被修改)。
final修饰的方法表示该方法在子类中不能被重写,final修饰的类表示该类不能被继承。
对于基本类型数据,final会将值变为一个常数(创建后不能被修改);但是对于对象句柄(亦可称作引用或者指针),final会将句柄变为一个常数(进行声明时,必须将句柄初始化到一个具体的对象。而且不能再将句柄指向另一个对象。但是,对象的本身是可以修改的。这一限制也适用于数组,数组也属于对象,数组本身也是可以修改的。方法参数中的final句柄,意味着在该方法内部,我们不能改变参数句柄指向的实际东西,也就是说在方法内部不能给形参句柄再另外赋值)。

static:
static可以修饰:属性,方法,代码段,内部类(静态内部类或嵌套内部类)
static修饰的属性的初始化在编译期(类加载的时候),初始化后能改变。
static修饰的属性所有对象都只有一个值。
static修饰的属性强调它们只有一个。
static修饰的属性、方法、代码段跟该类的具体对象无关,不创建对象也能调用static修饰的属性、方法等
static和“this、super”势不两立,static跟具体对象无关,而this、super正好跟具体对象有关。
static不可以修饰局部变量。

  1. BIO、NIO、AIO 区别有哪些?项目中有用到吗?Netty 了解吗?
    在这里插入图片描述
    Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性,有了netty NIO编程更为简便。
    分布式开源框架中dubbo、Zookeeper,RocketMQ底层rpc通讯使用就是netty。游戏开发中,底层使用netty通讯。

推荐阅读:本人的NIO和Netty专栏

  1. Object 类下有哪些方法?
registerNatives() //私有方法
getClass() //返回此 Object 的运行类。
hashCode() //用于获取对象的哈希值。
equals(Object obj) //用于确认两个对象是否“相同”。
clone() //创建并返回此对象的一个副本。
toString() //返回该对象的字符串表示。
notify() //唤醒在此对象监视器上等待的单个线程。
notifyAll() //唤醒在此对象监视器上等待的所有线程。
wait(long timeout) //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或 者超过指定的时间量前,导致当前线程等待。
wait(long timeout, int nanos) //在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
wait() //用于让当前线程失去操作权限,当前线程进入等待序列
finalize() //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
  1. 字符串"123"转换成整型123的API是什么?整型123转换成字符串“123”的 API 又是什么?

前者有两种方法

String s = "123";
int i = Integer.parseInt(s); 
int i = Integer.valueOf(s).intValue();

后者有三种方法

Integer i = 123;
String s = String.valueOf(i);
String s = Integer.toString(i);
String s = "" + i;
  1. 存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为C 么?如 C = (C) B

这属于强制类型转换,如果被转换的B实例不是C类型,会有异常
比如你的ABC分别对应动物,猫,黑猫。
向上转型就是比如

C c = new C();
B b = c;

你把c转型为B,黑猫是猫吗?是啊,所以这是ok的。
但是反过来

B b = new B();
C c = (C)b;

这就不ok了,只知道这个b是一只猫,他不一定是黑猫。
但如果这个b已经确定是一只黑猫了,那就可以转型了

B b = new C();
C c = (C)b;

这里的b本来就是黑猫啊。

  1. 哪个类包含 clone 方法?是 Cloneable 还是 Object?
    java.lang.Cloneable 是一个标示性接口,不包含任何方法,clone 方法在object 类中定义。并且需要知道 clone() 方法是一个本地方法,这意味着它是由c 或 c++ 或 其他本地语言实现的。

  2. Java 中 ++ 操作符是线程安全的吗?
    不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。

  3. a = a + b 与 a += b 的区别
    += 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。如果加法操作的结果比 a 的最大值要大,则 a+b 会出现编译错误,但是

byte a = 127;byte b = 127;
b = a + b;// error : cannot convert from int to byte
b += a;// ok

(译者注:这个地方应该表述的有误,其实无论 a+b 的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte就会编译出错)

  1. 我能在不进行强制转换的情况下将一个 double 值赋值给long 类型的变量吗?
    不行,你不能在没有强制类型转换的前提下将一个 double 值赋值给 long 类型的变量,因为 double 类型的范围比 long 类型更广,所以必须要进行强制转换。

  2. 3*0.1 == 0.3 将会返回什么?true 还是 false?
    false,因为有些浮点数不能完全精确的表示出来。

  3. int 和 Integer 哪个会占用更多的内存?
    Integer 对象会占用更多的内存。Integer 是一个对象,需要存储对象的元数据。但是 int 是一个原始类型的数据,所以占用的空间更少。

  4. 为什么 Java 中的 String 是不可变的(Immutable)?
    Java 中的 String 不可变是因为 Java 的设计者认为字符串使用非常频繁,将字符串设置为不可变可以允许多个客户端之间共享相同的字符串。

  5. 我们能在 Switch 中使用 String 吗?
    从 Java 7 开始,我们可以在 switch case 中使用字符串,但这仅仅是一个语法糖。内部实现在 switch 中使用字符串的 hash code。

  6. Java 中的构造器链是什么?
    当你从一个构造器中调用另一个构造器,就是 Java 中的构造器链。这种情况只在重载了类的构造器的时候才会出现。

  7. a==b”和”a.equals(b)”有什么区别?
    如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。

  8. a.hashCode() 有什么用?与 a.equals(b) 有什么关系?
    hashCode() 方法是相应对象整型的 hash 值。它常用于基于 hash 的集合类,如 Hashtable、HashMap、LinkedHashMap 等等。它与 equals() 方法关系特别紧密。根据 Java 规范,两个使用 equal() 方法来判断相等的对象,必须具有相同的 hash code。

  9. final、finalize 和 finally 的不同之处?
    final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。finally是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。

  10. Java 中的编译期常量是什么?使用它又什么风险?
    公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。
    这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的 jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。
    推荐阅读:Java 中的编译期常量是什么?使用它有什么风险?

  11. 说出几条 Java 中方法重载的最佳实践?
    下面有几条可以遵循的方法重载的最佳实践来避免造成自动装箱的混乱。
    a)不要重载这样的方法:一个方法接收 int 参数,而另个方法接收 Integer 参数。
    b)不要重载参数数量一致,而只是参数顺序不同的方法。
    c)如果重载的方法参数个数多于 5 个,采用可变参数。

  12. 在多线程环境下,SimpleDateFormat 是线程安全的吗?
    不是,非常不幸,DateFormat 的所有实现,包括 SimpleDateFormat 都不是线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如 将 SimpleDateFormat 限制在ThreadLocal 中。如果你不这么做,在解析或者格式化日期的时候,可能会获取到一个不正确的结果。因此,从日期、时间处理的所有实践来说,我强力推荐 joda-time 库。

  13. Java 中如何格式化一个日期?如格式化为 ddMMyyyy的形式?
    Java 中,可以使用 SimpleDateFormat 类或者 joda-time 库来格式日期。
    推荐阅读Java日期格式化

  14. Java 中,怎么在格式化的日期中显示时区?
    使用SimpleDateFormat来实现格式化日期,但是DateFormat 的所有实现,包括 SimpleDateFormat 都不是线程安全的,因此你不应该在多线程序中使用,除非是在对外线程安全的环境中使用,如将SimpleDateFormat 限制在 ThreadLocal 中。如果你不这么做,在解析或者格式化日期的时候,可能会获取到一个不正确的结果。因此,从日期、时间处理的所有实践来说,强力推荐 joda-time 库。

  15. Java 中 java.util.Date 与 java.sql.Date 有什么区别?
    java.sql.Date 是针对 SQL 语句使用的,它只包含日期而没有时间部分,一般在读写数据库时用。
    java.util.Date 是在除了 SQL 语句外的所有情况下使用的,一般是日常日期字段。java.util.Date 是 java.sql.Date 的父类。唯一的相同点就是都有 getTime 方法返回毫秒数。代码解释所示:

public class DateShow {
    public static void main(String[] args) {
        java.util.Date nowUtil = new java.util.Date();
        java.sql.Date nowSql = new java.sql.Date(System.currentTimeMillis());

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(nowUtil));
        System.out.println(format.format(nowSql));
        System.out.println(nowUtil);
        System.out.println(nowSql);
    }
}

运行结果如下:

 2018-06-08 17:33:06
 2018-06-08 17:33:06
 Fri Jun 08 17:33:06 CST 2018
 2018-06-08

之所以直接打印 Date 对象表现的值不一样就是上面解释的部分,是指是调用了各自 Date 的 toString() 方法,两个 Date 对象分别有自己的 toString() 重写实现

  1. Java 中,如何计算两个日期之间的差距?
public static String getDatePoor(Date endDate, Date nowDate) {
    long day = 1000 * 24 * 60 * 60;
    long hour = 1000 * 60 * 60;
    long minute = 1000 * 60;
    // long second= 1000;
    // 获得两个时间的毫秒时间差异
    long diff = endDate.getTime() - nowDate.getTime();
    // 计算差多少天
    long day = diff/day;
    // 计算差多少小时
    long hour = diff % day / hour;
    // 计算差多少分钟
    long min = diff % day % hour / minute;
    // 计算差多少秒//输出结果
    // long sec = diff % day % hour %  minute / second;
    return day + "天" + hour + "小时" + min + "分钟";
}
  1. Java 中,如何将字符串 YYYYMMDD 转换为日期?
Date date = new SimpleDateFormate("yyyyMMdd").parse(你的字符串);
String dateStr = new SimpleDateFormate("yyyy-MM-dd").formate(date);
  1. 如何测试静态方法?
    可以使用 PowerMock 库来测试静态方法。

  2. 怎么利用 JUnit 来测试一个方法的异常?
    利用try - fail - catch,当没有异常被抛出的时候fail方法会被调用,输出测试失败的信息。

@Test
public voidtestExceptionMessage() {
      try {
          new ArrayList<Object>().get(0);
          fail("Expected an IndexOutOfBoundsException to be thrown");
      } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
          assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
      }  
}

推荐阅读JUnit中测试异常抛出的方法

  1. 你使用过哪个单元测试库来测试你的 Java 程序?

  2. @Before 和 @BeforeClass 有什么区别?
    @Before :在每个测试方法之前都执行一次, 方法需要声明为public
    @beforeclass :只在类中执行一次, 必须声明为public static

  3. 怎么检查一个字符串只包含数字?解决方案
    用Java自带的函数、用正则表达式、用ascii码判断

  4. Java 中如何利用泛型写一个 LRU 缓存?
    这是一种混合的数据结构,我们需要在哈希表的基础上建立一个链表。但是Java已经为我们提供了这种形式的数据结构-LinkedHashMap!它甚至提供可覆盖回收策略的方法。唯一需要我们注意的事情是,改链表的顺序是插入的顺序,而不是访问的顺序。但是,有一个构造函数提供了一个选项,可以使用访问的顺序。

  5. 写一段 Java 程序将 byte 转换为 long?
    可参考

  6. 在不使用 StringBuffer 的前提下,怎么反转一个字符串?
    使用递归

public static String reverseStr(String s) {
    if (s == null || s.length() <= 1) {
        return s;
    }
    return reverseStr(s.substring(1)) + s.charAt(0);
}

参考【面试题】求一个字符串的反转字符串

  1. 如何检查出两个给定的字符串是反序的?
    思路主要是,从开始字符,和另外一个从末尾字符比较,先判断长度是否相同,不同直接不可能反文。然后再比较。

  2. 接口是什么?为什么要使用接口而不是直接使用具体类?
    接口用于定义 API。它定义了类必须得遵循的规则。同时,它提供了一种抽象,因为客户端只使用接口,这样可以有多重实现,如 List 接口,你可以使用可随机访问的 ArrayList,也可以使用方便插入和删除的 LinkedList。接口中不允许写代码,以此来保证抽象,但是 Java 8 中你可以在接口声明静态的默认方法,这种方法是具体的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值