JVM java虚拟机,针对不同的系统,使用相同的字节码会给出相同结果。一次编译,随处可运行
JDK Java SDK 提供给开发者使用,创建和编译Java程序。包含了JRE,同时包含了其它工具(java 源码的编译器 javac 等)
JRE Java运行环境,包含JVM和基础类库
JVM可以理解的代码叫字节码(.class文件),只面向虚拟机,解决了传统解释性语言效率低的问题,又保留了解释性语言可移植的特点。
.class - > 机器码,首先加载字节码文件,然后解释器逐行解释执行,如果代码块经常被调用(热点代码),JIT在第一次编译后将机器码保存下来,下次直接使用。
根据二八定律,消耗大部分资源的只有一小部分代码(热点代码),即JIT需要编译的部分。JIT需要预热,达到一定时间和调用频率才会触发JIT分层
直接将字节码编译成机器码,避免预热。但不能根据程序运行情况进一步优化。代码经常更新的话每次都需要重新编译。
编译:将源代码一次性翻译成可被该平台执行的机器码(C++)开发慢,执行快
解释:一句一句的将代码解释(interpret)为机器代码后再执行(Python)开发快,执行慢
Java程序要先经过编译,生成字节码,再由Java解释器执行
整数型:byte short int long
浮点数:float double
字符:char
布尔:boolean
包装类型可用于泛型,基本类型不行
基本数据类型的局部变量存放于虚拟机栈的局部变量表,成员变量放在堆中;包装类型属于对象类型,放在堆
基本数据类型占用空间小
包装类型不赋值时为null,基本数据类型有默认值
基本数据类型 == 比较真值,包装类型 == 比较地址;整型包装类型之间的比较用 equals
整型(-128~127)、布尔、字符默认创建了缓存数据,如 Integer i1 = 40; 直接使用了缓存中的对象
装箱:基本类型->引用类型
拆箱:引用类型->基本类型
Integer i = 10
等价于 Integer i = Integer.valueOf(10)
int n = i
等价于 int n = i.intValue()
精度丢失:无限循环的小数储存在计算机会被截断,没办法用二进制精确表示
浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断
BigDecimal 可以实现对浮点数运算不丢精度
超过long:BigInteger内部用int[]储存任意大小的整型数据
static 被类的所有实例共享,所有对象共享同一份静态变量,节省内存。通常静态变量会被final修饰成常量。
字符常量相当于一个整型值(ASCII),可以参加运算;字符串常量表示一个地址(字符串在内存中的位置)
char占两个字节
面向对象三大特性:封装、继承、多态
静态方法不能调用非静态成员:静态方法属于类,类加载时分配内存,可通过类名直接访问;非静态成员属于对象,实例化后才能存在。
调用可以使用 类名.方法名
和对象.方法名
只允许访问静态成员
重载:一个方法根据输入不同,处理不同。参数类型、个数、顺序不同,返回值,修饰符可以不同
重写:子类继承父类相同方法,覆盖父类方法。参数列表相同,返回值、抛出异常范围应该小于等于父类,访问修饰符范围大于等于父类(两同两小一大)
可变参数只能作为最后一个参数,重载优先匹配固定参数
面向过程:过程拆解成一个个方法
面向对象:抽象出对象,用对象执行方法
new 创建对象实例(对象实例在堆内存),对象引用(在栈内存)指向实例
气球和绳子:一个实例可有多个引用
对象相等:内存中内容相等
引用相等:指向的内存地址相等
没有声明构造方法也可执行(默认无参构造)
不能重写(overwrite),但能重载(overload)
对象的状态信息隐藏在内部,不允许外部直接访问对象内部信息,提供方法给外界。
子类可以增加新的数据或功能,也可以用父类的,但不能选择性继承。
父类的引用指向子类的实例
Animal animal1 = new Dog();
对象类型和引用类型间有继承(类)/实现(接口)关系
多态不能调用“只存在于子类不存在于父类”的方法
共同点
区别
public static final
类型的;抽象类成员变量默认default,可以在子类重新定义赋值浅拷贝:堆上创建一个新对象,原对象内部是引用对象的话,会直接复制内部对象的地址,即共用一个内部对象
实现Cloneable接口,调用父类Object的clone方法
深拷贝:完全复制整个对象,包括内部对象
序列化和反序列化
public class DeepCopy {
public static void main(String[] args) {
}
// 泛型类型参数必须实现 Serializable 接口
public static <T extends Serializable> T deepClone(T obj) throws IOException, ClassNotFoundException {
// 对象写入字节流。序列化
// 对象写入字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 对象序列化写入outputStream
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
// 将对象obj写入outputStream
objectOutputStream.writeObject(obj);
// 从字节流读取对象,反序列化
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
return (T) objectInputStream.readObject();
}
}
class User implements Serializable {
String name;
Address address;
public User(String name, Address address) {
this.name = name;
this.address = address;
}
}
class Address {
String province;
String city;
public Address(String province, String city) {
this.province = province;
this.city = city;
}
}
hashCode: 返回对象的哈希码;
equals: 比较两对象地址是否相等(String重写了该方法)
clone: 浅拷贝
toString:
wait: 暂停线程
notify、notifyAll: 唤醒线程
== 对于基本类型比较值,对于引用类型,比较地址(本质也是比较值,但引用类型变量存的地址)
equals 等价于 == ,但一般会重写,来比较属性相等
获取哈希码,确定对象在哈希表中的索引位置
hashcode和equal都是比较对象是否相等,但hashcode效率更高。HashSet对比时,同样的哈希码下再用equals。
两个对象hashcode相等,不一定对象相等(哈希码算法可能重复)
两对象equals相等时,hashcode一定相等,不然使用hashmap会出现问题(无法正确找到对象)
如果不重写hashcode,equals按属性值比较,hashcode按地址比较
String不可变,故线程安全,每次改变都会生成一个新的String对象。String中使用final修饰的字符数组来保存字符串。
StringBuilder
与 StringBuffer
都继承自 AbstractStringBuilder
类,提供了修改字符串的方法,如 append
StringBuffer 对方法加了同步锁,线程安全;StringBuilder线程不安全
字符串 + 实际上是通过StringBuilder调用append方法实现,String的for循环拼接每次循环创建一个StringBuilder,不如直接用StringBuilder拼接效率高。
JVM为字符串开辟的区域,避免重复创建
// 在堆中创建字符串对象”ab“
// 将字符串对象”ab“的引用保存在字符串常量池中
String aa = "ab";
// 直接返回字符串常量池中字符串对象”ab“的引用
String bb = "ab";
System.out.println(aa==bb);// true
String.intern 将指定字符串对象的引用保存在字符串常量池,若已保存,直接返回该引用
exception:程序本身可以处理的异常,可以通过catch捕获
error:程序无法处理的错误,JVM一般会选择线程终止。内存溢出、虚拟机异常等
checked:没有被catch或throws处理的话没法通过编译,如IO异常
unchecked:不接受检查也可以正常通过编译,由于逻辑错误或环境错误引起,如算术错误、空指针
try-catch-finally
finally不一定会运行,如:CPU关闭、线程死亡
泛型类
public class Generic{
泛型接口
public interface Generator<T> {
泛型方法
public static < E > void printArray( E[] inputArray )
自定义一个与CommonResult
接口,接口中的方法 getData()
中使用类型参数 T
来动态指定结果的数据类型。
public interface CommonResult {
boolean isSuccess();
String getMessage();
T getData();
}
工具类
可以在运行时分析类以及执行类中方法,通过反射可以获取任意一个类的所有属性和方法,并调用
反射通过编译后的字节码(class)文件找到其中的信息
在动态代理中,invoke函数中使用反射类Method来调用指定方法
注解也用到了反射,@Value
注解就读取到配置文件中的值
优点:让代码更灵活,为框架开箱即用的功能提供便利
缺点:安全问题,性能略差
class对象将一个类的信息告诉程序
Class alunbarClass = TargetObject.class;
Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
TargetObject o = new TargetObject();
Class alunbarClass2 = o.getClass();
@Override
// 覆盖父类方法
@Deprecated
// 标注内容不再被建议使用
注解解析后才会被使用
服务者提供给框架的使用者的接口,运行时动态加载框架。
将服务的接口与具体实现类解耦。
按照规定将要暴露对外使用的具体实现类在固定文件中声明,框架在运行时扫描并加载实现类。
API:实现方提供接口和实现,我们调用接口
SPI:调用方确定接口规则,厂商根据规则实现
优点:接口设计灵活
缺点:需要遍历加载所有实现类,效率低
序列化:将数据结构或对象转换成二进制字节流
反序列化:将二进制字节流转成数据结构或对象
目的:通过网络传输对象,或储存
属于计算机网络的应用层
不想被序列化:transient修饰
不推荐原因
RPC协议,dubbo2.x默认启用序列化协议
简单易用,性能低
服务者提供给框架的使用者的接口,运行时动态加载框架。
将服务的接口与具体实现类解耦。
按照规定将要暴露对外使用的具体实现类在固定文件中声明,框架在运行时扫描并加载实现类。
API:实现方提供接口和实现,我们调用接口
SPI:调用方确定接口规则,厂商根据规则实现
优点:接口设计灵活
缺点:需要遍历加载所有实现类,效率低
序列化:将数据结构或对象转换成二进制字节流
反序列化:将二进制字节流转成数据结构或对象
目的:通过网络传输对象,或储存
属于计算机网络的应用层
不想被序列化:transient修饰
不推荐原因
RPC协议,dubbo2.x默认启用序列化协议
简单易用,性能低