Java学习笔记

Java

  • 1.1995年推出Java程序设计语言和Java平台(即JavaEE JavaME JavaSE)

  • 2.流行的Java开发环境:
    (1)Eclipse (2)Myeclipse (3)IntelliJIDEA (4)Jbuider (5)Jdeveloper (6)Netbeans (7)JCreator

  • 3.Java 虚拟机:称为JVM(Java Virtual Machine),Java运行环境又称为JRE(Java Runtime Environment)

  • 4.Eclipse是一个开放源代码、基于Java的可扩展开发平台,只是一个框架和一组服务,用于通过插件组件构建开发环境。附带标准插件集,包括Java开发工具(Java Development Kit,JDK)

  • 5.建立资源包要遵循MVC 结构规则(Model View Controller)


知识点

变量

  • char、short、byte不能相互转换,在运算时会自动转为int类型,由于JVM机制,此类变量无法直接相加
  • char/short/byte<int<long<float<double,小值转大值无需强制类型转换
  • 二进制自变量前加0b或0B可自动转为整形,数字可用”_”分割方便阅读(JDK7新特性)
  • 静态变量与成员变量区别
    • 静态变量属于类,也称类变量,成员变量属于对象,也称实例变量
    • 静态变量存储在方法区中的静态区,成员变量存储在堆内存中
    • 静态变量随类加载而加载,随着类消失而消失。成员变量随着对象创建而存在,随着对象消失而消失
    • 静态变量可以通过类名调用,成员变量只能通过对象名调用

  • 初始化过程
    • 属性、方法、构造方法和自由块都是类中的成员,在创建类的对象时,类中各成员的执行顺序:
      • 1.父类静态成员和静态初始化快,按在代码中出现的顺序依次执行。
      • 2.子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
      • 3.父类的实例成员和实例初始化块,按在代码中出现的顺序依次执行。
      • 4.执行父类的构造方法。
      • 5.子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
      • 6.执行子类的构造方法。
    • 分层初始化:先进行父类初始化,然后进行子类初始化。super()仅仅表示要先初始化父类数据,再初始化子类数据
  • Object类
    Object类是类层次结构的根类,所有类都直接或间接继承自该类

    • hashCode()
      返回对象的哈希码值,根据对象实际地址通过哈希算法得出,int类型。主要作用为提高哈希表性能。
    • getClass()
      返回此 Object 的运行时类,即字节码文件对象
    • toString()
      返回该对象的字符串表示,等同于 getClass().getName() + ‘@’ + Integer.toHexString(hashCode()),易读性较差,一般需要重写toString方法
    • equals(Object obj)
      默认判断对象地址值是否相等,注意当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
    • finalize()
      用于垃圾回收,System.gc()调用时finalize方法执行,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写 finalize 方法,以配置系统资源或执行其他清除
    • clone()
      创建并返回此对象的一个副本,开辟新内存空间,非引用原地址。重写clone方法时,被克隆的类需实现Cloneable接口,否则会抛出CloneNotSupportedException异常
    • notify()
      唤醒在此对象监视器上等待的单个线程,唤醒不代表立即执行,依然要抢CPU执行权
    • notifyAll()
      唤醒在此对象上等待的所有线程
    • wait()
      线程等待,notify后从此行开始继续向下执行代码

枚举

枚举允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示。定义枚举类要用关键字enum,所有枚举类都是Enum的子类。
注意:枚举类可以有构造器,但必须private;枚举类也可以有构造方法,但是枚举项必须重写该方法。

  • 格式
  1. 访问修饰符 enum 枚举名称
  2. {
  3. 枚举1,枚举2,枚举3,枚举4...枚举n //枚举序数依次为0/1/2/3....n-1
  4. }
  • 常用方法
    • ordinal:返回枚举序数
    • valueOf:返回指定名称、指定类型的枚举常量
    • name:返回枚举常量名称
    • compareTo:返回枚举序数的差值

位运算符

  • <<:空位补0,被移除的高位丢弃
  • >>:高位被移后,最高位符号不变
  • >>>:被移位二进制最高位强制用0补
  • &:二进制数按位进行与运算
  • |:二进制数按位进行或运算
  • ~:二进制数按位进行非运算(得到的数是补码)
  • ^:二进制数按位进行抑或运算(a^b^a,结果是b)

修饰符

  • 权限修饰符
位置 public protected default private
同一类中
同一包子类,无关类 ×
不同包子类 × ×
不同包无关类 × × ×
  • 类及其组成可用修饰符
    • 类:default,public,final,abstract (自定义public居多)
    • 成员变量:四种权限修饰符,final,static (自定义private居多)
    • 构造方法:四种权限修饰符 (自定义public居多)
    • 成员方法:四种权限修饰符,final,static,abstract (自定义public居多)

代码块

JAVA中用{}括起来的代码称为代码块,根据其位置不同可分为:

  • 局部代码块:局部位置,方法中出现,用于限定变量的生命周期,及早释放,提高内存利用率
  • 构造代码块:在类的成员位置,多个构造方法中相同代码存放在一起,每次调用构造都执行,并且在构造方法前执行
  • 静态代码块:近似于构造代码块,{前加static修饰,一般用于对类进行初始化
  • 同步代码块:synchronize(锁对象){….},用于实现多线程线程安全

异常

超类Throwable,程序异常分为Error、编译期异常和运行期异常(RuntimeException)。

  • Java异常分类
    • ①Error: 这种异常被设计成不被捕获,因为这种异常产生于JVM自身。
    • ②Runtime Exception: 运行时异常往往与环境有关,编译时无法检查,并且可能发生的情况太广泛,所以系统会去处理,程序不需要捕获。
    • ③普通异常(编译期异常): 常见的异常大多属于此类。
  • 常见异常
    • ArrayIndexOutOfBoundsException:数组索引越界异常
    • NullPointerException:空指针异常
    • ClassCastException:类转换异常(易出现于多态向下转型中)
    • CloneNotSupportedException:对象不支持克隆异常
    • ArithmeticException:算术异常
  • 处理方法

    • try…catch…finally:捕获异常,后续程序需要继续运行时使用。try里面的代码越精简越好,以免JVM浪费过多资源处理;catch内必须有内容,能明确的异常尽量明确,如果出现异常父子关系,父在后。
      1. try{
      2. 可能出现问题的代码;
      3. }catch(异常名1|异常名2|...|异常名n 变量){ //多个异常处理时,处理方法是一致的,而且多个异常间必须是平级关系(JDK7新特性)
      4. 针对问题的处理; //如果内有return语句,finally内部代码在return前执行
      5. }finall{ //finally控制的语句体一定会执行,用于释放资源,多见于IO流
      6. 释放资源;
      7. }
    • try-with-resources:java7新特性,这种在try后面加个括号,再初始化对象的语法就叫try-with-resources。判断对象是否为null,如果不为null,则调用close()函数的的字节码。
      注意:只有实现了java.lang.AutoCloseable接口,或者java.io.Closable(实际上继随自java.lang.AutoCloseable)接口的对象,才会自动调用其close()函数。

      1. try(实例化类1;实例化类2...){
      2. ...
      3. }catch(...){
      4. ...
      5. }finally{
      6. ...
      7. }
    • throws:抛出异常,后续程序不需要继续运行时使用。定义功能方法时,需要把问题抛出交由调用者处理,则通过throws在方法上标识

      1. throws 异常类名 //必须跟在方法的括号后面
throws和throw区别 区别
throws 用在方法声明后面,跟的是异常类名;
可以跟多个异常类名,用逗号隔开;
表示抛出异常,由该方法调用者处理;
throws表示出现异常的一种可能性,并不一定会发生
throw 用在方法内,跟的是异常对象名;
只能抛出一个异常对象名;
表示抛出异常,由方法体内的语句处理;
throw是抛出了异常,执行throw则一定抛出了某种异常
名称 区别
final 关键字,修饰类=>不能被继承、修饰变量=>常量、修饰方法=>不能被重写
finally 异常处理的一部分,被用于释放资源
finalize Object类的一个方法,用于垃圾回收
  • 常用方法
    • getMessage():异常的消息字符串
    • toString():返回异常的简单信息描述
    • printStackTrace():默认catch方法,将此 throwable 及其追踪输出至标准错误流。此方法将此 Throwable 对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值
  • 自定义异常
    • 自己想定义一个异常类,编译期异常需要继承自Exception、运行期异常继承自RuntimeException,注意重写父类异常构造方法
  • 注意事项
    • 子类重写父类方法时,子类方法必须抛出相同的异常或父类异常的子类
    • 如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是它的子集,子类不能抛出父类没有的异常
    • 如果被重写的方法没有抛出异常,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,只能try..catch…

方法

  • 构造方法
    与类名一致,创建对象时调用构造方法,可重载。子类无条件继承父类不带参数的构造方法,调用其他构造方法必须使用super关键字,子类不能重写父类构造方法。
  • 重写与重载
    Overloading与Overriding,重载发生在一个类中,重写发生在继承中
    构造方法用private修饰,即可实现单例模式,即该类无法创建对象,只能通过类调用static方法

    • 方法重载:同一个类中,出现的方法名相同、参数列表不同的方法,重载可以改变返回值类型,因为它和返回值无关
    • 方法重写:子类中出现的和父类一模一样的方法声明
      • 使用特点
        • 如果方法名不同,有就调用对应的方法
        • 如果方法名相同,最终使用的是子类自己的
      • 应用
        • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样既沿袭了父类的功能,又定义了子类特有的内容
      • 注意事项
        • 父类中私有方法不能被重写
        • 子类重写父类方法时,访问权限不能更低
        • 父类静态方法,子类也必须通过静态方法重写
  • 形式参数
    形式参数paramet,实际参数argument

    • 可变参数:当参数个数不确定时,可设置可变参数,最多设置一个。可变参数只能放置在参数的最后,即最右。编译器将可变参数当做一维数组对待,可使用foreach语句调用。
      格式例如:public void Function1(String str,String...arr){} // public void Function2(String...arr){}

内存分配

  • 栈:存储局部变量,创建类存储在栈内存,栈内存指向堆内存
  • 堆:存储成员变量,实例化对象开辟内存空间、存储在堆内存中(new出来的内容)
  • 方法区:
    • 静态域:存放在对象中用static定义的静态成员,堆栈具有动态特性。
    • class内容区域:存放类的定义,包含类内部的成员变量和成员方法的定义
    • 方法内容区域:存放构造方法和类内部方法
  • 本地方法区:和系统相关
  • 寄存器:给CPU使用

抽象类

  • 包含一个抽象方法的类就是抽象类,声明而未被实现的方法称为抽象方法,用abstract关键字声明。
  • 抽象类被子类继承,子类(如果不是抽象类)必须重写抽象类中的所有抽象方法。
  • 抽象类不能直接实例化,要通过其子类进行实例化。
  • 抽象类关键字abstract与private、final冲突,static无意义
    • 定义格式:
      1. abstract class className [extends 继承父类]
      2. {
      3. 属性;
      4. 方法;
      5. 抽象方法;
      6. }

接口

  • 接口是一种特殊的类,里面全部是由全局常量和公共的抽象方法组成。(成员变量默认修饰符:public static final,成员方法默认修饰符:public abstract)JDK8允许接口内使用default关键字和static关键字修饰方法并给出方法体,为接口添加非抽象的或静态的方法

  • 接口无构造方法(事实上调用接口时,extends Object类,子类默认重写Object无参构造方法//注:Object类是类层次结构的根类,每个类都使用Object类作为超类)

  • 接口实现必须通过子类,使用关键字implements,而且接口是可以多实现的。
  • 一个子类可以同时继承抽象类和实现接口。
  • 一个接口不能继承一个抽象类,但是却可以通过extends关键字同时继承多个接口,实现接口的多继承。
    • 接口格式:
      1. interface interfaceName [implements 继承接口]
      2. {
      3. 全局常量;
      4. 抽象方法;
      5. }
  • 抽象类与接口的区别
区别 成员区别 关系区别 设计理念区别
抽象类 成员变量可以是常量,也可以是变量
有构造方法
成员方法可以抽象,也可以非抽象
类与类:继承,单继承 被继承体现的是“is A”的关系
定义该继承体系的共性功能
接口 成员变量只能是常量
无构造方法
成员方法只能是抽象
类与接口:实现,单实现,多实现
接口与接口:继承,单继承,多继承
被实现体现的是“like A”的关系
定义该继承体系的扩展功能

OOP特性

封装性

  • 类下面属性使用private等关键字封装,通过使用属性调用(快速方法:右键Source→Generate Setter&Getter)
  • 匿名对象使用:程序只用一次该对象,可利用匿名对象的方式,无需实例化,直接new调用。有利于GC(garbage collection垃圾回收)

继承性

  • Java内使用extends关键字继承已有类。
  • Java中只允许单继承(可以多层继承),子类无法访问父类私有成员,只能继承父类所有非私有的成员方法和成员变量
  • 子类调用构造方法之前,先调用父类中的无参构造方法
  • 子类不能继承父类的构造方法,父类无无参构造方法不能调用,可利用super关键字调用父类方法(super代表父类存储空间的标识),可利用this调用本类其他构造方法
  • 注意事项:super、this调用构造方法时必须置于第一行
  • 方法重写:子类定义与父类同名的方法。定义:方法名称相同,返回值类型相同,参数也相同。限制:子类重写父类方法时,访问权限不能低于父类权限(private<default<public),权限最好一致
  • 继承优缺点:
    • 优点
      • 提高代码复用性,多个类相同的成员可以放到同一个类中
      • 提高代码维护性,如果功能的代码需要修改,修改一处即可
      • 类与类之间产生关系,是多态的前提(同时也是弊端:类的耦合性变强)
    • 缺点
      • 开发的原则在于低耦合、高内聚,尽可能单独处理任务

多态性

  • 实现:方法的重载和重写、对象的多态性。
  • 对象的多态性:
    • 向上转型:程序自动完成(父类 父类对象=子类实例
    • 向下转型:强制类型转换(子类 子类对象=(子类)父类实例)
  • 前提:要有继承关系,要有方法重写,要有父类引用指向子类对象。
  • 多态中的成员访问特点
    • 成员变量:编译看左边,运行看左边
    • 构造方法:创建子类对象时,访问父类构造方法,对父类数据进行初始化
    • 成员方法:编译看左边,运行看右边(成员方法由于重写,运行看右边)
    • 静态方法:编译看左边,运行看左边(静态和类相关,算不上重写)

内部类

把类定义在其他类的内部,这个类就是内部类

  • 内部类的访问特点
    • 内部类可以直接访问外部类成员,包括私有
    • 外部类要访问内部类成员,必须创建对象
    • 内部类和外部类没有继承关系,内部类如想调用外部类成员,需通过外部类名限定this对象(即通过外部类名.this.成员变量调用)
  • 内部类划分
    • 根据位置划分
      • 成员内部类:定义在成员位置
        创建对象:外部类名.内部类名 对象名=new 外部类对象.new 内部类对象
      • 局部内部类:也叫方法内部类,定义在局部位置,可直接访问外部类成员,通过调用内部类方法来使用局部内部类功能
        局部内部类访问局部变量必须被final修饰,因为局部变量会随着方法调用完毕而消失,而堆内存内容并不会立即消失,final修饰后变量变为常量
  • 静态内部类
    用static将内部类静态化,内部类只能访问外部类的静态成员变量。
    内部类被静态化,可以看做是外部类的成员,因此内部外部可以当做一个整体看,可以直接new 出内部类的对象(通过类名访问static,生不生成外部类对象都没关系)
    创建对象:外部类名.内部类名 对象名=new 外部类名.内部类名
  • 私有内部类
    如果一个内部类只希望被外部类中的方法操作,那么可以使用private声明内部类。
  • 匿名内部类
    即内部类的简化写法

    • 前提:存在一个类或者接口
    • 格式:new 类名或接口名(){重写方法;};
    • 本质:是一个继承了类或者实现了接口的子类匿名对象
    • 应用:无需实例化新的对象,只能用一次,便于内存回收
  • Lambda表达式
    • 介绍:与匿名类概念相比较,Lambda 其实就是匿名方法,是一种把方法作为参数进行传递的编程思想。匿名类型最大的问题就在于其冗余的语法
    • 语法:由参数列表、箭头符号->和函数体组成。函数体既可以是一个表达式,也可以是一个语句块。
      格式:(T args) -> { //代码块 }

      • 参数:(T args)是这个lambda expression的参数部分,包括参数类型和参数名,可为空,小括号不可缺少
      • 箭头:->,不可缺少
      • 代码块:就是用”{}”包含着的代码。当代码块内代码只有一行时,花括号可以省略,且代码块内分号省略

泛型(Generic)

  • 格式:
    1. 访问权限 class 类名<泛型,泛型...>
    2. {
    3. 属性;
    4. 方法;
    5. }
  • 实例化:
    类名<具体类型> 对象名=new 类名<具体类型> ();
    方法参数使用通配符“?”指定泛型。

    • 泛型接口:interface 接口名称<泛型标识>{……}

    • 泛型方法:访问权限 <泛型标识>泛型标识 方法名称([泛型标识 参数名称]){……}

多线程

线程:程序中单独顺序的控制流,本身依靠程序运行,只能分配给程序的资源和环境
进程:执行中的程序,一个进程可以包含一个或多个线程,至少要包含一个线程
单线程:程序中只存在一个线程,实际上主方法就是一个主线程
多线程:在一个程序中运行多个任务,更好使用CPU资源

  • ①线程实现方式:继承Thread类;实现Runnable接口
    • Thread类:在java.lang包中定义,继承Thread类必须重写run()方法
      • 定义格式:
        1. class ClassName extends Thread
        2. {
        3. run(){......}
        4. }
    • Runnable接口:同Thread,调用接口方式,同样需要覆写run()方法
    • Callable接口:Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
      • 同Runnable区别
        • Callable规定的方法是call(),Runnable规定的方法是run().
        • Callable的任务执行后可返回值,而Runnable的任务是不能返回值
        • call方法可以抛出异常,run方法不可以
    • Future接口
      通过线程池ExecutorService运行submit方法可以拿到一个Future对象,Future 表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。Future的cancel方法可以取消任务的执行,它有一布尔参数,参数为 true 表示立即中断任务的执行,参数为 false 表示允许正在运行的任务运行完成。Future的 get 方法等待计算完成,获取计算结果
  • ②线程的状态
    线程具有固定的操作状态
    创建状态:准备好了一个多线程对象
    就绪状态:调用start()方法,等待CPU进行调度
    运行状态:执行run()方法
    阻塞状态:暂时停止执行,可能将资源交给其他线程使用
    终止状态:也称为死亡状态,线程销毁
  • ③线程常用方法
    • getName():取得线程名称
    • currentThread():取得当前线程对象
    • isAlive():判断线程是否启动
    • join():线程的强制运行
    • sleep():线程的休眠
    • yield():线程的礼让,Thread.yield(),即满足某一条件后,线程不在执行,切换其他线程运行
  • ④线程优先级:通过Thread.setPriority 设置优先级
  • ⑤线程同步与死锁

    • 同步前提:多个线程,且使用同一锁对象,能够解决多线程安全问题。弊端在于线程相当多时耗费资源,降低程序运行效率。
    • 原子性操作:即不可中断的操作,比如赋值操作。原子性操作本身是线程安全的。
      • java.util.concurrent.atomic包:JDK6新增,里面有各种原子类,比如AtomicInteger。而AtomicInteger提供了各种自增,自减等方法,这些方法都是原子性的(i++、i–不是原子性操作)。 换句话说,自增方法 incrementAndGet 是线程安全的,同一个时间,只有一个线程可以调用这个方法。
    • 同步代码块:在代码块上加上“synchronized“关键字,则此代码块就称为同步代码块(方法也可以同步),资源共享的时候需要使用同步
      格式:

      1. synchronize(锁对象)
      2. {
      3. 需要同步的代码块;
      4. }
    • 锁对象
      同步代码块的锁对象:任意对象
      同步方法的锁对象:this
      静态方法的锁对象:当前类的.class文件

    • Lock锁:近似于同步代码块,通过Lock.lock()、Lock.unlock()方法加锁、释放锁,通常使用try…final…完成锁

  • ⑥线程的生命周期

  • ⑦线程组

    • 把多个线程组合到一起,可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制
    • 通过ThreadGroup类设置线程组,常用方法:
      • getName():获取线程组名称
      • setDaemon():设置后台线程,true表示改组的线程都是后台线程、守护线程
      • destroy():销毁线程组
  • ⑧线程池

    • 程序启动新线程成本较高,因为涉及与操作系统的交互。使用线程池可以很好的提高性能,尤其当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
    • Executors类定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
    • Java通过Executors工厂类提供四种线程池,返回ExecutorService接口,分别为:
      • newCachedThreadPool
        创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
      • newFixedThreadPool
        创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
      • newScheduledThreadPool
        创建一个定长线程池,支持定时及周期性任务执行。
      • newSingleThreadExecutor
        创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

反射

  • 类的加载:当程序要使用某个类时,如该类尚未加载到内存中,则系统会通过加载、连接、初始化三步来实现对这个类的初始化
    • 加载:就是将class文件读入内存,并为之创建一个Class对象。任何类使用时系统都会建立一个Class对象。
    • 连接
      • 验证:是否有正确的内部结构,并和其他类协调一致。
      • 准备:负责为类的静态成员分配内存,并设置默认初始化值。
      • 解析:将类的二进制数据中的符号引用替换为直接饮用。
    • 初始化:即Java中类的初始化步骤。
      初始化时机:

      • 创建类的实例
      • 调用类的静态方法
      • 使用反射方式强制创建某个类或接口对应的Class对象
      • 初始化某个类的子类
      • 直接使用java.exe命令来运行某个主类
  • 反射:JAVA反射机制是在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法;对于任何一个对象,都能调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能成为JAVA语言的反射机制。所以必须要获取到该类的字节码文件,首先就要获取每一个字节码文件对应的Class类型的对象。
    • 获取Class方式
      • Object类中的getClass方法
      • 数据类型的静态属性class
      • Class类中的静态方法 forName(string ClassName)注:ClassName要写全路径,即package.ClassName
    • Class类方法
      • getConstructors:返回所有公有构造方法,Constructor类的数组形式。
      • getDeclaredConstructors:返回所有构造方法
      • getField/getDeclaredField:返回成员变量,Field类。通过Field类中set方法可以设置变量值。
      • getMethod/getDeclaredMethod:返回方法,Method类。通过Method类中inovke方法调用,invoke第一个参数传对象,后面的参数传方法参数。
    • Constructor类方法
      • newInstance:创建新实例
      • setAccessible(boolean):参数为布尔值,值为true时暴力访问,指示反射的对象在使用时取消Java语言访问检查,即无视访问修饰符存在。
  • 动态代理:在程序运行过程中产生代理对象,通过反射生成(通过java.lang.reflect包下Proxy类和InvocationHandler接口实现)。JDK提供的代理只能针对接口做代理,cglib提供更强大代理。
    • Proxy类:使用newProxyInstance方法生成代理后的对象
    • InvocationHandler接口:使用invoke(Object proxy, Method method, Object[] args)方法生成代理对象

注解

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

  • 作用分类:
    • 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
    • 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
    • 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

基本内置注解

  • @Override
    用在方法上,表示这个方法重写了父类的方法,如toString()。如果父类没有这个方法,那么就无法编译通过

  • @Deprecated
    表示这个方法以及过期,不建议开发者使用。

  • @SuppressWarnings
    这个注解的用处是忽略警告信息。有常见的值,分别对应如下意思:

    1. deprecation:使用了不赞成使用的类或方法时的警告(使用@ Deprecated使得编译器产生的警告);
    2. unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
    3. fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
    4. path:在类路径、源文件路径等中有不存在的路径时的警告;
    5. serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
    6. finally:任何 finally 子句不能正常完成时的警告;
    7. rawtypes 泛型类型未指明
    8. unused 引用定义了,但是没有被使用
    9. all:关于以上所有情况的警告。
  • @SafeVarargs
    只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。使用前提是开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

  • @Functionallterface
    是Java1.8 新增的注解,用于约定函数式接口。
    函数式接口概念: 如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。函数式接口其存在的意义,主要是配合Lambda 表达式 来使用。

自定义注解

  • 创建注解
    创建注解类型的时候即不使用class也不使用interface,而是使用@interface
    如:public @interface JDBCConfig

  • 元注解

    • @Target
      说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

      • 作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
      • 取值:
        1. 1.CONSTRUCTOR:用于描述构造器
        2. 2.FIELD:用于描述域
        3. 3.LOCAL_VARIABLE:用于描述局部变量
        4. 4.METHOD:用于描述方法
        5. 5.PACKAGE:用于描述包
        6. 6.PARAMETER:用于描述参数
        7. 7.TYPE:用于描述类、接口(包括注解类型) enum声明
    • @Retention(RetentionPolicy.RUNTIME)
      定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

      • 作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
      • 取值:
        1. 1.SOURCE:在源文件中有效(即源文件保留)
        2. 2.CLASS:在class文件中有效(即class保留)
        3. 3.RUNTIME:在运行时有效(即运行时保留)
    • @Inherited
      阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

    • @Documented
      用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

  • 注解解析
    用自定义注解把目标类改造为注解方式类,通过反射Object.class.getAnnotation(自定义注解.class);获取注解方式类的注解对象
    通过调用注解对象的内部方法获取各个注解元素的值


关键字

  • this关键字

    1. 表示类中的属性和调用方法
    2. 调用本类中的构造方法(必须放在首行
    3. 表示当前对象
  • static关键字

    1. 使用static声明全局属性
    2. 使用static声明方法,直接通过类名调用
    3. 使用static方法,只能访问static声明的成员变量和方法,而非static声明的属性和方法是不能访问的
    4. 静态方法中没有this关键字,因为静态随着类加载而加载,this是随着对象创建而存在的
  • super关键字
    代表父类存储空间的标识,强行调用父类构造方法执行,可用于方法重写,也可以表示哪些方法是由父类中继承而来。

  • final关键字

    • 被称为完结器,表示最终。能声明类、方法、属性。
    • 使用final声明的类不能被继承,声明的方法不能被重写,声明的变量变为常量,不能被修改。
    • 初始化时机:final修饰的变量只能赋值一次,在构造方法完毕前赋值
    • final修饰局部变量时,如果是基本类型,值不能改变;如果是引用类型,地址值不能改变,但对象内容可以改变
  • instanceof关键字
    用于判断某对象是否由某类实例化,返回Boolean值

  • package关键字
    用来定义包。
    注意事项:

    • package语句必须是程序的第一条可执行代码
    • package语句在一个JAVA文件中只能有一个
    • 如果没有package,表示默认无包名
  1. package 包名;//多级包用.分开即可
  • transient关键字
    变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。

  • import关键字
    用来导入包。
    注意事项:

    • 这种方式导入是到类的名称
    • 虽然可以最后写*,但是不建议
    • 顺序:package>import>class,package只能有一个,import可以有多个,class可以有多个但是建议一个
  1. import 包名;

常用语句

  1. syso –>System.out.println(); 控制台输出 System.in输入(实例Scanner类),System.err.println()优先级更高,一般用于调试
  2. switch语句内表达式可以传入 int short char byte、枚举、String;case下如果不加break可能会发生switch穿透,即顺延下个case
  3. ‘\t’ tab键 ‘\r 回车键 ‘\n’ 换行键(不同系统下换行符不同,Windows:\r\n,Linux:\n,Mac:\r)

Eclipse常用快捷键

  1. ctrl+shift+F 重新格式化
  2. alt+shift+S弹出Source快捷菜单
  3. ctrl+1快速修复
  4. alt+shift+M 提炼方法,抽取一段代码生成新的方法
  5. alt+shift+R 重命名方法名、属性或者变量名
  6. /**+ENTER 生成Java Doc,方法前操作可添加参数说明。
  7. ctrl+shift+O/M 组织包/导入包

编程习惯

  • JavaDoc格式
    生成JavaDoc后,@para 表示传入参数,@return表示返回值,@author 表示作者,@version 表示版本号

    • 格式:cmd命令: javadoc -d 目录 -author -version 程序名称.java
    • 使用Eclipse生成JavaDoc出现乱码错误时,在VM Option选项下加入:“-encoding utf-8 -charset utf-8”(以UTF-8为例)
  • Package作用
    把相同的类名放在不同的包下,对类进行分类管理。分类方法:①按照功能分 ②按照模块分
    带包的编译和运行:

    • 手动式
    1. 编写一个带包的Java文件
    2. 通过Javac命令编译该Java文件
    3. 手动创建包名
    4. 把2步骤的class文件放到c步骤的最底层包
    5. 回到和包根目录在同一目录的地方,然后运行(带包运行)
    • 自动式
    1. Javac编译的时候带上 -d . 即可
      如:javac -d . HelloWorld.java
    2. 通过java命令执行,和手动式一样

常见问题

  • 命令行窗口下,Java执行class报出“找不到或无法加载主类”,环境变量配置无误,出错原因可能为:
    • package路径不正确,class文件没有严格按照package路径存放
    • 命令行执行java命令时,class文件不要加.class后缀

发表评论

电子邮件地址不会被公开。 必填项已用*标注