1、面向对象和面向过程对比

  • 面向对象需要实例化,因此需要调度资源,开销大影响性能,但是它的封装、继承、多态三个特性使它易维护、易复用、易扩展。面向过程性能较优,适合看中性能的开发,比如单片式和嵌入式开发,比较注重性能。
  • 注:解释性面向过程语言不一定比面向对象性能好,java语言性能低的原因还有他是半解释半编译型语言。

2、Java和c++比较

  • java不提供指针直接访问内存,内存操作由jvm来执行,并且会有gc线程帮忙管理内存,gc会自动申请释放内存,不需要程序员手动释放,c++需要程序员主动申请和释放。
  • java类只能单继承,接口可以多继承,这样可以让类结构层次更清晰,c++支持多继承。

3、字符常量和字符串常量的区别

  • 字符常量是ascll码值,可以参与运算,字符串常量是个地址值。
  • java中字符占2个字节,c++占1个字节,字符串根据具体长度计算。

4、重载、重写重定义

  • 父类的私有属性和构造方法只能被重载不能重写。
  • 重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。   
  • 重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
  • 重定义:发生在父子类中,方法名相同,返回值可以不同,参数列表可以相同(不能有Override解释)。

5、Java中的多态

5.1 Java实现多态有三个必要条件:继承、重写、向上转型。

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

5.2 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

在了解java多态特性的时候,必须要了解到向上转型和向下转型,在继承中,我们可以通过子类去实例化父类或者使用父类去实例化子类,这样可以达到多态的效果,下面对向上转型和向下转型操作做一个详细解释。

  • 向上转型:通过子类对象(小范围)实例化父类对象(大范围),这种属于自动转换,向上转型时,父类只能调用父类方法或者子类覆写后的方法,而子类中的单独方法则是无法调用的。
  • 向下转型:通过父类对象(大范围)实例化子类对象(小范围),这种属于强制转换,在java中向下转型则是为了,通过父类强制转换为子类,从而来调用子类独有的方法(向下转型,在工程中很少用到)。为了保证向下转型的顺利完成,在java中提供了一个关键字:instanceof,通过instanceof可以判断某对象是否是某类的实例,如果是则返回true,否则为false。
    5.3 编译时多态和运行时多态
    对于面向对象语言,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编译之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

6、final关键字主要用在三个地方:变量、方法、类。

  • 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
  • 当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。
  • 使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为final。

7、hashCode()与equals()的相关规定

  • 如果两个对象相等,则hashcode一定也是相同的
  • 两个对象相等,对两个对象分别调用equals方法都返回true
  • 两个对象有相同的hashcode值,它们也不一定是相等的
  • 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  • hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

8、== 与 equals(重要)

  • ==: 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。
  • equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
    情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
    情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

9、Java异常与错误

java中异常和错误都是Throwable的子类,其中error无法被程序本身处理,exception可以被程序本身进行处理。

9.1 Throwable类常用方法:
  • public string getMessage():返回异常发生时的简要描述
  • public string toString():返回异常发生时的详细信息
  • public string getLocalizedMessage():返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
  • public void printStackTrace():在控制台上打印Throwable对象封装的异常信息
    9.2 finally执行注意点:
  • 在finally语句块第一行发生了异常。 因为在其他行,finally块还是会得到执行
  • 在前面的代码中用了System.exit(int)已退出程序。 exit是带参函数 ;若该语句在异常语句之后,finally会执行
  • 程序所在的线程死亡。
  • 关闭CPU。
  • 当try语句和finally语句中都有return语句时,在方法返回之前,finally语句的内容将被执行,并且finally语句的返回值将会覆盖原始的返回值。

10、获取用键盘输入常用的两种方法

方法1:通过 Scanner

1
2
3
   Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();

方法2:通过 BufferedReader

1
2
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));   
String s = input.readLine();

11、Java中的IO流

  • java io流主要4个抽象类:InputStream(字节输入流)、Reader(字符输入流) 、OutputStream(字节输出流)、Writer(字符输出流)。

  • java io流按照流的方向可以分为输入流和输出流。

  • java io流按照操作单元可以分为字节流和字符流

  • 字符流是通过java虚拟机转换得到的,转换过程比较耗时,而且在未知编码类型传输时使用字节流容易出现乱码现象,所以提供了字符流。

  • 按操作方式java io流结构图:
    在这里插入图片描述

  • 按照操作对象java io流分类结构图:
    在这里插入图片描述

12、BIO,NIO,AIO 有什么区别?

  • BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
  • NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
  • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

13、Java序列化

  • 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
  • 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
  • 如果想让某个变量不被序列化,使用transient修饰。
  • 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
  • 反序列化时必须有序列化对象的class文件。
  • 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
  • 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
  • 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
  • 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。