JavaSE | 接口| 枚举| 注释| 异常

包:

1、包的作用:
(1)避免类的同名(区分类);类的全名称:包.类名

回忆:java.util.Scanner
java.util.Arrays
java.lang.String
j
(2)可以限定某些类或成员的可见范围;(权限)
如果某个类或成员省略了权限修饰符,它的可见范围是本包

(3)用于组织管理项目中众多的类

2、包的声明的格式:package 包名;

声明的要求:
(1)这句package语句必须在“源文件”代码的首行
(2)包名:A:所有单词都小写,每一个单词之间使用.分割;  B:一般习惯上用公司的域名倒置加模块名 com.atguigu.xxx;

3、
编译:javac 源文件名.java;       ----->>>   编译:javac -d . 源文件名.java
运行:java 类名                           ----->>>   运行:java 包.类名

-d:directory文件夹,目录; .:表示当前目录

4、如何使用其他的包?  前提:被使用的类必须是可见的
(1)使用类的全名称
(2)使用import语句先导包,然后使用类的简名称;   import 包.类名;

  特殊情况:要使用的两个类同名,包名不一样;那就一个导包用简名称,一个使用全名称

* 导包:
* (1)import 包.类名;
* (2)import 包.*;
* (3)import static 包.类名.静态成员;
* (4)import static 包.类名.*;

* (3)(4)就是静态导入,JDK1.5之后引入

* JDK1.5增加的:
* (1)foreach
* (2)枚举
* (3)注解
* (4)可变参数
* (5)静态导入


* JDK1.8增加的:
* (1)接口的默认方法和静态方法

 final关键字

* 关键字:final,最终的
 * 它也是一个修饰符
 * 
 * 1、它可以修饰什么?
 * final可以修饰:类(包括外部类和内部类)、变量(包括局部变量、实例变量和类变量)、方法(静态方法和非静态方法); final不能用于修饰构造方法
 * 
 * 2、它修饰后有什么不同?
 * (1)修饰类,即class前面出现了final
 * 表示这个类是最终类,即这个类不能被继承了,没有子类,它是太监类,没有子孙后代
 * 例如:String类
 * 
 * (2)修饰方法,即返回值类型前面出现final
 * 表示这个方法是最终实现版本,即这个方法不能被重写
 * 
 * (3)修饰变量,即在变量数据类型前面出现final;  被final修饰的变量只能在变量定义时初始化。
 * 表示这个变量的值不能被修改,它是常量,一般要求常量名大写,每个单词之间使用_,常量必须赋值
 * 
 * 例如:Math.PI

native关键字

* 关键字:native
 * 它也是修饰符
 * 
 * 1、native可以修饰什么?
 * 可以修饰方法
 * 
 * 2、native修饰的方法是什么意思?
 * 表示这个方法是一个“原生”的方法,即它的方法体的实现不是用Java语言实现的,是有C/C++等语言实现的,
 * 实现后编译为.dll文件,然后由Java代码调用。
 * 
 * 对应调用者,使用者来说,可以把它当成Java实现的方法一样使用。
 * 而且子类可以选择用Java代码重写native方法
 */
public class TestNative {
    public static void main(String[] args) {
        Object obj = new Object();
        int hashCode = obj.hashCode();
        System.out.println(hashCode);
    }
}
class Student{
    private int id;
    private String name;
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    
}
View Code

 接口

* 1、声明一个接口
 * 【修饰符】 interface 接口名{
        }    //类似于类的声明(class)
可以用来修饰interface的有public, static也对; private和protected都不对;接口的内部成员都是public
 * 2、接口的成员
 * JDK1.8之前:
 *       (1)全局静态的常量  public static final  如 int MAX_SPEED = 20000;
 *       (2)公共的抽象的方法  public abstract   如:void run();
 * JDK1.8之后:增加了两个成员
 *      (1)默认方法
 *      (2)静态方法  
 * 
 * 3、如何使用接口?
 * (1)全局静态的常量:通过接口名直接调用
 * (2)抽象方法,由实现类(就是子类)来实现它;;;“子类“要实现接口重写接口的方法,不一定要继承父类。
 * 
 * 【修饰符】 class 实现类名  implements 接口们{
 *         //如果这个类不是抽象类,那么必须实现接口的所有的抽象方法
 * }
 * 
 * 接口可以比喻成“干爹”,可以有好几个
 * 继承可以比喻成“亲爹”,只能有一个,所以单继承
 * 
 * 4、接口的特点
 * (1)接口也是不能直接创建对象
 * (2一个类可以同时实现多个接口
 * (3一个类可以同时继承它的父类,又实现接口,要求必须继承在前,实现在后
 * 【修饰符】 class 实现类名 extends 父类  implements 接口们{
 *         //如果这个类不是抽象类,那么必须实现接口的所有的抽象方法
 * }
 * (4)接口和父类有点像,所以接口的变量与实现类对象可以构成多态引用
 * (5)一个实现类实现接口时,必须实现接口的所有的抽象方法,否则这个实现类也得是抽象类
 * (6接口可以继承接口,并且可以继承多个接口。
 * 【修饰符】interface 接口名 extends 接口们{
 * }
 * 
 * 关系:
 * 类与类之间:继承,单继承  extends
 * 类与接口之间:类实现接口,可以多实现 implements
 * 接口与接口之间:继承,多继承 extends
 * 
for(int i = 1; i < arr.length; i++){
            for(int j = 0; j < arr.length - i; j++){
        /*
         * 假设传入的是Student[]数组,里面都是学生对象
         * 如何表示前面的学生对象arr[j]比arr[j+1]大
         */
        //需要调用arr[j]的compare方法,怎么才能调用compary方法呢,
        //参数为Object类型向下转型为Student类型,它重写了compary方法
        //通过arr[j].compare(arr[j+1])>0,就可以确定arr[j]比较arr[j+1]大    
                Sortable left = (Sortable) arr[j];//这一步很关键啊
                if(left.compare(arr[j + 1]) > 0){   //if(arr[j] > arr[j+1]){
                    //交换两个元素,temp和元素的类型一样就可以
                    
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        
    }
* JDK1.8之后,接口增加了两个成员:
 * 1静态方法
 *     和类中的静态方法的格式一样。
 *     调用时:通过“接口名."调用即可
 * 
 * 原来的核心类库中,有Collection接口和Collections工具类(全部是静态方法),
 *                 Path接口和Paths工具类(全部是静态方法)
 *             后面的工具类是为前面的接口服务的。
 *         原来为了为某个接口提供工具类,还要增加一个类,现在就不同了,直接在接口中声明静态方法即可。
 *         而且这些静态的实现和接口的实现类是什么类型无关。
 * 
 * 2默认方法
 *     语法格式:
 * 【修饰符】 interface 接口{
 *         【修饰符】 default 返回值类型  方法名([形参列表]){
 *             方法体
 *         }
 * }
 * 
 *     如何调用?
 *     必须通过接口的"实现类对象."才能调用
 * 
 *     某一个接口的某个抽象方法,可能它的多数实现类对该方法的实现是一样的,那么就没必要每一个实现类都写一遍。
 *  把这样的方法实现,提取到接口中声明为默认方法,如果其他不一样的实现类,可以选择“重写”。
 */
public class TestInterface {
    public static void main(String[] args) {
        MyInter.test();  //接口中的静态方法直接    接口名.静态方法;
        
        MyImp myimp = new MyImp();
        myimp.fun();//通过接口的实现类对象来调用 接口的default默认方法;
        
        myimp.method();//通过接口的实现类对象来调用 接口的default默认方法;
        
    }
    
}

interface MyInter{
    public static void test(){
        System.out.println("接口中的静态方法直接接口名.来调用哦");
    } 
    public default void fun(){
        System.out.println("接口中的默认方法fun通过接口的实现类创建对象来调用");
    }
    public default void method(){
        System.out.println("接口中默认方法method通过接口的实现类创建对象来调用");
    }
    
}

class MyImp implements MyInter{

    /*@Override   //接口中的方法不是抽象方法,可以不用重写;
    public void fun() { 
        // TODO Auto-generated method stub
        MyInter.super.fun();   
    }
    
    */
    
}
View Code

/*
* 默认方法的冲突问题:
* 1、当某个类实现了多个接口,多个接口的默认方法的方法签名是一样的
* 必须重写,但是在重写的时候可以选择(1)保留其中一个(2)选择完全重写
*
* 2、当某个类继承了父类,又实现了接口,但是父类中有一个方法和接口中的默认方法的方法签名是一样的
* 默认选择保留“父类”,即子类创建对象默认调用的是父类中的方法,如果子类重写了父类的方法就按照子类重写的方法;

当然也可以重写接口中的方法,就会调用接口中的方法,如 InterD.super.test( ) ;

当然也可以选择重写(1)选择父接口的(2)完全重写 
*/

public class TestDefaultMethod {

    public static void main(String[] args) {
        
        Sub s = new Sub();
        s.test();
        
        
        Son son = new Son();
        son.test(); //如果子类没有重写,就默认调用父类的
        
    }
    
}

interface InterA{
    public default void test(){
        System.out.println("我是接口A的默认方法test");
        
    }
}

interface InterB{
    public default void test(){
        System.out.println("我是接口B的默认方法test");
    }
}

class Father{
    
}

class Sub extends Father implements InterA, InterB{

    
    @Override
    public void test() {
        // TODO Auto-generated method stub
        InterA.super.test();//保留A接口的默认实现
        InterB.super.test();//保留A接口的默认实现,也可以实现两个都保留;也可以进行重写;
        System.out.println("我重写,两个都不要了");
    }

}


interface InterD{
    public default void test(){
        System.out.println("我是接口D中的默认方法test");
    }
}

class Fu{
    public void test(){
        System.out.println("我是父类Fu中的方法test");
    }
}

class Son extends Fu implements InterD{
    public void test(){
        InterD.super.test(); //重写接口D中的方法;  子类重写父类的方法了,就不会调用父类的方法了调它自己的
        System.out.println("我是子类Son中的方法test,重写了父类的了");
        
        
    }
    
    
}
View Code

 用实现类代替接口

public class TestInterface {

    public static void main(String[] args) {
        //AA aa = new BB(); //需要一个接口,给个实现类即可
        AA aa = new CC(); //多态的传递
        // AA aa = new BB(); BB bb = new CC(); 构建CC,等同于构建他的父类,父类可以代替接口实现;能代替不代表实现了接口,class CC extends BB implements AA这样子就实现了接口
        //System.out.println(aa);
        System.out.println(CC.class.getInterfaces().length); //CC并没有实现接口AA
    }
}
interface AA{

}
class BB implements AA{

}
class CC extends BB{

}

简单工厂模式

* 简单工厂模式(了解):
* (1)当创建某个对象比较麻烦
* (2)想要与被创建的对象的类型解耦合
*
* 工厂模式的目的:对象的创建者与对象的使用者角色分离
*
* 代码的结构:
* (1)接口
* (2)有接口的很多实现类
* (3)有一个工厂类,专门new接口的各种实现类的对象
* (4)使用接口的实现类对象的地方,通过工厂类之间获取对象,而不直接new实现类对象
*
* 耦合:依赖,关联
*/

public class TestFactory {

    public static void main(String[] args) {
        String str = new String();  //TestFactory与String类发生耦合,依赖
        //对象的使用者TestFactory
        //想要获取宝马车的对象; new出BMW对象,接口类型Car b 
        Car c = new BMW();//与BMW发生耦合,对象的使用者和创建者都是TestFactory
        c.run();
        
        
        //对象的使用者TestFactory不负责BMW和Aodi对象的创建,与BMW和Aodi类解耦合
        Car b = Factory.getCar("宝马");
        b.run();
        Car a = Factory.getCar("奥迪");
        a.run();
    }

}

class Father{
    
}

class Son extends Father{

}

interface Car{
    void run();
}
class BMW implements Car{

    @Override
    public void run() {
        System.out.println("宝马来了。。。");
    }
}

class AoDi implements Car{

    @Override
    public void run() {
        System.out.println("奥迪来了。。。");
        
    }
}
class Factory{
    //工厂只负责创建对象;创建一个getCar方法来生产Car的对象
    public static Car getCar(String type){
        if("宝马".equals(type)){
            return new BMW();
        }else if("奥迪".equals(type)){
            return new AoDi();
        }
        return null;
        
    }
}
View Code

代理模式

* 代理:代购、中介
* 把麻烦,多变交给代理,核心的不易变化的还是自己来做。
*
* 静态代理和动态代理。
*
* 代理模式:(了解)
* 1、接口:主题接口
* 2、被代理者
* 3、代理者
* (1)被代理者和代理者都要实现主题接口。
* (2)要指定代理者为谁代理,即代理者中必须持有被代理者对象的引用
*
* 静态代理:

public class TestProxy {

    public static void main(String[] args) {
        
        DaiGou d = new DaiGou(new Customer()); //用有参构造器,创建DaiGou的对象d,并给他赋值初始化
        d.buy();    //构造器中的形参Subject target, 把实参new出Customer对象传给它;最后由d对象来调用方法
        
    }

}

interface Subject{
    void buy();  //抽象方法省略了public abstract 
}

//被代理者  --Customer类实现了Subject接口;
class Customer implements Subject{

    @Override
    public void buy() {
        // 最核心的自己写
        System.out.println("一手交钱一首交货");
    }
    
}

class DaiGou implements Subject{

    private Subject target;  //类DaiGou的属性,接口类型的引用数据类型targer; 被代理者对象的引用

    public DaiGou(Subject target) {  
        super();
        this.target = target;  //在构造器中给属性targer初始化
    }

    @Override
    public void buy() {
        System.out.println("筛选商品");
        
        target.buy();   //一手交钱一首交货
        System.out.println("反馈下");
        
    }
    
}
View Code

枚举

* 枚举:也是一个种类型,也是一个类
* 1、什么是枚举?
* 中文:枚举 的近义词 列举,穷举,罗列
* Java中,枚举,罗列出该类型的所有对象
*
* 2、什么情况会用枚举?
* 当某个类型它的对象是有限的几个,这个时候就可以使用枚举。
* 3、如何声明枚举类
* JDK1.5之前
* JDK1.5之后

public class TestEnum {
    public static void main(String[] args) {
//        Season s = new Season();//构造器不可见
        
        //如何获取春天对象
        Season spring = Season.SPRING;  类型 类名 = 类型.静态对象
        System.out.println(spring);
        
        Season summer = Season.SUMMER;
        System.out.println(summer);
    }
}
//JDK1.5之前
/*
 * (1)限定使用者创建对象;    2)把有限的几个对象,提前创建好,并存起来,大家共享
 * 存对象:肯定用变量才能存;   共享:类变量,静态变量;      随处可用:public 
 */
class Season{
    //(2)把有限的几个对象,提前创建好,并存起来,大家共享
    public static final Season SPRING = new Season();
    public static final Season SUMMER = new Season();
    public static final Season FALL = new Season();
    public static final Season WINTER = new Season();
    
    //(1)限定使用者创建对象,把构造器私有化
    private Season(){
        
    }
    //可以定义其他的成员
    public String toString(){
        if(this == SPRING){
            return "春眠不觉晓,处处闻啼鸟。";
        }else if(this == SUMMER){
            return "小荷才露尖尖角,早有蜻蜓立上头";
        }else if(this == FALL){
            return "停车坐爱枫林晚,霜叶红于二月花。";
        }else{
            return "千山鸟飞绝,万径人踪灭。";
        }
    }
}
* JDK1.5之后:
 * 1、枚举类的声明格式
 * 【修饰符】 enum 枚举类名{
 *       枚举类的常量对象列表 【;
 *         其他成员列表
 ** }
 * 
 * 说明:
 * (1)如果枚举常量对象列表后面要写其他成员,那么需要在常量对象列表后面加;分隔,如果没有其他成员,那么;可写可不写
 * (2)构造器一定是私有化的
 * (3)枚举类型的默认父类不是Object,而是java.lang.Enum类,当然Enum也是Object的子类
 * 枚举类型不能再继承别的类型
 * 
 * java.lang.Enum类:
 * (1)构造器
 * protected Enum(String name,int ordinal)
 * name是为Enum类中的name属性赋值,自动赋值为常量对象的名称
 * ordinal是Enum类中的ordinal属性赋值,自动赋值为常量对象的“序号”,这个序号是从0开始
 * 
 * 他们的get方法没有按照普通类的get方法的命名,而是直接用属性名作为get方法的名称:name(),ordinal()
 * 
 * 因为父类Enum只有唯一的一个有参构造,意味着我们自己写的枚举类的构造器和普通类(默认调用父类的无参构造)不一样,
 * 默认调用的是父类的有参构造。
 * 
 * (2)Enum实现了java.lang.Comparable接口
 * 所有的枚举类型都支持比较大小,因为Enum实现了java.lang.Comparable接口,按照常量对象的顺序比较大小。
 * 父类中把这个int compareTo()加了final,子类不能重写
 * 
 * (3)两个API中没有的方法
 * static 枚举类型[] values():用来返回枚举类型的所有常量对象
 * static 枚举类型  valueOf(字符串类型的常量对象名) -->> 枚举类名.valueof(“ ”)
     Week sunday = Week.SUNDAY;
        System.out.println(sunday); //对象sunday打印的是 toString的内容;
        System.out.println(sunday.name());
        System.out.println(sunday.ordinal());
        
        System.out.println("----------------");
        
        Week[] values = Week.values();
        for (Week week : values) {
            System.out.println(week);
        }
        
        Week w = Week.valueOf("MONDAY");
        System.out.println(w);
        

System.out.println(Week.valueOf("SUNDAY")); --->> 星期天       //(SUNDAY("星期天"); )

public enum Status {

    BUSY("忙得热火朝天,无法再安排其他任务"), //创建的对象时候用的是有参构造;
    FREE(),   //用的是无参,默认null
    VOCATION(), 
    LEFT("离职了");
    
    private String desc;

    private Status() {
    }

    private Status(String desc) {
        this.desc = desc;
        
    }



                Status busy = Status.BUSY;
        
        
        Employee[] emp = new Employee[5];
        emp[0] = new Employee("kris", 10000, Status.BUSY);//busy
        
for (Employee employee : emp) {
            System.out.println(employee.toString());//employee  <==> employee.toString();
        }
               

 注释

注解(annotation):它又称为注释,它本质上也是注释,只不过它是代码级别的注释,即它用代码注释代码。
* 因为说注释容易让人误解为单行和多行的普通注释,很多人就故意叫做“注解”
* 注解是JDK1.5之后引入。
*
* 普通的注释:用文字去注释代码
* (1)单行注释
* (2)多行注释
*
* 文档注释:用代码和文字一起去注释代码。
*
* 注解长什么样? @注解

* 一个完整的注解,它应该有三部分组成:
* (1)定义,声明
* 可能是程序员自己声明的,也可能是别人声明好的;* 开发中,绝大多数都是用别人声明好的。

* (2)注解的使用
* 你看到在类上面、方法上面、属性上面....用到了@注解,就是在使用注解
* (3)读取注解
* 得有代码去读取这个注解,理解代码的用意,信息...
* 读取注解需要用代码去读取,这个代码我们称为“注解处理流程”,大多数情况下,这个代码也是别人写好的,
* 一般都是谁定义,谁复制编写读取注解的代码。
*
* 注解在后面的框架中使用最多,它的作用是用来替代xml的配置文件,对代码进行解释。
* 因为xml的配置方式,一个是复杂,另一个与所解释的代码是独立的,所以有的地方不用xml,用注解

常见的注解

* 常见的注解:
 * 
 * 一、系统定义的最基本的三个注解(必须都认识,会写,会用)
 * 1、@Override:
 * 这个注解的声明是在JDK的核心类库中声明的,
 * 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
 * 这个注解的使用由程序员来使用,用在所有的重写的方法的上面,表示让编译器,按照重写的要求对该方法进行格式检查和编译。
 * 
 * 重写的要求:
 * (1)方法名和形参列表必须相同
 * (2)返回值类型
 *         如果是基本数据类型和void,必须相同
 *         如果是引用数据类型,必须<=   子类重写的方法的返回值类型<=父类被重写的方法的返回值类型
 * (3)权限修饰符:必须>=            子类重写的方法的权限修饰符的可见范围>=父类被重写的方法的权限修饰符的可见范围
 * (4)抛出的异常列表类型范围:?
 * (5)其他修饰符:被重写的方法不能是static,private,final
 * 
 * 2、@SuppressWarings(xx)    
 * 这个注解的声明是在JDK的核心类库中声明的,
 * 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
 * 这个注解的使用由程序员来使用,用在任意需要抑制警告的地方    
 * 
 * @SuppressWarnings("all")
 * @SuppressWarnings({ "rawtypes", "unused" })
 * 
 * 3、@Deprecated 
 * 这个注解的声明是在JDK的核心类库中声明的,
 * 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
 * 这个注解的使用由程序员来使用,用在任意需要标记为“已过时”的元素上面,可能是方法,可能是类,
 * “已过时”的东西,不建议程序继续使用的,如果使用可能有问题
 * 
 * 删除的行为一定要谨慎。
 * 
 * 编译器如果遇到了程序员使用了已标记为“已过时”的元素时,它会弹出警告

 文档注解,文档注释

二、文档注解,文档注释
 * 文档注解的声明,也有JDK核心类库声明过了; * 读取:javadoc.exe来读取
 * @author:表示作者
 * @version:表示版本
 * @since:起始版本
 * @see:另请参考
 * @param:形参
 * @return:返回值
 * @throws:抛出的异常列表
 * 
 * @param、@return、@throws只能在方法上使用
 * @param 形参名 形参的数据类型  形参的解释
 * @return 返回值类型  说明
 * @throws 异常类型 说明
import javax.management.RuntimeErrorException;

/**
 * @author Administrator
 * @version 1.8
 * @since 1.0
 * @see java.lang.Object
 * @see java.lang.Math
 */

public class TestAnnotation {

    public static void main(String[] args) {
        /**java程序主入口
         * @param args String[] 命令行参数
         */
        @SuppressWarnings(value = { "unused" })
        int a = 10;
    }
    
    public static int getMax(int a, int b){
        /**
         * 从两个整数中找出最大值
         * @param a int
         * @param b int
         * @return int 返回最大值
         */
        
        return a > b ? a :b;
    }
    
    public static int divide(int a, int b) throws RuntimeErrorException{
        
        /**
         * 这是一个求两个整数的商
         * @param int a 
         * @param int b
         * @return int 
         * @throws RuntimeException,当b为0时抛出异常
         */
        
        if(b == 0){
            throw new RuntimeException("除数不能为0");
        }
        return a/b;
    }
    
    @Deprecated
    public void print(){
        System.out.println("过时的方法啊");
    }

    @Override
    public String toString() {
        return "TestAnnotation [toString()=" + super.toString() + "]";
    }
    
}
View Code

单元测试

* JUnit框架不是JRE核心类库,需要单独引入它的jar,类库;  eclipse等IDE(集成开发工具)都直接集成了JUnit框架
 * 
 * 三、单元测试
 * 声明和定义:JUnit框架中定义的* 读取:由java + JUnit框架读取
 * 
 * 如何运行?
 * 如果没有选择,那么当前源文件中的所有的单元测试都会运行
 * 如果选中某个方法,只运行某一个;
 * 
 * @Test:   要先引入import org.junit.Test;
 *加在需要单独测试的方法。* 
 * @Before  导入 import org.junit.Before;  与之类似的 --->>> @After 是在@Test方法后边最后才执行。
 * 加在需要在单元测试方法前面运行的方法上;  如public void test(){ }; *执行的特点:每一个@Test方法前面都会执行这个方法,再执行@Before; 
 * 
 * @BeforeClass            @BeforeClass
 * 加在需要在类初始化时执行的方法上。 如public static void test(){  }; 最先执行,首行位置;* 
 * @AfterClass    类似上边@BeforeClass的用法
 *     加在需要在类所有的测试方法之后执行的方法上
 *     
这四个都有要求:方法所在的类必须是public
* 方法本身必须是public,而且是无参无返回值的,静态的
@Test
    public void test(){
        System.out.println("Hello");
    }
    @Before
    public void test1(){
        System.out.println("hi");
    }
    @After
    public void test2(){
        System.out.println("Test之后");
    }
    @BeforeClass
    public static void test3(){
        System.out.println("嘿嘿");
    }
    @AfterClass
    public static void test4(){
        System.out.println("嘿哈");
    }
View Code

自定义注释

* 枚举看成是类
 * 注解看成是接口
 * 
 * 注解:
 * (1)声明
 * (2)使用
 * (3)读取
 * 
 * 一、自定义注解
 * 1、语法格式:
 * 【修饰符】 @interface 注解名{
 * }
 * 
 * 2、加元注解说明一下
 * 元注解:注解注解的注解,给注解加的注解。它们在java.lang.annotation包* (1)@Target 
 * @Target(ElementType.xx)
 * @Target({ElementType.xx,ElementType.xx,...})
 * ElementType是一个枚举类型,有很多常量对象:例如:TYPE,METHOD(方法),FIELD(属性),CONSTRUCTOR....
 *     TYPE(包含 Class, interface (including annotation type), or enum declaration )
 * @Target作用:限制自定义的注解的使用的目标位置
 * 
 * (2)@Retention
 * @Retention(RetentionPolicy.SOURCE):源代码阶段   该注解只能被编译器读取
 * @Retention(RetentionPolicy.CLASS):字节码阶段  该注解只能被编译器和类加载器* @Retention(RetentionPolicy.RUNTIME):运行时阶段  该注解可以在运行时仍然被读取
 * 
 * SOURCE < CLASS < RUNTIME
 * 
 * @Retention的作用:限制自定义注解的寿命,可以“滞留”到什么阶段
 * RetentionPolicy也是枚举类型,常量对象只有三个:SOURCE,CLASS,RUNTIME
 * 
 * (3)@Documented
 * 标记某个注解是否可以被javadoc读取到API中。
 * 
 * (4)@Inherited
 * 标记某个注解是否可以被子类继承
 * 
 */
package com.atguigu.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class TestDefineAnnotation {

    public static void main(String[] args) {
        
        //读取MyClass类上面的注解,用到了反射
        Class clazz = MyClass.class;
        MyAnnotation my = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
        System.out.println(my);
        
        Class clazz2 = MySub.class;
        MyAnnotation my2 = (MyAnnotation) clazz2.getAnnotation(MyAnnotation.class);
        System.out.println(my2);

    }

}

//@YoursAnnotation
class MyClass{
    //@YoursAnnotation  //不能在属性上使用,因为它规定了只能使用在METHOD即方法上
    @MyAnnotation
    private String filed;
    
    @MyAnnotation
    @YoursAnnotation
    public void test(){
        
    }
    
}

class MySub extends MyClass{
    
}

@Inherited  //标记这个注解可以被子类继承;
@Retention(RetentionPolicy.RUNTIME) //可以在运行时阶段读取;
@interface MyAnnotation{  //自定义一个注解;
    

}
@Documented
@Target(ElementType.METHOD) //限制自定义注解使用的目标位置
@Retention(RetentionPolicy.SOURCE) //只能被编译器读取;
@interface YoursAnnotation{
    
}
View Code
* 自定义注解
 * 
 * 1、语法格式:
 * @元注解
 * 【修饰符】 @interface 注解名{
 * }
 * 
 * 
 * @元注解
 * 【修饰符】 @interface 注解名{
 *         配置参数
 * }
 * 
 * 没有配置参数的注解:
 * (1)@Override
 * (2)@Deprecated
 * (3)@Documented
 * (4)@Inherited
 * (5)@Test
 * 
 * 有配置参数的
 * (1)@SuppressWarnings(xx)
 * (2)@Target(xx)
 * (3)@Retention(xx)
 * (4)@WebServlet(xx)
 * 
 * 1、配置参数的声明
 * (1)声明格式:
 *     数据类型  参数名();
 * (2)配置参数在声明时,可以有默认值
 *     数据类型  参数名() default 默认值; 如 String info() default "atguigu";
 * (3)数据类型
 * 注解的配置参数的数据类型的要求:8种基本数据类型,4种引用数据类型(String,Class,枚举,注解*                             可以是它们的数组类型,例如:int[],String[],枚举类型[]等
 * 
 * 2、如果有配置参数,在使用时
 *(1) @注解名(参数名1 = 参数值1,参数名2 = 参数值2,。。。。)
 *(2)如果这个注解只有一个配置参数,并且它的名字叫做value,那么可以省略value=
 *
 *换句话说,声明配置参数时,参数名首先考虑value
 * 
 * 3、读取配置参数值时,   变量 = 注解对象.参数名()
 * 
 * 
 * 回忆:default
 * (1)switch
 * (2)接口
 * (3)注解配置参数的默认值
 * 
 * 数据类型:
 * (1)数据类型有哪些:
 * (2)变量的数据类型: 都可以
 * (3)属性的数据类型什么要求: 都可以
 * (4)形参的数据类型什么要求: 都可以
 * (5)返回值类型的类型有什么要求: 都可以
 * (6)switch(表达式)中表达式的类型要求:4种基本数据类型,2种引用数据类
 * (7)注解的配置参数的数据类型的要求:8种基本数据类型,4种引用数据类型(String,Class,枚举,注解)
 *                             可以是它们的数组类型,例如:int[],String[],枚举类型[]等
 */
public class TestAnnotation2 {
    public static void main(String[] args) {
        @SuppressWarnings("rawtypes")
        Class clazz = TestA.class;
        AnnotationA my = (AnnotationA) clazz.getAnnotation(AnnotationA.class);
        System.out.println(my);
        
        String str = my.info(); //对象.方法 来进行调用;
        System.out.println(str);
    }

}
@AnnotationA(info = "atguigu", age = 22, value = 88.9) //赋值时像属性,变量
class TestA{                              //只有一个参数时可以省略value = 
    
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface AnnotationA{
    String info() default "尚硅谷"; //可以有默认值
    int age();  //配置参数的声明;
    char gender() default '男';
    double value();
    
}

异常

* 所谓异常:程序大多数情况下是可以正常,正确的运行,但是有的时候因为一些不可控的因素,导致程序运行异常,中断。
* 例如:复制文件时,因为目标盘空间不足; 聊天功能时,因为网络中断;* 计算两个数的商,用户输入的除数为0

1)语法错误;   2)逻辑错误  --->>  它们不是异常。。。

异常的作用:使得系统可以通过捕获异常对象,然后处理异常,使得程序继续运行,否则,如果一旦异常,程序就会挂了。使得程序更健壮。

* Java中是如何处理异常?(原理)

* 当某句代码发生异常时,程序会在这句代码“停”下来(下面的代码是无法执行的)
然后JVM(大多数是JVM,有的时候也可能是程序中自己new)
会创建一个“合适类型的异常的对象”,并且“抛”出来;
JVM会在该句代码的“外围”搜索是否有"try..catch"可以“捕获”这个异常,如果可以“捕获”那么程序从"try..catch"下面继续运行,
如果没有找对应的"try..catch",或者先有的"try..catch"无法“捕获”,
那么程序会把这个异常对象“抛”给“上级”如果上级可以“捕获”,那么就“上级”的"try..catch"下面继续运行,
否则接着往上抛,一直到main,如果main也“捕获”不了,就挂了。

异常的类型

* 异常的类型:
 * java.lang.Throwable:Throwable 类是 Java 语言中所有错误或异常的超类。
 * (1)只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
 * (2)只有此类或其子类之一才可以是 catch 子句中的参数类型。 
 * 
 * “抛”:JVM抛,throw抛
 * “抓,捕获”:catch
 * 
 * 两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。
 * 通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。 
 * 
 * 分为:
 * Error:错误,严重的异常,用于指示合理的应用程序不应该试图捕获(catch)的严重问题。
 *         例如:VirtualMachineError的两个子类: OutOfMemoryError, StackOverflowError
 * Exception:异常
 *         非受检异常/运行时异常:RuntimeException及其它的子类
 *         受检异常/编译时异常:除了运行时异常,剩下的都是编译时异常
 * 
 * 编译器在检查程序时,遇到你throw或throws出RuntimeException,编译器不会强制要求你编写try..catch或继续throws处理;
 * 编译器在检查程序时,遇到你throw或throws出非运行时异常,那么编译器会强制要求你编写try...catch或继续throws否则编译不通过。
 *

  Throwable是所有错误和异常的父类,超类。

  Exception是所有异常的父类,它分为RuntimeException和非RuntimeException。

try..catch..finally形式有三种:1) try..catch;  2) try...catch..finally;  3) try..finally

try...catch 

* try...catch
 * 1、语法格式:
 * try{
 * 
 *         可能发生异常的语句块;
 * 
 * }catch(异常类型1  异常名){
 *         处理该异常的代码;
 * }catch(异常类型2  异常名){     //catch -->> catch --> 一定是有先后顺序的,从子类---->>>父类,高级的
 *         处理该异常的代码;
 * }catch(异常类型3  异常名){
 *         处理该异常的代码;
 * }
 * ....
 * 
 * try..catch的执行过程:
 * (1)如果try中的代码没有异常,那么try中的代码执行完,正常执行try..catch下面的代码
 * (2)如果try中的代码发生异常,首先,try中发生异常那句代码  后面的代码是无法执行,其次,在try中抛出一个
 * 异常对象,catch会按从上到下,依次尝试“捕获”,如果有一个“捕获”了,下面的catch就不看。
 * 所有要求子异常类型写上面,父异常类型写下面。
 * (3)如果try中的代码发生异常,并且所有的catch都没有“捕获”,那么try..catch下面的代码就无法执行了,
 * 会把异常对象抛出“上级——调用者”,如果已经是最上级(main),就挂了。
 * 
 * 这个特点有的像:
 * if...else if....
 * 
 * 
 * 
 * 提示:把字符串类型的数字转成int的值
 * Integer.parseInt(字符串)

try...catch...finally 

* try...catch...finally
 * 2、语法格式:
 * try{
 * 
 *         可能发生异常的语句块;
 * 
 * }catch(异常类型1  异常名){
 *         处理该异常的代码;
 * }catch(异常类型2  异常名){
 *         处理该异常的代码;
 * }catch(异常类型3  异常名){
 *         处理该异常的代码;
 * }finally{
 *         无论try中是否发生异常,也不管catch是否能够捕获异常,finally中一定要执行。
 * }
 * 
 * finally块中一般编写:释放资源,断开连接等代码。
 * 
 * 
 * 面试题:final,finally,finalize的区别?
 * final是修饰符,修饰类,表示不能被继承,修饰方法,表示不能被重写,修饰变量,表示值不能被修改是常量。
 * finally:是try..catch..finally的一部分,无论try中是否发生异常,也不管catch是否能够捕获异常,finally中一定要执行
 * finalize:是一个方法名,在Object类中,表示当对象被“垃圾回收器GC”回收之前调用,有它在就不回收了,只有第一次有效,第二次无效会被gc回收。

 * 形式:
 * try..catch
 * try..finally
 * try..catch...finally
public static void main(String[] args) {    
        int num3 = test();
        System.out.println("num3 = " + num3); //1 
    }
public static int test(){
        int result = 0;
        try {
            result = 1/1;
            System.out.println("result = " +result); //1
            
            return result;//(1)先把1,load到“方法的返回值存放区”(3)再结束当前方法,返回“方法的返回值存放区”的值
        } catch (Exception e) {
            return result;
        }finally{
            result++;//(2)result变量自增,变成2,这个2就不会放到“方法的返回值存放区” //如果变成return result++; 结果还是1 ;如果是return 3; 它就变成3了
            System.out.println("result = " + result); //2
        }

* 结论:
* (1)finally中的部分无论如何都要执行
* (2)如果finally中有return,以finally中的return语句为主
* (3)如果finally中无return,以try或catch中的return语句为主
*/

考到try...catch...finally和return一起的时候:
(1)finally中代码,无论如何一定要执行,不管是否发生异常,也不管是否catch住异常;
(2)如果finally中没有return语句,那么就先执行finally,然后再回去执行try或catch中的return语句,第二个作用“结束当前方法”,返回值不受finally影响;
(3)如果finally中有return语句,那么就执行finally中的return语句,相当于try和catch中return语句“失效”。

throws

throws:显式声明当前方法中,没有处理的异常,由调用者来处理,特别是编译时异常

如果方法中有产生编译时异常,而又未处理,那么必须加throws声明,否则编译不通过

如果方法中有产生运行时异常,而又未处理,那么可以加throws也可以不加,因为编译期间检测不到运行时异常,编译可以通过。

* throws* 1、用于在声明方法时,显式的声明当前方法中没有处理的异常,要调用者来处理。
 * 调用者在使用有throws的方法时,用try...catch就知道该catch什么更具体异常,否则就按Exception
 用上throws(你得知道要抛出的是什么异常如ArithmeticException),写在方法名的后边,你再try...catch.. 选择try里边的代码右键选择Sound with 选择try,
它就知道要抛什么异常了,不然它只会抛Exception异常。
* * 2、语法格式: * 【修饰符】 返回值类型 方法名(【形参列表】)throws 异常列表{ * } * * 异常列表可以写好几个,用,分割 * * 3、关于方法重写 * (1)方法名和形参列表必须相同 * (2)返回值类型 * 基本数据类型和void:必须一致 * 引用数据类型:<= 子类重写方法的返回值类型<=父类被重写方法的返回值类型 * (3)权限修饰符:>= 子类重写方法的权限修饰符的可见性范围 >= 父类被重写方法的权限修饰符的可见性范围 * (4)其他修饰符: 哪些不能重写 static,final,private * (5)抛出的异常列表的类型:<= 子类重写方法抛出的异常类型 <= 父类被重写方法抛出的异常类型 */
public class TestThrows {

    public static void main(String[] args) {
        
            try {
                divide(1, 0);
            } catch (ArithmeticException e1) {
                e1.printStackTrace();
            }
            
        
        
        try {
            copy("1.txt", "2.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
            
        Father f = new Son();//多态引用
        
        try {
            f.test(); //编译时按照父类Father,运行时按子类Son,子类抛出RuntimeException异常,Exception要能够捕获到
        } catch (Exception e) {  //反过来按照子类抛出的Exception,这个时候发现catch就捕获不了
            e.printStackTrace();
        }
        

    }
    
    public static int divide(int a, int b) throws ArithmeticException{
        return a/b;
    }
    
    public static void copy(String srcFilePath, String destFilePath) throws FileNotFoundException{
        FileInputStream fis = new FileInputStream(srcFilePath);
        FileOutputStream fos = new FileOutputStream(destFilePath);
        
    }
    

}

class Father{
    public void test()throws Exception{
        
    }
}
class Son extends Father{
    public void test() throws RuntimeException{  //子类的抛出的异常类型要比父类的小
                                //要保证子类抛出的异常父类能够接住
    }
    
}
View Code

throw用于手动抛出异常对象

* 大多数异常对象是JVM根据情况抛出。有的时候需要手动抛出异常,
* throw:用于手动抛出异常对象
* 语法结构:
  throw 异常对象;
   可以代替return语句,即带回异常信息,而且可以结束方法的执行

public class TestThrow {

    public static void main(String[] args) {
        Account account = new Account();
        
        try {
            account.withdraw(100);
            System.out.println("取款成功");
        } catch (Exception e) {
            System.out.println(e.getMessage()); // 打印的是条件不满足时抛出的异常,给用户看的
            //e.printStackTrace(); //直接打印出红色异常信息,给开发者看的;
            
        }
        System.out.println("余额为:" + account.getBalance());
    }

}

class Account{
    private double balance = 1000;
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    public void withdraw(double amount){
        if(amount < 0){
                        //Illegal不合法,Argument参数
            IllegalArgumentException e = new IllegalArgumentException("取款金额输入有误");
            throw e;
        }if(amount > balance){
            throw new RuntimeException("余额不足");
        }
        balance -= amount;
    }
}

自定义异常:

* (1)要继承Throwable或它子类
* 一般都继承Exception(编译时异常),或者RuntimeException(运行时异常)
* (2) 异常名要见名知意
* (3)尽量保留父类的两个构造器:一个是无参构造,一个是为message赋值的构造器
* (4)自定义异常必须手动用throw来抛出,JVM无法给你自动抛出
*
* 一个异常:
* (1)类型要见名知意
* 例如:ArrayIndexOutOfBoundsException
* ClassCastException
* FileNotFoundException
*
* (2)自己的message消息
* 异常对象名.getMessage()可以获取

(3)堆栈跟踪信息
* 异常对象经历的抛出路线,从哪个方法到哪个方法
* 异常对象名.printStackTrace(); //Trace痕迹

* System.err:异常信息,默认是红色的
* System.out:普通信息
* System.err和System.out是两个线程,谁先抢到谁先打印

public class TestMyException {

    public static void main(String[] args) {
        
        try {
            regist("admin", 22, "123@qq.com");
            System.out.println("注册成功");
        } catch (UsernameExistException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
    
    public static void regist(String username, int age, String email) throws UsernameExistException{
        //做一个假的注册,假设我的数据库已经存"admin"
        if("admin".equals(username)){
            throw new UsernameExistException("用户名已存在");
        }
    }
}

class UsernameExistException extends Exception{
    
    public UsernameExistException(){
        super();
    }
    public UsernameExistException(String message){
        super(message);
    }
    
}

异常类型

//下标越界
public class TestArrayIndexOutOfBoundsException {
    public static void main(String[] args) {
        int[] arr = new int[0];
        
        try {
            System.out.println(arr[0]);
        } catch (Exception e) {
            e.printStackTrace();//标准的异常信息的打印方法,信息比较全,(1)类型(2)message(3)堆栈跟踪信息
            //
            System.out.println(e.getMessage());//只有message
        }
    }
}
View Code

运行时异常
异常栈e.printStank

NullPointerException:空指针异常,当对象是null,却用对象调用方法,属性等。
ArrayIndexOutOfBoundsExceptiom:数组下标越界异常,当下标的值超过[0,数组的长度-]的范围
ClassCastException:类型转换异常,当对象不是该类型的实例时
NumberFormatException:数字格式化异常,当把一个非数字的字符串转为数字
ArithmeticException:算术异常,例如当除一个0时


Java可能导致内存泄露的错误代码或者用简单代码演示内存溢出

public class TestOutOfMemoryError {
    public static void main(String[] args) {
        Object[] arr = new Object[Integer.MAX_VALUE];
        
        System.out.println("Integer.MAX_VALUE =" + Integer.MAX_VALUE);
    }
}
java.lang.OutOfMemoryError: Requested array size exceeds VM limit

----------------------------------------------------------------------------------
public class TestStackOverflowError { public static void main(String[] args) { test(); } public static void test(){ test(); } } java.lang.StackOverflowError

错误异常从最下看
最后一个Caused by :xxx,然后再从下往上

原文地址:https://www.cnblogs.com/shengyang17/p/10031596.html