#基础概念
##Java语言的特点
- 面向对象。封装、多态、继承
- 较好的兼容性(Java虚拟机实现跨平台,一次编译,多平台使用)
- 支持多线程
- 支持网络编程
- 编译与解释并从
Write Once, Run Anywhere
##JVM
Java虚拟机,是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现,目的是使用相同的字节码,得到相同的运行结果,是一次编译,处处运行的体现。
##JRE 和 JDK
JDK(Java Development Kit),是全功能的Java SDK。除了包含JRE之外,还有编译器javac,工具javadoc,jdb。
JRE是Java程序运行时的环境,是运行已编译Java程序所需内容的集合。包含JVM,Java类库,Java命令和一些基础构件。正常情况下只需要运行Java程序使用JRE足够,如果需要开发或者编译Java程序则必须使用JDK。
如果使用JSP部署WEB程序,则需要JDK。因为应用程序服务器会将JSP转换为Java Servlet,需要JDK来编译Servlet。
##字节码
JVM可以理解的代码叫做字节码,扩展名为.class的文件。
字节码解决了传统解释型语言执行效率低的问题,同时保留了解释型语言可以值的提点。
##编译与解释并存
编译型:通过编译器一次性将所有代码翻译成机器码。执行速度快但开发效率低。如C、C++、Go、Rust。
解释型:通过解释器一句一句将代码解释成机器码再执行。开发快但执行速度满。如Python,PHP,JS。
Java语言即具有编译型语言的特征,也具有解释型语言的特征。Java程序需要经过先编译,再解释两个过程。
通过编译生成字节码.class文件,再有Java解释器解释执行。
#基础语法
##continue、break 和 return
continue:跳出当前这一次循环,继续执行下一次循环。
break:跳出整个循环体,继续执行循环体下面的代码。
return:天出当前方法,结束该方法的执行。
##成员变量和局部变量
- 语法形式:成员变量属于类,局部变量属于方法。成员变量可以被public、private、static修饰符修饰,局部变量不行。两者都能被final修饰。
- 存储方式:如果成员变量被static修饰,这个成员变量属于类,如果没有被static修饰,成员变量属于实例。对象存储与堆中,局部变量存储在栈中。
- 生存时间;成员变量是对象的一部分,随着对象的创建而创建。局部变量随着方法调用生成,随方法效用结束而结束。
- 默认值:成员变量如果没有被赋初始值,会自动以类型的默认值赋值(例如boolen默认false,int默认0,string默认null)。局部变量不会自动赋值。
##静态变量
静态变量可以被类的所有实例共享。无论一个类创建了多少个对象,它们都共享同一份静态变量。
通常情况下,静态变量会被 final
关键字修饰成为常量。
##字符常量和字符串常量
- 形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。
- 含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。
- 占内存大小 : 字符常量只占 2 个字节; 字符串常量占若干个字节。
##静态方法为什么不能调用非静态成员
静态方法属于类,在类加载时被创建。非静态成员属于实例,当对象被实例化时候创建。
静态方法先于非静态成员创建。
##静态方法和实例方法区别
调用方式:静态方法通过类名.方法名
调用。实例方法通过对象.方法名
调用。
##重写和重载
重载
只能在同一个类中,方法名必须相同,参数类型、个数、顺序不同,方法返回值,访问修饰符可以不同。
重写
发生在运行时
- 方法名,参数列表必须相同,返回类型相同
- 如果父类访问修饰符为
private/final/static
则子类就不能重写该方法
#基本数据类型
##8 种数据类型
- 6 种数字类型
- 4 种整数型:
int\short\byte\long
- 2 种浮点型:
float\double
- 4 种整数型:
- 1 种字符类型:
char
- 1 种布尔型:
boolen
##默认值及所占空间大小
基本类型 | 位数 | 字节 | 默认值 | 取值范围 |
---|---|---|---|---|
byte | 8 | 1 | 0 | -128 ~ 127 |
short | 16 | 2 | 0 | -32768 ~ 32767 |
int | 32 | 4 | 0 | -2147483648 ~ 2147483647 |
long | 64 | 8 | 0L | -9223372036854775808 ~ 9223372036854775807 |
char | 16 | 2 | 'u0000' | 0 ~ 65535 |
float | 32 | 4 | 0f | 1.4E-45 ~ 3.4028235E38 |
double | 64 | 8 | 0d | 4.9E-324 ~ 1.7976931348623157E308 |
boolean | 1 | 1 | false | true、false |
long
类型需要在数值后加上L
,否则将作为整型解析
char a = 'h'
char :单引号,String a = "hello"
:双引号。
##基本类型和包装类型区别
- 基本类型的局部变量存放在栈中,基本类型的成员变量存放在堆中。包装类型属于对象,存放在堆中。
- 包装类型默认值为null。
- 包装类型可用于泛型,基本类型不可以。
##包装类型的缓存机制
Byte
,Short
,Integer
,Long
这 4 种包装类默认创建了数值 -128,127 的相应类型的缓存数据Character
创建了数值在 0,127 范围的缓存数据Boolean
直接返回True
orFalse
Float
,Double
没有缓存
如果定义新变量超出范围则会创建新的对象
##拆箱与装箱
- 装箱:将基本类型用它们对应的引用类型包装起来;
- 拆箱:将包装类型转换为基本数据类型;
##为什么浮点数运算会丢失精度
无限循环小数在计算机中保存是会被截断,导致小数精度丢失。
##如何解决浮点数精度丢失
使用BigDecimal
##超过lang
类型的数据如何表示
使用BigInteger
#面向对象基础
##面向对象和面向过程
- 面向过程:将问题解决过程拆解成一个个方法,通过一个个方法的执行解决问题。
- 面向对象:先抽出对象,用对象执行方法的方式解决问题。
##对象实体和对象引用
对象引用:对象的实例化
通过new创建对象实例(对象实例存放在堆中),对象引用指向对象实例(对象引用存放在栈中)。
一个对象引用可以指向0或1个对象。
一个对象可以有n个引用指向它。
##构造方法
完成对象的初始化,在实例化一个对象时,后面的括号说明调用的时无参构造方法。
如果没有声明构造方法,默认会有不带参构造方法。如果声明了有参构造方法,会覆盖默认无参构造方法,需要手动再次声明无参构造方法。
构造方法必须与类名相同,不可以重写,但可重载。
##面向对象的特性,封装、继承、多态
封装
封装是指将一个对象的属性,隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以通过一些允许被外部访问的方法来操作属性方法get(),set()
来操作属性。
继承
- 子类拥有父类所有的属性和方法,但是无法访问父类中私有属性和方法无法访问。
- 子类可以创建新的属性和方法,对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
多态
- 编译时多态:指方法的重载
- 运行时多态:程序中定义的对象引用所指向的具体类型在运行期间才确定
多态存在的条件:继承、重写、父类引用指向子类对象(例如:Animal a = new Cat()
)
##接口和抽象类
相同点:
- 不能被实例化
- 可以包含抽象方法
- 可以有默认的实现方法(使用default关键字在接口中定义默认方法)
不同点:
- 单继承,多实现
- 接口中成员变量只能是
public static final
类型的,且必须有初始值。抽象类的成员变量默认default,可以在子类中被重新定义,赋值。
##深拷贝、浅拷贝、引用拷贝
- 浅拷贝:会在堆上创建一个新的对象,如果原对象内部属性是引用类型的话,浅拷贝会直接地址内部对象的引用地址,即拷贝对象和原对象共用同一个内部对象。
- 深拷贝:完全复制整个对象,包括这个对象包含的内部对象。
- 引用拷贝:两个不同的引用指向同一个对象。
#String Object
##==和equals()区别
- == 判断引用是否指向堆内存的同一块地址
- equals 比较堆中的内容是否相同,不比较地址
##重写hashCode()必须重写equals()
因为不同对象的hashCode可能相同,但是hashCode不同的对象一定不相同
如果只重写一个,可能会出现equals相同但是hashCode不相同
使用HashSet时,先判断HashCode是否相同,如果相同再使用equals方法判断是否相同。
##String、StringBuffer、StringBuilder
StringBuffer
对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全。StringBuilder
没有对方法进行加同步锁,所以线程不安全。String
不可变(保存字符串的数组被final
修饰且为私有的),每次对String
类型进行改变的时候,都会生成一个新的String
对象,然后将指针指向新的String
对象。StringBuffer
每次都会对StringBuffer
对象本身进行操作,而不是生成新的对象并改变对象引用。
使用:
- 操作少量的数据: 适用
String
- 单线程操作字符串缓冲区下操作大量数据: 适用
StringBuilder
- 多线程操作字符串缓冲区下操作大量数据: 适用
StringBuffer
##字符串拼接不能使用+
如果使用+
拼接,实际上是通过StringBuilder
调用append()
方法实现,拼接之后调用toString()
得到String
对象。在循环体内使用+
拼接时,每循环一次就会创建一个StringBuilder
对象,如果手动使用StringBuilder
就不会有这个问题。
##String.equals()和 Object.equals()
String
中的equals
方法是被重写过的,比较的是 String 字符串的值是否相等。Object
的equals
方法是比较的对象的内存地址。
##字符串常量池
字符串常量池作用是避免重复创建String类导致内存消耗专门开辟的区域。
当创建一个String类型对象时,会将对象的内容保存到堆中,将对象的引用保存到常量池。再次创建相同的String对象时,如果堆中已经有相同的对象,则直接返回常量池中保存的引用。
##String s1 = new String("abc")会创建几个字符串对象
如果字符串 "abc"之前已经创建过了,则会创建 1 个字符串对象。如果字符串"abc"之前未创建,则会创建 2 个字符串对象
##intern 方法
intern 方法将指定的字符串对象的引用保存在字符串常量池
- 如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用。
- 如果字符串常量池中没有保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回。
##String 类型的变量和常量做“+”运算
- 如果是编译期可以确定值的字符串,JVM会将拼接后的字符串引用放入常量池。
例如:String str3 = "str" + "ing"
会优化成 String str3 = "string";
- 如果是编译期间无法确定的字符串,
StringBuilder
调用append()
之后在调用toString()
得到一个String
#异常
##Exception 和 Error
Java中主要由两种异常Exception 和 Error。
- Exception:程序本身可以处理的异常,可以通过catch捕获。Exception有分为Checked Exception受检查异常,必须处理 和 Unchecked Exception不受检查异常,可以不处理
- Error:程序无法处理的异常,出现Error会导致线程终止。例如Java虚拟机运行异常,内存溢出,堆栈溢出等。
#Checked Exception 和 Unchecked Exception
- Checked Exception 受检查异常,在编译过程中,如果检查出受检查异常没有被catch或者throws,编译将无法通过。
- 除了RuntimeException及其子类外,其他Exception都属于受检查异常。
- Unchecked Exception 不受检查异常,在编译过程中可以不处理。
- RuntimeException 及其子类都是不受检查异常,常见的有:空指针、数组越界等
##Throwable 类常用方法
getMessage()
返回异常的简要描述toString()
返回异常详细信息getLocalizedMessage()
返回异常对象本地化信息printStackTrace()
在控制台打印出 Throwable 对象封装的异常信息
#try-catch-finally使用
- try:用户捕获异常,后必须要接catch或者finally中一个
- catch:处理try捕获到的异常
- finally:无论是否捕获到或处理异常,finally都会被执行。如果try或者catch中有return,fianlly会在方法返回之前执行。
##fianlly是否一定会执行
不一定,如果fianlly之前JVM终止运行,fianlly就不会执行,后者程序所在的线程死亡,或者cpu关闭
#泛型
##泛型使用的方式
- 泛型类
- 泛型接口
- 泛型方法
#反射
##什么是反射
在程序运行过程中,动态获取一个对象所属的类,获取类的成员变量和方法,调用类的属性和方法
##什么地方用到了反射
spring通过注解@Component获取到类的信息,属性,参数等。
##如何使用反射获取一个类
- 通过
类名.class
Class alunbarClass = TargetObject.class;
- 通过
Class.forName(“类名”)
Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
- 通过方法
Object.getClass()
TargetObject o = new TargetObject(); Class alunbarClass2 = o.getClass();
- 通过类加载器
xxxClassLoader.loadClass()
传入类路径获取:ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
#注解
##什么是注解
可以修饰类、方法、变量,用于提供信息给程序编译或运行期间使用
##注解解析的方式
- 编译期间扫描
- 运行期间通过反射处理
#引用类型
通过引用类型来判断对象是否可以被垃圾回收器回收♻️
##强引用
通过new
关键字创建的对象,是强引用,强引用的对象不会被GC回收。
##软引用
软引用对象,会在内存不足时被回收。
通过SoftReference
关键字可以创建软引用对象
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
##弱引用
弱引用对象会被直接回收,创建的弱引用对象只能存活到下次GC发生之前。
可以通过WeakReference
关键字创建弱引用对象
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
##虚引用
不能通过虚引用获取一个对象,虚引用不会对对象产生任何影响。
虚引用的作用是:虚引用的对象被GC回收时可以收到一个通知。
可以通过PhantomReference
关键字创建需引用对象。
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);