与C++的异同
- 都是面相对象的编程语言,都具有封装、继承、多态的三大特征。
面向对象是先抽象出对象,让对象执行方法来解决问题。面向过程是将问题拆成一个一个的方法。执行这些方法来解决问题。
- java没有指针,不直接访问内存,内存安全;c++有指针;
- c++支持函数重载以及操作符重载,java只有方法重载
- c++需要处理内存;java有内存管理(GC),自动处理
- c++支持多重继承;java类不支持,接口支持
JAVA的特点
简单、高可靠、可跨平台、面向对象、分布式、多线程、支持网络编程等等(一次编译,随处运行)
部分相关概念
JVM是Java虚拟机,即Java字节码的虚拟机。不同的操作系统有不同的JVM,为了让Java程序在不同的系统上,使用相同的字节码,产生相同的结果,即“一次编译,随处运行”,也是跨平台的关键。常见的JVM是HotSpot VM,除此之外还有Zing VM、JRockit VM等等,其实只要满足JVM的规范,可以开发自己的专属JVM。
JDK(Java Development Kit)是Java SDK,即Java软件开发包,JDK=JRE+JAVAC+各种工具,它是Java程序运行的基础。
JRE是Java运行时的环境,是运行已编译Java程序所需的所有内容的集合,包括JVM、Java类库、Java命令、一些基础构件等等,但他不用于创建新程序。这就说明,如果你想运行java程序,那你只安装JRE就行,如果你想编程,那你就要安装JDK了。
字节码
字节码在Java中是JVM可以理解的代码,即.class文件。它不局限于任何特定的处理器,只面向VM,字节码赋予了跨平台可移植的特点。
一个完整的Java程序从代码到可运行的过程:完整可运行的代码,即.java文件,经过javac编译器编译,将之转换为字节码,即.class文件,字节码通过JVM类加载器加载,再通过解释器解释执行。(其中,通过引入JIT编译器,将常用代码编译后保存起来,方便以后直接使用)变为机器码,再到计算机读这些机器码即可运行。后面JDK9推出AOT(Ahead of Time Compilation)编译模式,直接将字节码编译为机器码,避免JIT过程的开销,当然JDK支持分层编译和AOT协作使用的。
那么AOT这么优秀为啥不全部使用它呢?
因为Java具有动态性的,存在一种ASM技术,它是直接在内存中生成并加载修改后的字节码,AOT没有JIT保存机器码的过程,导致ASM不能使用。
高级语言可分为编译型和解释型。编译型语言会通过编译器将源代码一次性翻译成可被该平台执行的机器码。一般情况下,编译语言的执行速度比较快,开发效率比较低。常见的编译性语言有 C、C++等等。解释性语言会通过解释器逐句的将代码解释(interpret)为机器代码后再执行。解释型语言开发效率比较快,执行速度比较慢。常见的解释性语言有 Python、JavaScript、PHP 等等。
关键字
- private、protected、public
- abstract、class、extends、assert、final、implements、interface、native、new、static、strictfp、synchronized、transient、volatile、enum
- boolean、byte、char、double、float、int、long、short
- import、package
- case、continue、default、do、else、for、if、instanceof、return、switch、while、break
- super、this、void
- throw、throws、try、finally、catch、
- goto、const
- true、false、null
成员变量、局部变量、全局变量
- 成员变量只能通过对象访问;写在类声明的大括号里,属于类;存储在堆中;可以被public、static等修饰符修饰
- 局部变量不能被修饰符修饰;写在方法里或者代码块中;存在于栈中;
- 全局变量存在静态区;写在函数外或者大括号外
重载与重写
重载是同一个类中的多个同名方法,由于不同的传参导致进行不同的处理。
重写是子类继承父类的方法,由于子类的方法进行不同的处理,覆盖了父类方法,产生不同的结果。
类的构造方法
构造方法用于初始化对象。其特点有:方法名必须与类名相同;不能用void声明,虽然方法没有返回值;生成对象时自动执行;不能被重写,但可以重载。
一般地,类有默认的无参构造方法,也就是说即使一个类没有构造方法,这个类也是可以执行的。如果我们创建了构造方法(有参或者无参的),就不再使用默认的了。在创建对象时,在最后要加一个(),这里就已经使用了默认的无参方法或者自己创建的无参方法。
反射
反射是将java类的各种成分映射成对象,可以通过调用这些对象获取到类的所有信息(属性和方法);框架中运用了大量的反射机制。
序列化、反序列化
序列化是将对象或者数据结构转换为二进制字节流的过程;反序列化反之。主要为将对象存储到文件中、数据库中、内存中。一般在网络传输、存入文件、缓存数据库前需要进行序列化,读取或者接收时则需要反序列化。
transient关键字可以阻止序列化,对于反序列化的,不能被持久化和恢复。transient只能修饰变量
代理模式
使用代理对象来代替真实对象,保证不修改真实对象的前提下,拓宽业务。增加功能。代理模式分为静态代理与动态代理
静态代理日常开发不咋用,它不符合java开发的特点,不灵活并切很麻烦,静态代理的实现步骤:
- 定义一个接口及其实现类
- 创建代理类也实现这个接口
- 将对象注入进这个代理类中,然后就可以调用对应的方法了
动态代理,Spring AOP、RPC框架是靠动态代理实现的,实现动态代理方式有很多种,比如JDK动态代理、CGLIB动态代理。
JDK动态代理,其核心是InvocationHandler
接口和 Proxy
类,其中Proxy类中的newProxyInstance()方法,可以生成一个代理对象。免去了自己创建代理类的步骤。当然实现动态代理还需要实现InvocationHandler类,来自定义处理逻辑。这个类的作用是当代理对象调用一个方法时,这方法的调用就会转发到实现InvocationHandler类中的invoke方法中来调用。JDK动态代理类使用步骤:
- 定义一个接口及其实现类
- 重写InvocationHandler类中的invoke方法,在invoke方法中调用原生方法以及自定义的处理逻辑
- 使用newProxyInstance()方法创建代理对象
CGLIB动态代理,MethodInterceptor
接口和 Enhancer
类是核心。需要重写 MethodInterceptor
中intercept
方法,Enhancer
类中的creat()方法来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor
中的 intercept
方法。实现步骤:
- 定义一个类;
- 重写
MethodInterceptor中
intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的invoke
方法类似; - 通过
Enhancer
类的create()
创建代理类
两者的区别:CGLIB没有代理任何接口的类,JDK只能通过代理接口来实现动态代理。但是JDK代理的效率更高。
遇见的小问题
==与equals()的区别
基本数据类型,==比较的就是数值;引用数据类型,==比较就是对象内存地址了。
equals()可以用来比较对象,不可以比较两个基本数据类型。重写equals方法可以比较对象的内容是否相等。String的equals()方法就是比较对象的值,原始的equals的方法是Object中的,与==相同比较的是地址。
SPI和API
简单的讲,API是一种用户直接使用完成特定目标的对象,可以直接使用(即插即用)。SPI更像是一种规则,用户想要使用它达到特定的目标,必须要继承或者实现它,这就导致了一般都是有特殊用途的接口开发商使用,当然个人也可以。SPI机制可以极大的扩宽接口的灵活性和实用性,但是存在效率比较低的现象。
SPI机制需要依赖ServiceLoader来实现,ServiceLoader是一个工具类,是一种加载服务实现的工具。