Java基础
JVM、JDK、JRE
JVM是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现,目的是使用相同的字节码,它们都会给出相同的结果。
JDK是功能齐全的Java SDK,它能够创建和编译程序。
JRE是Java运行时环境,它不能用于创建新程序。
8种基本数据类型
- 6种数据类型
- 4种整型:byte「1B」、short「2B」、int「4B」、long「8B」
- 2种浮点型:float「4B」、double「8B」
- 1种字符类型:char「2B」
- 1种布尔型:boolean「1B」
基本类型和包装类型
- 成员变量包装类型不赋值就是
null
,基本类型有默认值且不是null
- 包装类型可用于泛型,而基本类型不可以
- 基本数据类型的局部变量存放在虚拟机栈中,基本数据的成员变量「未被static修饰存放在虚拟机堆中。包装类型属于对象,对象实例都存在堆中
面向对象三大特征
封装、继承、多态
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
- 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
多态,顾名思义,表示一个对象拥有多种的状态,具体表现为父类的引用指向子类的实例。
- 多态不能调用「只在子类存在但在父类不存在」的方法
深拷贝和浅拷贝
- 浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
- 深拷贝 :深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
重写equals()和hashCode()
因为两个相等的对象的 hashCode
值必须是相等。也就是说如果 equals
方法判断两个对象是相等的,那这两个对象的 hashCode
值也要相等。
如果重写 equals()
时没有重写 hashCode()
方法的话就可能会导致 equals
方法判断是相等的两个对象,hashCode
值却不相等。如果在HashMap
中,这可能会导致出现重复的键值对。
字符串
- 线程安全
- String中的对象是不可变的,可以理解为常量,线程安全
- StringBuffer加了同步锁,是线程安全的
- StringBuilder不是线程安全的
- 性能
- 每次对
String
类型进行改变的时候,都会生成一个新的String
对象,然后将指针指向新的String
对象 - StringBuilder比StringBuffer快一点
- 每次对
equals()
String
中的 equals
方法是被重写过的,比较的是 String 字符串的值是否相等。 Object
的 equals
方法是比较的对象的内存地址
字符串常量池
字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
try-catch-finally
不要在 finally 语句块中使用 return! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。
面对必须要关闭的资源,总是应该优先使用try-with-resources
而不是try-finally
。例如InputStream
、OutputStream
、Scanner
等资源。
try-catch-finally
1 | //读取文本文件的内容 |
try-with-resources
1 | try (Scanner scanner = new Scanner(new File("test.txt"))) { |
当然也可以使用分号分割,在try-with-resources
块中声明多个资源。
反射
什么是反射
反射赋予了我们在运行时分析类以及执行类中方法的能力。通过反射,可以获取任意一个类的所有属性和方法,还可以调用这些方法和属性。比如注解的实现也依赖于反射。
- 优点:让代码更加灵活、为各种框架提供了便利
- 缺点:增加了安全问题,另外反射的性能也稍微差点
反射实战
假设TargetObject
是要使用反射操作的类
1 | package cn.javaguide; |
使用反射操作这个类的方法以及参数
1 | package cn.javaguide; |
重载和重写的区别
重载是指在同一个类中,方法名相同,但参数列表不同的多个方法。重载方法必须有不同的参数列表,可以有不同的返回类型和访问修饰符。重载方法可以被认为是一个新方法,只是与原来的方法名相同而已。
重写是指子类重新定义父类中已有的方法。重写方法必须有相同的名称、参数列表和返回类型。
抽象类和接口的区别
在Java中,抽象类和接口都是用于实现多态的机制。抽象类是对一种事物的抽象,而接口是对行为的抽象。
- 一个类只能继承一个抽象类,但是可以实现多个接口
- 接口只包含常量和抽象方法;抽象类可以包含抽象方法和非抽象方法
什么是泛型
Java泛型是JDK5中新引入的一个新特性。使用泛型参数,可以增强代码的可读性以及稳定性。
编译器可以对泛型参数进行检测,并且通过泛型参数可以指定传入的对象类型。比如ArrayList<User> a = new ArrayList<User>()
这行代码就指明必须传入User
对象,传入其他类型的对象就会报错。
并且,原生 List
返回类型是 Object
,需要手动转换类型才能使用,使用泛型后编译器自动转换。
泛型类
1 | public class Test<T> { |
泛型接口
1 | public interface Test<T> { |
泛型方法
1 | public void print(T[] array) { |
注解
注解是一种元数据,可以将它理解为一种特殊的注释。它为我们在代码中添加信息提供了一种形式化的方法,它用于帮助我们更快捷的写代码。主要有四个作用:
- 生成文档:即将元数据生成为Javadoc文档
- 编译检查:编译器在编译阶段会对代码进行检查,例如@override会提示编译器查看是否重写了父类的方法
- 编译动态处理:主要用作动态生成代码,例如一些帮助类、方法,通过注解实现自动生成
- 运行动态处理:典型的例子是通过反射来注入实例
在实际的项目开发中见到的注解一般是来自 Java 自带的注解、元注解「修饰注解的注解,最基准的注解」、Spring 等框架的注解
参考文章:JavaGuide