Java基础
三大特性
- 封装
- 继承
- 多态
- 多态分为编译时多态(
方法重载)和运行时多态(对象引用所指向的具体类型在运行期间才确定) - 运行时多态有三个条件:
继承、覆盖(重写)、向上转型
- 多态分为编译时多态(
方法分类
https://www.runoob.com/note/40084
- 虚方法:可以被覆写的方法都可以称作虚方法,也可以理解为除了用static、final、private修饰之外的所有方法都是虚方法。
- 纯虚方法:abstract修饰的方法
解析与分派
- 解析是指方法在编译期就可知的,有一个确定的版本且运行期不可变。是静态的,在**
类加载时**解析阶段会将其符号应用解析从直接引用。- invokestatic:静态方法
- invokespecial:构造器、私有方法、父类方法、final方法
- 分派又分为静态分派、动态分派。
- 重载属于静态分派(invokevirtual),在**
编译期间**能根据参数的静态类型决定使用哪一版本的方法。 - 重写属于动态分派(invokevirtual),在运行期间进行符号引用解析,根据参数的实际类型决定调用方法的版本。
- 重载属于静态分派(invokevirtual),在**
- 解析和分派时多态的一个实现,这种多态是方法的多态。但是字段不支持多态,父类字段名和子类字段名相同时,子类对象会存在两个字段,但是他们会被分开在所属类的空间中,父类方法访问的时父类的字段,子类方法访问的是子类的字段。
面向对象设计原则(单开里依接米)
- 单一职责:一个类应该只负责一个职责
- 开闭原则:一个类当对扩展开放,对修改关闭
- 里氏替换原则:系统中所有用到某个类的地方都替换成其子类,系统应该仍然可以正常工作。子类与父类的含义与功能一致
- 依赖倒置原则:抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。让调用者依赖的接口尽可能的小。
- 米迪特原则:一个类应该对自己需要调用的类知道得最少,类的内部如何实现与调用者没关系,调用者只需知道他需要的方法即可,其他的一概不关心。
八个基本类型:
- boolean/1
- byte/8:-2^7 ~ 2^7 - 1,即 -128 ~ 127
- char/16: 0 ~ 2^16 - 1,即 0 ~ 65535
- short/16: -2^15 ~ 2^15 - 1,即 -32768 ~ 32767
- int/32:-2^31 ~ 2^31 - 1,即 -2147483648 ~ 2147483647
- float/32
- long/64: -2^63 ~ 2^63 - 1,即 -9223372036854775808 ~ 9223372036854775807
- double/64
String为final的好处
- 可以缓存hash值
- String pool的需要,只有 String 是不可变的,才可能使用 String Pool
- 线程安全,String 不可变性天生具备线程安全,可以在多个线程中安全地使用
String.intern()
使用 String.intern() 可以保证相同内容的字符串变量引用**同一内存对象**
字符串常量池
运行时常量池(Runtime Constant Pool)是虚拟机规范中是方法区的一部分,在加载类和结构到虚拟机后,就会创建对应的运行时常量池;而字符串常量池是这个过程中常量字符串的存放位置。所以从这个角度,逻辑上字符串常量池属于虚拟机规范中的方法区,它是一个逻辑上的概念;而堆区,永久代以及元空间是**实际的存放位置**。
- jdk7之前存在永生代,字符串常量池存放在永生代中
- jdk7依然存在永生代,永久代(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)
- jdk7之后移除永生代,元空间(类型信息、字段、方法、常量)和堆(字符串常量池、静态变量)
switch语法
- switch
底层使用 int来进行判断的,即使是枚举、String类型,最终也是转变成 int 型。由于 long 型表示范围大于 int 型,因此不支持 long 类型。 - jdk7开始,switch支持String类型作为参数,编译时通过String的hashcode()转换成int型
- switch不支持long、double类型的参数
Java 注解
- 为类、方法等代码添加额外的注解元数据;
- 注解可以给编译器提供信息;在编译阶段可以根据注解生成代码、文档等;运行阶段可以根据注解提取代码。
拆箱装箱的原理
1、在编译阶段把需要拆箱的代码替换成class.xxValue(),需要装箱的代码替换成.valueOf() 2、基础类型使用享元模式,short,byte,int,long:-128~127 boolean:true,false
ThreadLocal
线程变量,可以使变量在多个线程有不同的副本:不同线程自己的Map,存同一个ThreadLocal对应不同value
核心特点:
- 每个线程有独立的 ThreadLocalMap(互不干扰)
- 每个 ThreadLocalMap 存储多个 Entry(键是 ThreadLocal 实例,值是线程私有副本)
- 键用弱引用(ThreadLocal 实例不用时可被回收)
- 值用强引用(保证线程运行时能正常访问)
细节补充:
- hashcode使用**
斐波那契散列法,当出现hash冲突时使用开放选址法(hash+1)(线性探测法**)进行定位 - ThreadLocal.set时,会通过cleanSomeSlots方法**
清除无效**的ThreadLocal数据
问题:没有解决hash冲突问题,变量很多时效率低。未及时清理ThreadLocal导致内存泄露