Java的几大关键特性:
- 面向对象
- 健壮性:
程序失败的两个主要原因:内存管理错误和未处理的异常(即运行时错误)。java采用了自动内存管理,并且提供了面向对象的异常处理功能。 - 多线程
- 体系结构中立:java虚拟机
- 解释执行和高性能:源代码->字节码->高性能的本机代码
OOP三原则:
- 封装:将代码和数据绑定在一起的机制,并保证代码和数据既不会受到外部的干扰,也不会被误用。封装的基础是类(Class)。
- 继承:一个对象获取另一个对象属性的过程。
- 多态:一个接口,多个方法。具体使用哪个方法和场景有关。
Java基本类型
- 整型:byte(1字节)、 short(2)、 int(4)、 log(8) -> 有符号
- 浮点型:float(4)、 double(8) -> 有符号
- 字符型:char(2)->无负值
- 布尔型:boolean(1) -> true/false
Java类型转换
- 自动类型转化:两种类型是兼容 & 目标类型大于源类型
- 强制类型转换
Java表达式中的自动类型提升,规则
- 所有byte、short和char类型的值被提升为int
- 如果有一个long,整个表达式提升为long
- 如果有一个float,整个表达式提升为float
- 如果有一个double,整个表达式提升为double
java数组
- 类型相同
- 一维或者多维
java主要的运算符
- 基本算术运算符:+、-、 *、 /
- 求模运算符: %
- 自增与自减运算符:++、 –
- 位运算符:
- 位逻辑运算符:& 、|、 ^、 ~
- 左/右移: << 、>>
- 关系运算符 <、 >、 <=、 >=、 !=
- 位运算: ? :
java的语句
- 选择语句
- if:if else; 可嵌套
- switch: 表达式可以是: byte、short、int、char、enum、 String
- 迭代语句
-
for
- 普通版本: for(int i = 0; i < 1-; i++)
- for each:for(int a: nums)
-
while
-
do while:至少执行一次循环体
-
- 跳转语句
- break:跳出本层的全部迭代
- continue: 终止一次迭代
- return:返回,方法结束
Java类
- 类定义了一种新的数据类型
- new运算符在运行时为对象分配内存
- 为对象引用变量赋值,这两个对象指向同一块内存空间。当一个对象引用变量赋值给另一个对象引用变量时,不是创建对象的副本,而是创建引用的副本。
- 方法重载:根据参数类型,个数。当没有找到准备的匹配时,Java会使用自动类型转换
- 基本类型使用值传递;对象是引用传递
- 访问控制:private、默认、protected、public
- static:静态。可以修饰变量、代码块、方法。静态代码块只执行一次,在第一次加载类的时候执行,
- final:必须初始化。要么在声明一个变量时提供一个值,要么在构造函数中为其赋值。final可以修饰变量、方法、类。
- 嵌套类和内部类。内部类可以访问外部类的所有成员,但是反过来不可以。
- String类:String类型的对象是不可变的。
继承
- extends
- 成员访问与继承:子类包含超类的所有成员,但是子类不能访问超类的私有成员。
- 超类变量可以引用子类对象。但是此时的parent只能访问父类定义的那些值。
ParentBox parent = new ParentBox();
ChildBox child = new ChildBox();
parent = child;
- super
- 调用超类的构造函数,必须是子类构造函数的第一条语句。
- 访问超类中和子类中的同名成员
- 构造函数的调用时机:先超类,后子类。因此super()必须在构造函数的第一行
- 方法重写:多态的基础。子类调用子类的版本,超类定义的版本会被隐藏
- 动态方法调度:在运行时解析对重写方法的调度
- 抽象类:abstract。包含一个或多个抽象方法的类。不能直接new,但是可以创建引用
- final
- 修饰变量值,一旦赋值,后续不能修改
- 修饰方法,不能重写
- 修饰class,不能继承
- Object:所有类的超类。数组也是作为类实现的,所以Object类型的变量也可以引用任何数组
包和接口
- package是多个类的容器,保持类的名称空间相互隔离。减少命名冲突
- Java运行时如何查找包
- 默认情况,Java运行时系统使用当前的工作目录作为起始点
- 其次,可以通过ClassPath环境变量来制定目录或者路径
- java运行时,-classpath选项
- 接口: interface
- 从java 8开始,可以在接口方法中添加默认的实现
default String getString() { return "default string". }
- 对性能要求苛刻的代码中,不要随意使用接口,会增加负担
- 如果累包含了一个接口,但是没有实现该借口定义的全部方法,则必须将类声明为abstract
- 类和接口关键的区别:类可以维护状态信息(通过使用实例变量),而接口不可以
- JDK 8之后,接口可以定义一个或者多个静态方法
异常处理
- 5个关键字:try, catch, throw, throws, finally
- Throwable的子类: error和exception。runtimeException是exception的重要子类
- throws子句列出了方法可能抛出的异常类型,除了error和runtime exception及其子类的异常之外,对于所有其他类型的异常都是必须在throws子句中进行声明
- finally:不管是抛出异常,还是显示return,都会在方法返回之前执行finally语句
- Java的内置异常,必须在throws中包含的异常,称之为经验查的异常。例如classNotFoundException,IllegalAccessException, NoSuchMethodException
- 链式异常:可以为异常关联另一个异常。处理多层异常
多线程编程
-
线程是可调度的最小单元
-
线程的五种状态:新建、就绪、运行、阻塞、死亡
-
-
线程的优先级
- 优先级是一些整数,绝对值没有意义,今比较大小
- setPriority() 设置优先级
- 抢占式和非抢占式
- 抢占式:只要高优先级线程希望运行,则会取代低优先级线程
- 非抢占式:当线程资源放弃控制,从准备运行的线程中挑选高优先级线程,使其运行。
- 优先级相同的线程,一般是以循环方式自动获取CPU资源
-
线程同步
- 同步:当两个或多个线程需要访问共享的资源时,确保每次只有一个线程使用资源
- 同步的关键是监视器。Java每个对象都有自己的隐式监视器,给定的时刻,只有一个线程可以拥有监视器。当线程取得锁时,就进去了监视器
- synchronized方法;synchronized对象
-
线程通信:
- 为了避免轮询检查,java通过wait() notify() notifyAll()方法,来进行线程间通信
- 这3个方法都只能在同步上下文中调用
- wait()通知调用线程放弃监视器并进入休眠,直到其他一些线程进入同一个监视器并调用notify方法
- notify()方法唤醒调用相同对象的wait()方法的线程
- notifyAll()唤醒调用相同对象的wait()方法的所有线程,其中一个线程将会得到访问授权
-
主线程:
- 其他子线程都是从主线程产生的,主线程最后结束
- isAlive(), 如果线程还在运行,则return true
- join(),该方法一直等待,直到调用线程终止。
- 通过currentThread()获取对主线程的一个引用,从而控制主线程
- 其他子线程都是从主线程产生的,主线程最后结束
-
创建线程
- 继承Thread类
- 扩展Runnable接口
枚举、自动装箱和注解(元数据)
- 枚举类
- enum Apple
- 每个枚举常量被隐式声明为公有、静态、final成员
- 枚举类不能实例化,每个枚举常量都是所属枚举类型的对象;如果为枚举类定一个构造函数,则创建每个枚举常量时都会调用该构造函数。
- 枚举类自动包含两个预定义的方法:value()、 valueOf()
- value() 方法返回一个包含枚举常量列表的数组
- valueOf(str) 返回str字符串相对应的枚举常量
- 类型封装器
- Character是char类型的封装器
- Boolean封装器
- 数值类型封装器:Integer、Double、Long、Float、Short、Byte
- 自动装箱和自动拆箱
- 自动装箱:需要基本类型的对象时,自动将基本类型自动封装到与之等价的类型封装器中
- 自动拆箱:需要时自动抽取对象数值的过程。
- 注解(annotation)
- 注解是基于接口创建的,所有的注解都自动扩展Annotation接口
- 声明注解:
@interface MyAnno { String str(); int val(); }
- 类、方法、域变量、参数以及枚举常量都可以带有注解
- 使用注解: @MyAnno(str = “xxx”, val = 100) public static void myMeth() {}
- 保留策略,通过@Retention指定
- SOURCE:只在源文件中保留,编译期间会被抛弃
- CLASS:在编译时被存到了.class文件,但是在运行时,无法得到
- RUNTIME: 在编译时被存到了.class文件,并且在运行时,可以通过JVM获取注解
- 在运行时通过反射获取注解:getAnnotation()
- 注解的一些限制
- 一个注解不能继承另一个注解
- 注解声明的所有方法都不带参数,且不能返回一下类型的值
- 基本类型
- String或者Class类型的对象
- 枚举类型
- 其他注解类型
- 上述类型的数组
- 注解方法不能指定throws子句
I/O
- 字节流:为处理字节的输入/输出提供了方法
- InputStream和OutputStream
- 字符流:为处理字符的输入/输出提供了方法,使用Unicode编码,可以被国际化
- Reader和Writer
- 读写文件
- FileInputStream、FileOutputStream
- 可能会抛出异常,需要try catch,在finally中close文件
- 自动资源管理, 使用局部变量,try catch结束时,隐式调用close,关闭流
try (FileInputStream fin = new FileInputString(xxx)) { xxx } catch { }
其他
- transient: 当存储对象时,不需要永久保存这个值
- volatile:可见性,即修改的值,其他线程立马可见。
- instanceof:运行时知道对象的类型
泛型
- 泛型:参数化类型
- 必须是引用类型
- sample:
Class Stats <T extends Number> {}
- 通配符
- 擦除:java使用擦除实现泛型。即在编译时,替换为界定的类型或者object
- 使用泛型的限制:
- 不能创建类型参数的实例,例如 new T()
- 静态成员不能使用在类中声明的类型参数,static T
- 不能实例化元素类型为类型参数的数组。T vals[] = new T[10];
- 不能创建特定类型的泛型引用数组.
Class Gen<T extends Number> Gen<Integer> gens[] = new Gen<Integer>[10];
- 泛型类不能扩展Throwable,即不能创建泛型异常类
Lambda表达式
- Lambda表达式(毕包):本质是一个匿名方法。会产生一个匿名类
- 函数式接口:通常表示单个动作,仅包含一个抽象方法的接口
- 两部分:()->{}
- 左侧:指定表达式需要的所有参数
- 右侧:指定lambda体
- eg: () -> 123.45 n-> (n % 2) == 0
- eg: (n) -> {}
interface NumberTest {
boolean test(int a, int b);
}
NumberTest nt = (n,m) -> (n%m) == 0;
if (nm.test(10,2)) {
return true;
}