JAVA基础学习

201 阅读9分钟

Java基础

Object类详解

Object类的几个重要方法

  1. toString
  2. equals: 对于Object类的equals()方法来说,它是判断调用equals()方法的引用与传进来的引用是否一致,即这两个引指向的同对象。 对于 Object类的equals()方 法来说,它等价于 == 。 关于Object类的equals方法的特点 a) 自反性:x.equals(x)应该返回true b) 对称性:x.equals(y)为true,那么y.equals(x)也为true c) 传递性:x.equals(y)为 true并且y.equals(z)为true,那么x.equals(z)也应该为true d) 一致性:x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也应该为true,前提条件是在比较之间没有修改x也没有修改y e) 对于非空引用x,x.equals(null)返回false
  3. hashCode:Object类的hashCode值表示的是对象的地址 关于Object类的hashCode()方法的特点: a) 在Java应用的一次执行过程当中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化) b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的 c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能 d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址) 如果我们重写equals方法,那么也要重写hashCode方法,反之亦然
  4. getClass

ISSUE: Object类方法相关问题

ISSUE: equals方法的意义

对于object对象来说,他的equals方法是判断调用equals()方法的引用与传进来的引用是否一致,即这两个引指向的同对象。 而对于其他类,如果重写了equals方法,则按照具体方法实现判断内容是否一样

String类源码

  • equals方法重写:对于String类的equals()方法来说,它是判断当前字符串与传进的内容 是否一致
  • 是final类,不能被继承
  • String 是常量,其对象一旦创建完毕就无法改变。当使用+拼接字符串时,会生成新的String对象,而不是向原有的String 对象追加内容
  • String Pool(字符串池,池用于提高效率) String str = 'aaa'(字面方式赋值) 和String str = new String("aaa")的差别
  • intern()方法
  • StringBuffer

集合源码

  • java.util包
  • 集合框架中的接口

Collection interface

集合框架

ArrayList

  • 底层就是 Object[] elementData的数组,使用不带参数的构造方式生成一个ArrayList时,默认生成长度为10的Object数组
  • add操作: 如果增加的元素个数超过了10个,那么ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素时,重复该过程
  • remove操作:对于ArrayList元素的删除操作,需要将被删除元素的后续元素向前移动,涉及到大量元素的移动,代价比较高

LinkedList

LinkedList中所维护的是一个个的Entry对象

HashSet

返回无序set。当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hashcode值是否与增加的对象的hashCode值一致; 如果不一致,直接加进去; 如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

底层原理:HashSet的底层是HashMap 当使用add方法将对象添加到Set当中时,实际上是将该对象作为底层所维护的Map对象的key,而value则都是同一个Object对象(该对象我们用不上)

TreeSet (SortedSet接口的实现)

返回排序后的set。 底层有比较机制, 对象需要指定好排序规则,实现Comparator接口

HashMap

底层原理: HashMap底层维护一个数组 ,我们向HashMap中所放置的对象实际上是存储在该数组当中, 实际是 数组+链表的混合结合实现 数组的初始长度(16), 负载因子(0.75)[当数组容量有75%被占用了,数组就会扩容两倍 ]。

当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(Entry类有一个Entry类型的next成员变量,指向了该对象的下一个对象),如果此链上有对象的话,再去使用equals方法进行比较,如果对此链上的某个对象的equals方法比较为false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。

TreeMap

ISSUE: ArrayList与LinkedList的比较分析

  • ArrayList底层采用数组实现,LinkedList底层采用双向链表实现
  • 当执行插入或者删除操作时,采用LinkedList比较好
  • 当执行搜索操作时,采用ArrayList比较好
  • 当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一个Entry对象,该Entry对象的结构为
{
    Entry previous;
    Object element;
    Entry next;
}

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Entry又构造好了向前与向后的引用previous、next,最后将生成的这个Entry对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Entry对象

ISSUE: Vector, Hashtable的特征

自动装箱与自动拆箱

Integer 源码

方法valueOf:-128~127 会被缓存, 范围在此的数值不会生成新的对象, 比Integer的构造方法性能更好(构造方法生成的数据一定是生成新对象的)

反射 reflection

I/O

字节流和字符流

字节流

核心抽象方法:read(), write()

  • InputStream Interface, OutputStream Interface(接口):
  1. 用于操作文件的方法FileInputStream, FileOutputStream
  2. ByteArrayInputSream(byte[] byteArray, ..), ByteArrayOutputStream

字符流 支持Unicode字符

  • Reader和Writer抽象类
  1. InputStreamReader和OutputStreamWriter 字节流和字符流的桥梁

节点流和过滤流

过滤流 FilterInputStream, FilterOutputStream

过滤流会将文本数据处理转成二进制流

  • BufferedInputStream, BufferedOutputStream, ** 包装输入流和输出流**

序列化

将对象转换成字节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化,实现对象持久化
需要实现Serializable接口(标示性接口)

  1. 序列化只保存对象的非静态成员变量
  2. 如果一个对象的成员变量也是一个对象,这个对象也会被保存
  3. 如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作都会失败(处理方法!!! 将这个引用标记为transient
  4. static变量无法序列化

常用设计模式

单例模式

策略模式(实例:TreeSet,TreeMap)

- 抽象策略角色
- 具体策略角色
- 环境角色

策略模式的编写步骤:

  1. 对策略对象定义一个公共接口
  2. 编写策略类,该类实现了上面的公共接口
  3. 在使用策略对象的类中保存一个对策略对象的引用
  4. 在使用策略对象的类中,实现对策略对象的set和get方法(注入)或者使用构造方法完成赋值。 缺点: 1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类 2.造成很多的策略类;解决办法:采用工厂方法

代理模式

为其他对象提供一种代理以控制对这个对象的访问

代理对象:在客户端和目标对象之前起到中介作用

- 抽象角色:真是对象和代理对象的共同接口
- 代理角色:还有对真实对象的引用,从而可以操作真是对象
- 真实角色:代理角色表达的真实对象

静态代理的缺点:类的急剧膨胀,如果事先不知道真实角色,也不能用

动态代理: 运行是时候生成类,在生成类的时候提供一组interface,然后该class就宣称实现了这些Interface

Interface InvocationHandler (调用处理器) 一个invoke方法:返回object

    Object invoke(Object proxy, 
    Method method, 
    Object[] args)

Proxy

    public static Object newProxyInstance(ClassLoader loader,
    Class[] interfaces,
    InvocationHandler h)

通过动态代理,被代理的对象可以在运行时动态改变,需要控制的接口可以在运行时改变,控制的方式也可以改变,从而实现了非常灵活的动态代理关系

观察者模式(实例:AWT事件模型)

定义一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有的观察者对象,让他们自动更新自己

-抽象主题角色
-抽象观察者角色
-具体主题角色
-具体观察者角色

JDK内置支持 Observable类

装饰模式(实例:I/O)

又名包装模式,以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
可以在不创造更多子类的情况下,将对象的功能加以扩展

- 抽象构建角色 Component
- 具体构建角色 Concrete Component
- 装饰角色 Decorator 
- 具体装饰角色 Concrete Decorator

其中 装饰角色持有一个构建对象的引用,并定义一个与抽象构建接口一致的接口

工厂方法

迭代器模式

异常

异常分类: Checked Exception(非Runtime Exception) Unchecked Exception(Runtime Exception)

运行时异常都是继承RuntimeException的

System.exit(0) 会终止运行的虚拟机

内部类

分类:静态内部类,成员内部类,匿名内部类(隐式的继承了一个父类或者实现了一个接口), 局部内部类

线程及并发基础

ISSUE: 线程与进程的区别

  1. 多个进程的内部数据和状态是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能相互影响。
  2. 线程本身的数据通常只有寄存器数据,以及
  3. 进程是重量级的任务,需要分配独立地址空间。而

常见面试题汇总

  • transient 仅用在序列化,瞬时,使用以后就被修饰的数据就不会序列化到文件中
  • volitail

reference

https://blog.csdn.net/as6757uyy65uy75/article/details/79370686