Java 趣味笔记 - 基础


提示:以下是本篇文章正文内容,下面案例可供参考

一、面向过程和面向对象的区别

面向过程:面向过程性能会比面像过程高,因为类的调用需要实例化,开销比较大,比较耗费资源,所以当对性能要求比较高的时候,一般采用面向过程,如单片机、嵌入式开发等。

二、java性能低是因为面向过程的原因嘛?

这并不是根本原因,面向过程也需要分配内存,计算偏移量等,java性能低的主要原因是因为他是半编译语言,最终的执行代码并不是可以直接被cpu执行的二进制机械码。

三、构造器是否可以被override?

构造器不可以重写,但是可以重载

四、String, StringBuffer 和 StringBuilder的区别,为什么说String 是 不可变的?

String类中实际上是用final关键字修饰的字符数组 private final char value[],所以String对象是不可变的。在java 9之后,String 类的实现改用byte数组存储字符串
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder没有用final修饰字符串数组,所以这两种对象都是可变的。这两个对象的构造方法都是调用父类的。
线程安全性
String 是final的所以是线程安全的。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder没有加锁,所以是非线程安全的。

五、静态方法为什么不能调用非静态方法?

由于静态方法可以不通过类调用,因此在静态方法里不能调用其他非静态变量,因为静态方法先加载到内存。

六、接口和抽象类的区别是什么?

  1. 方法在接口中不能有实现(java 8允许方法可以有默认实现),而抽象类可以有非抽象的方法。
  2. 接口中出来static、final变量不能有其他变量,抽象类则不一定。
  3. 一个类可以实现多个接口,但是只能实现一个抽象类。
  4. 接口方法默认是public,抽象方法可以有public、protected和default这些修饰符(抽象方法是为了被重写所以不能使用private关键字修饰)。
  5. 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为规范。
  6. 在jdk8中,接口也可以定义静态方法,可以用接口名调用,实现类和实现是不能调用的。如果同时实现了两个接口,接口中定义了一样的默认方方法,则必须重写,否则报错。
  7. jdk9 的接口允许定义私有接口
    jdk7之前,接口中只能有常量变量和抽象方法;jdk8的时候接口可以有默认方法和静态方法功能;jdk9在接口中引入了私有方法和私有静态方法。

七、== 和 equals

  1. 基本数据类型 == 比的是值
  2. 引用数据类型 == 比的是地址
  3. String的特殊情况见图1
  4. 没覆盖equals方法则等同于 ==
    在这里插入图片描述

八、你重写过hashCode和equals嘛,为什么重写equals的时候必须重写hashCode方法?

hashCode定义在Object中,作用是获取哈希码,这个哈希码是对象在哈希表中的索引位置,并且hashCode方法是native方法。
在这里插入图片描述
当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则计算另一个位置储存。
调用调用hashCode的原因是因为hashCode效率更高(仅为一个int值),比较起来更快。
当equals方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规约定:值相同的对象必须有相同的hashCode。
由此可以得到

  • object1.equals(object2)为true,hashCode也相同;
  • hashCode不同时,object1.equals(object2)为false;
  • hashCode相同时,object1.equals(object2)不一定为true;

那如果不重写hashcode会有什么问题呢,举个例子:
new 两个学生,学生只有一个属性,String idCart= 10,他们是两个不同的对象,所以他们默认的hash值是一定不同的,因此我们向hashSet中插入数据时,hashSet会判断hashCode码,发现hashCode码不一样,所以直接插入。此时hashSet中有两个身份证一样的人,但是显然这不是我们想要的结果,所以需要重写hashcode,手动将判断学生的idCart,如果idCart相同,则返回一样的hashcode。

九、Java是值传递还是引用传递

java是值传递,很多语言同时支持值传递和引用传递,在java中,将一个对象作为形参传到一个函数中,函数中的实参承接的是引用值的拷贝(注意实参和原参数是两个对象),如果在函数中对两个对象做swap(a,b);那么实际上对调的只是实参的引用,原来数据的引用并没有对调。所以java对象采用的不是引用调用,实际上对象引用是按值传递的。

十、java线程的状态与生命周期

java线程的几种状态
在这里插入图片描述
线程的生命周期
在这里插入图片描述
线程创建之后它将处于 NEW(新建) 状态,调⽤ start() ⽅法后开始运⾏,线程这时候处于READY(可运⾏) 状态。可运⾏状态的线程获得了 cpu 时间⽚(timeslice)后就处于RUNNING(运⾏) 状态。
操作系统隐藏 Java 虚拟机(JVM)中的 READY 和 RUNNING 状态,它只能看到RUNNABLE 状态(图源:HowToDoInJava:Java Thread Life Cycle and Thread
States),所以 Java 系统⼀般将这两个状态统称为 RUNNABLE(运⾏中) 状态 。

十一、关于final的一些总结

final主要用在三个关键字上,变量,方法,类

  1. final修饰变量的时候,变量的值初始化后就再也不能改变其值,修饰引用类型变量的时候,则其在初始化后便不能在指向其他对象。
  2. final修饰类的时候,这个类将不能在被继承。final类中的成员方法将会隐式指定为final。
  3. final修饰方法的原因有两个,一个是把方法锁定,防止继承类修改他的含义,另一个是效率,在早期java中会将final方法转为内嵌调用。类中的所有private方法都会隐式指定为final。

十二、异常处理总结

当在 try 块或catch 块中遇到 return 语句时, finally 语句块将在⽅法返回之前被执⾏。
在以下 3 种特殊情况下, finally 块不会被执⾏:

  • 在 try 或 finally 块中⽤了 System.exit(int) 退出程序。但是,如果 System.exit(int) 在异常
    语句之后, finally 还是会被执⾏
  • 程序所在的线程死亡。
  • 关闭 CPU。
    当 try 语句和 finally 语句中都有 return 语句时,在⽅法返回之前,finally 语句的内容将被
    执⾏,并且 finally 语句的返回值将会覆盖原始的返回值。
    在这里插入图片描述
    如果调⽤ f(2) ,返回值将是 0,因为 finally 语句的返回值覆盖了 try 语句块的返回值。

十三、java 序列化忽略字段

对于不想进⾏序列化的变量,使⽤ transient 关键字修饰。
transient 关键字的作⽤是:阻⽌实例中那些⽤此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和⽅法

十四、java中的IO流

1. 流的基本分类
  • 按照流的流的流向,可以分为输入流和输出流;
  • 按照操作单元划分,可以分为字节流和字符流;
  • 按照流的角色划分为节点流和处理流;

Java Io流共涉及40多个类,这些类存在紧密的联系,他们都是从如下四个抽象类基类中派生出来的。。

  • InputStream/Reader: 所有的输⼊流的基类,前者是字节输⼊流,后者是字符输⼊流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流
2. 为什么要有字符流

Java中一切都是字节流,没有字符流,字符只是根据编码对字节流进行翻译的结果。 字符流 = 字节流+编码表
字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是⾮常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就⼲脆提供了⼀个直接操作字符的接⼝,⽅便我们平时对字符进⾏流操作。

3. BIO,NIO,AIO 有什么区别?
  • BIO (Blocking I/O): 同步阻塞 I/O 模式,数据的读取写⼊必须阻塞在⼀个线程内等待其完成。在活动连接数不是特别⾼(⼩于单机 1000)的情况下,这种模型是比较不错的,可以 让每⼀个连接专注于⾃⼰的 I/O并且编程模型简单,也不⽤过多考虑系统的过载、限流等问 题。线程池本身就是⼀个天然的漏⽃,可以缓冲⼀些系统处理不了的连接或请求。但是,当⾯对⼗万甚⾄百万级连接的时候,传统的 BIO 模型是⽆能为力的。因此,我们需要⼀种更⾼效的 I/O 处理模型来应对更⾼的并发量。
  • NIO (Non-blocking/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,不过⼜放弃了。

十五、深拷⻉ 和 浅拷⻉

  1. 浅拷⻉:对基本数据类型进⾏值传递,对引⽤数据类型进⾏引⽤传递般的拷⻉,此为浅拷⻉。
  2. 深拷⻉:对基本数据类型进⾏值传递,对引⽤数据类型,创建⼀个新的对象,并复制其内容,此为深拷⻉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值