Java基础第二阶段


目录
  • 定义语法
  • 访问方法
  • 类变量使用注意事项和细节讨论
  • 类方法基本介绍
  • 类方法的调用
  • 类方法使用的注意事项和细节讨论
  • 理解mian方法语法

Java基础第二阶段

、类变量和类方法

定义语法

访问修饰符 static 数据类型 变量名;

static 访问修饰符 数据类型 变量名;

访问方法

类名.类变量名

对象名.类变量名【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】

类变量使用注意事项和细节讨论

  1. 什么时候需要用类变量

    当我们要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量),如:定义学生类,统计所有学生共交多少钱

  2. 类变量与实例变量(普通属性)区别

    类变量是该类的所有对象共享的,而实例变量是每个对象共享的

  3. 加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量

  4. 类变量可通过 类名.类变量名 或者 对象名.类变量名 来访问,但Java设计者推荐我们使用 类名.类变量名方式访问

  5. 实例变量不能通过 类名.类变量名 访问

  6. 类变量是类加载时就初始化了,也就是说,即使没有创建对象,只要类加载,就可以使用类变量

  7. 类变量的生命周期是随类的加载开始,随着类消亡而销毁

类方法基本介绍

访问修饰符 static 数据返回类型 方法名(){}

static 访问修饰符 数据返回类型 方法名(){}

类方法的调用

使用方式:类名.类方法名 或者 对象名.类方法名 【前提是满足访问修饰符的权限和范围】

类方法使用的注意事项和细节讨论

  1. 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区

    类方法中无this的参数

    普通方法中隐含this的参数

  2. 类方法可以通过类名调用,也可以通过对象名调用

  3. 普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用

  4. 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以

  5. 类方法(静态方法)中只能访问 静态变量或静态方法。

  6. 普通成员方法,既可以访问 普通方法(方法),也可以访问静态成员和非静态成员(必须遵守访问权限)

理解mian方法语法

  1. java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
  2. java虚拟机在执行main()方法是不必创建对象,所以该方法必须是static
  3. 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
  4. java执行的程序 参数1 参数2 参数3

特别提示:

  1. 静态方法main可以访问本类的静态方法
  2. 静态方法main不能访问本类的非静态方法

代码块

基本语法

[修饰符] {

? 代码;

};

说明:

  1. 修饰符可选,要写的话,只能写static
  2. 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通/非静态代码块
  3. 逻辑语句可以为任何逻辑语句
  4. ;可以写,也可以省略
package com.hspedu.codeblock_;

public class CodeBlock {
    public static void main(String[] args) {
        new Movie("哈");
        Movie("姆", 120)
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    //下面三个构造器中有相同的语句
    //可以把相同的语句放到一个代码块中
    //不管调用哪个构造器,创建对象,都会先调用代码块内容
    //代码块调用顺序先与构造器
    {
        System.out.println("广告结束");
        System.out.println("电影结束");
    }
    public Movie(String name) {
        this.name = name;
    }

    public Movie(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

注意事项和细节讨论

  1. static代码块叫做静态代码块,作用是对类进行初始化,并且随着类的加载而执行,并且只会执行一次。而普通代码块,每创建一个对象,就执行

  2. 类什么时候被加载

    • 创建子类对象实例时

    • 创建子类对象实例,父类也会被加载,而且父类先被加载,子类后被加载

    • 使用类的静态成员(静态属性,静态方法)

  3. 普通代码块,在创建对象实例时,会被隐式调用。被创建一次,就会被调用一次。如果只使用类的静态成员时,普通代码块不会被执行。

  4. 创建一个对象时,在一个类调用顺序是:

    • 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
    • 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用
    • 最后调用构造器
  5. 构造器最前面隐含super()和调用普通代码块 ,新写一个类演示,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。

  6. 创建一个子类对象(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下

    • 父类静态代码块和静态属性(优先级一样,安定义顺序执行)
    • 子类的静态代码块和静态属性(优先级一样,安定义顺寻执行)
    • 父类的普通代码块和普通属性初始化(优先级一样,案定义顺序执行)
    • 父类构造器
    • 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
    • 子类构造方法
  7. 静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员

单例模式

单例

  1. 所谓单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
  2. 单例模式两种方式:1)饿汉式 2)懒汉式

饿汉式(存在资源浪费问题)

  1. 将构造器私有化
  2. 在类的内部直接创建
  3. 提供一个公共的static方法,返回gf对象

懒汉式(存在线程安全问题)

  1. 构造器私有化

  2. 定义一个static静态属性对象

  3. 提供一个public的static方法,可以放回一个cat对象

  4. 只有当用户使用getInstance时,才返回cat对象,后面再次调用时,回访会上次创建cat对象,从而保持单例

final关键字

使用final时刻

  1. 我们要求某一个类不能被其他类继承,可以用 final 修饰

  2. 不希望父类的方法不被子类重写可以使用 final 修饰

  3. 当不希望类的某个属性的值被修改,可以用final修改

  4. 当不希望某个局部变量被修改,可以用final修饰

final使用注意事项和细节讨论

  1. final修饰的属性又叫做常量,一般用XX_XX_XX命名
  2. final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以再如下位置
    • 在定义时:public final double TAX_RATE = 0.08
    • 在构造器中
    • 在代码块中
  3. 如果final修饰的属性是静态的(public static final ...),则初始化位置只能是
    • 定义时
    • 静态代码块
    • 不能再构造器中赋值
  4. final类不能继承,但是可以实例化对象
  5. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承,
  6. 一般来说,如果一个类是final类,就不需要再将方法修饰成final方法
  7. final不能修饰构造器
  8. final和static往往搭配使用,效率更高,不会导致类加载
  9. 包装类(Integer,Double,Float,Boolean等都是final)String也是final类,不能被继承

抽象类

抽象类介绍

  1. 用abstract 关键字修饰一个类时,这个类叫做抽象类 访问修饰符 abstract 类名 { }
  2. 用abstract 关键字修饰一个方法时,这个方法就是抽象方法 访问修饰符 abstract 返回类型 方法名 (参数列表); 没有方法体
  3. 抽象类的价值更多作用于设计,是设计者设计好后,让子类继承并实现抽象类

抽象类的细节

  1. 抽象类,不能被实例化

  2. 抽象类不一定要包含abstract方法,还能有实现方法

  3. 一旦类包含abstract方法,则这个类必须声明为abstract类

  4. abstract 只能修饰类和方法,不能修饰属性和其他

  5. 抽象类可以有任意成员

  6. 抽象方法不能有主体

  7. 如果一个类继承抽象类,则它必须实现抽象类所有抽象方法,除非自己也是abstract方法

  8. 抽象方法不能使用private、final 和 static来修饰,这些关键字都是和重写相违背

抽象模板模式

接口

接口的基本介绍

接口就是给一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出。语法:

interface 接口名{

? //属性

? //方法 (1.抽象方法 2. 默认实现方法 3.静态方法)

class 类名 implements 接口{

? 自己属性

? 自己方法

? 必须实现的接口的抽象方法

总结:

  1. 在Jdk7.0前接口里的所有方法都没有方法体,都是抽象方法

  2. Jdk8.0 后接口可以有静态方法,默认方法(default public void .....),也就是说接口中可以有方法的具体实现

接口的注意事项

  1. 接口不能被实例化,但可以指向 实现了接口的实例对象

  2. 接口中所有的方法是public方法,接口中抽象方法,可以不用abstract 修饰:
    void aaa();

    实际上是 abstract void aaa();

  3. 一个普通类实现接口,必须将该接口的所有方法都实现,可以使用alt + enter 来解决

  4. 抽象类实现接口,可以不用实现接口的抽象方法

  5. 一个类同时可以实现多个接口

  6. 接口中的属性,只能是final的,而且是 public static final修饰符

  7. 接口中属性的访问形式:接口名.属性名

  8. 一个接口不能继承其他的类,但是可以继承多个别的接口

  9. 接口的修饰符只能是public 和默认,这点和类的修饰符是一样的

接口的多态性

  1. 多态参数:既可以接收手机对象,又可以接收相机对象,体现接口多态
  2. 多态数组:
  3. 接口存在多态传递现象

内部类

基本介绍

一个类的内部又完整的嵌套另一个类结构。被嵌套的类被称为内部类,嵌套其他类的类称为外部类,是我们类的第五大成员。最大特点:可以直接访问私有

属性、方法、构造器、代码块、内部类

基本语法

class Outer{ //外部类

? class Inner{ //内部类

? }

class Other{ // 外部其他类

内部类的分类

  • 定义在外部类局部位置上,(比如方法内):
    1. 局部内部类(有类名)
    2. 匿名内部类(没有类名,重点)
  • 定义在外部类的成员位置上:
    1. 成员内部类(没用static修饰)
    2. 静态内部类(使用static修饰)

局部内部类

package com.hspedu.innnerclass;

/**
 * 演示局部内部类的使用
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.m1();
    }
}

//8.外部其他类不能访问局部内部类
class Outer02 { //外部类
    private int n1 = 100;
    private void m2() {
        System.out.println("Outer02 m2()");
    } //私有方法
    public void m1() {//方法
        //1.局部内部类是定义在外部类的局部位置,通常在方法
        //3.不能添加访问修饰符,但是可以使用final修饰
        //4.作用域:仅仅在定义它的方法或代码块中

        final class Inner02 { //局部内部类 (本质上是一个类)
            //2.可以直接访问外部类的所有成员,包含私有的
            private int n1 = 800;
            public void f1() {
                //5.局部内部类可以直接访问外部类的成员
                //7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,
                // 如果想访问外部类的成员,使用外部类名.this.成员去访问
                System.out.println("n1 = " + n1 + " 外部类的n1= " + Outer02.this.n1);
                m2();
            }
        }
        //6.外部类在方法中,可以创建Inner02对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }

}

匿名内部类

说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

(1)本质是类(2)内部类(3)该类没有名字(4)同时还是一个对象

  1. 匿名内部类的基本语法

    new 类或接口(参数列表) {

    ? 类体;

    };

package com.hspedu.innnerclass;


/**
 * 演示匿名内部类使用
 */
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {//外部类
    private int n1 = 10;//属性
    public void method() {//方法
        //1.需求:想使用IA接口,并创建对象
        //2.传统方式,是写一个类,实现接口,并创建对象
        //3.需求是Tiger 类只是使用一次,后面不再使用
        //4.可以使用匿名内部类简化操作
        //5.tiger的编译类型? IA
        //6.tiger的运行类型? 就是匿名内部类 XXXX => outer04$1
        /*
            我们看底层 会分配 类名 Outer04$1
            class outer04$1 implements IA {
                @Override
                public void cry() {
                System.out.println("老虎叫唤....");
                }
            }
         */
        //7.jdk底层在创建匿名内部类 Outer04$1,立即马上就创建 Outer04$1
        //实例,并且把地址返回给tiger

        //8.匿名内部类使用一次,就不能再使用
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫唤....");
            }
        };
        System.out.println("tiger的运行类型=" + tiger.getClass());
        tiger.cry();

//        IA tiger = new Tiger();
//        tiger.cry();
    }
}

interface IA {//接口
    public void cry();
}

//class Tiger implements IA {
//    @Override
//    public void cry() {
//        System.out.println("老虎叫唤。。。。");
//    }
//}

//class Dog implements IA {
//    @Override
//    public void cry() {
//        System.out.println("小狗叫.....");
//    }
//}
class Father {
    public Father(String name) {//构造器
    }
    public void test() {//方法
    }
}
package com.hspedu.exercise_;

/**
 * @author 何江龙
 * @version 1.0
 * 1.计算器接口有work方法,功能是运算,有一个手机类cellphone,
 * 定义方法testWork测试计算功能,调用计算接口的work方法
 * 2.要求调用CellPhone对象的testWork方法,使用匿名内部类
 */
public class HomeWork04 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        cellphone.testWork(new Calculator() {
            @Override
            public double work(double n1, double n2) {
                return n1 + n2;
            }
        },10,8);
    }
}

interface Calculator {
    public double work(double n1, double n2);
}
class Cellphone {
    public void testWork(Calculator calculator,double n1, double n2) {
        double result = calculator.work(n1, n2);
        System.out.println("计算后的结果是:" + result);

    }
}

成员内部类使用

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰

  1. 可以直接访问外部类的所有成员,包含私有的

  2. 可以添加任意访问修饰符(public, protected, 默认,private)因为它的地位就是一个成员

  3. 作用域和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。

  4. 成员内部类 可以 直接访问外部类

  5. 外部类 ------访问------》内部类 访问方式:创建对象,再访问

  6. 外部其他类 ------访问-------》成员内部类

    第一种方式:

    Outer08 outer08 = new Outer08();

    Outer08.Inner08 innner08 = outer08.new Inner08();

? 第二种方式:在外部类中编写一个方法,可以返回Inner08对象

? Outer08.Inner08 inner08Instance = outer08.getInner08Instance();

  1. 如果外部类和内部类中成员重名,会遵守就近原则,可以通过 外部类名.this.属性
package com.hspedu.exercise_;

import java.util.concurrent.Callable;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Homework07 {
    public static void main(String[] args) {
        Car car = new Car(23);
        Car car1 = new Car(49);
//        Car.Air iCar = car.new Air();
//        Car.Air iCar1 = car1.new Air();
//        iCar.flow();`
        car.getAir().flow();
        car1.getAir().flow();
    }
}
class Car {
    public double temperature;

    public Car(double temperature) {
        this.temperature = temperature;
    }

    class Air{
           public void flow(){
            if (temperature >= 40) {
                System.out.println("吹冷风");
            } else {
                if(temperature < 0) {
                    System.out.println("吹热风");
                } else {
                    System.out.println("停止吹风");
                }
        }
        }
        
    }
    public Air getAir() {
        return new Air();
    }
}

静态内部类的使用

说明:静态内部类是定义在外部类的成员位置,并且有static修饰

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员

  2. 可以添加任意访问修饰符,(public,protected,默认,private),因为它就是一个成员

  3. 作用域:同其他成员一样,是整个类体

  4. 静态内部类 -------访问------》外部类(静态属性)访问方式:直接访问所有静态成员

  5. 外部类-------访问--------》静态内部类 访问方式: 创建对象, 再访问

  6. 外部其他类 使用静态内部类

    第一种方法:静态内部类可以通过类名直接访问,要满足访问权限

    Outer.Inner10 inner10 = new Outer10.Inner10();

? 第二种方法:编写一个方法,可以返回静态内部类的对象实例

  1. 如果外部类和静态内部类成员重名,静态内部类访问的顺序遵循就近原则,如果想访问外部类的成员,可以使用(外部类名.成员)访问。

枚举和注解

枚举(enumeration—简写enum),枚举是一组常量的集合,它是一种特殊的类,其中只有一组有限的特定对象

枚举实现方式

自定义实现枚举

  1. 不需要提供setXXX方法,因为枚举对象通常为只读
  2. 对枚举对象/属性使用final + static 共同修饰,实现底层优化
  3. 枚举对象名通常使用全部大写,常量的命名规则
  4. 枚举对象根据需要,也能有多个属性
package com.hspedu.enum_;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Enumeration02 {
  public static void main(String[] args) {

    System.out.println(Season.AUTUMN);
    System.out.println(Season.SPRING);
  }
}

//演示自定义枚举实现
class Season {
  private String name;
  private String desc;

  //定义了四个对象
  public static final Season SPRING = new Season("春天", "温暖");
  public static final Season WINTER = new Season("冬天", "温暖");
  public static final Season AUTUMN = new Season("秋天", "温暖");
  public static final Season SUMMER = new Season("夏天", "温暖");
  //1.将构造器私有化,防止直接new
  //2.去掉setXXX方法,防止属性被修改
  //3.在Season内部,直接创建固定对象
  //4.优化,可以加入final修饰符
  private Season(String name, String desc) {
    this.name = name;
    this.desc = desc;
  }

  public String getName() {
    return name;
  }


  public String getDesc() {
    return desc;
  }

  @Override
  public String toString() {
    return "Season{" +
            "name='" + name + '\'' +
            ", desc='" + desc + '\'' +
            '}';
  }
}


使用enum 关键字实现枚举

package com.hspedu.enum_;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Enumeration03 {
}

//演示使用enum关键字枚举实现
enum Season2 {


  //定义了四个对象
//  public static final Season SPRING = new Season("春天", "温暖");
//  public static final Season WINTER = new Season("冬天", "温暖");
//  public static final Season AUTUMN = new Season("秋天", "温暖");
//  public static final Season SUMMER = new Season("夏天", "温暖");

  //1.使用关键字enum 代替 class
  //2.public static final Season SPRING = new Seanson("春天","温暖"); 直接使用
  // SPRING("春天","温暖"); 解读  常量名(实参列表)
  //3.如果有多个常量(对象),使用 ,号间隔
  //4.如果使用enum 来实现枚举,要求将定义常量对象,写在前面
  SPRING("春天","温暖"), WINTER("winter", "cold");
  private String name;
  private String desc; //描述

  private Season2(String name, String desc) {
    this.name = name;
    this.desc = desc;
  }

  public String getName() {
    return name;
  }


  public String getDesc() {
    return desc;
  }

  @Override
  public String toString() {
    return "Season{" +
            "name='" + name + '\'' +
            ", desc='" + desc + '\'' +
            '}';
  }
}

enum关键字实现注意事项

  1. 当我们使用enum 关键字开发一个枚举类时,默认会继承Enum类,并且是一个final类,使用javap进行演示
  2. 传统的 public static final Season2 SPRING = new Seanson2("春天","温暖");简化成SPRING("春天","温暖"),需要知道调用那个构造器
  3. 如果使用无参构造器 创建 枚举类,则实参列表和小括号都可以省略
  4. 当有多个枚举对象时,使用 , 间隔,最后有一个分号结尾
  5. 枚举对象必须放在枚举类的首行
package com.hspedu.enum_;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Enumeration03 {
  public static void main(String[] args) {
    System.out.println(Season2.SPRING);
  }
}

//演示使用enum关键字枚举实现
enum Season2 {


  //定义了四个对象
//  public static final Season SPRING = new Season("春天", "温暖");
//  public static final Season WINTER = new Season("冬天", "温暖");
//  public static final Season AUTUMN = new Season("秋天", "温暖");
//  public static final Season SUMMER = new Season("夏天", "温暖");

  //1.使用关键字enum 代替 class
  //2.public static final Season SPRING = new Seanson("春天","温暖"); 直接使用
  // SPRING("春天","温暖"); 解读  常量名(实参列表)
  //3.如果有多个常量(对象),使用 ,号间隔
  //4.如果使用enum 来实现枚举,要求将定义常量对象,写在前面
  //5.如果使用无参构造器,来创建常量对象,可以省略()
  
  SPRING("春天","温暖"),
  WINTER("winter", "cold"), What(); //调用无参构造器或者What
  private String name;
  private String desc; //描述

  private Season2() {

  }
  private Season2(String name, String desc) {
    this.name = name;
    this.desc = desc;
  }

  public String getName() {
    return name;
  }


  public String getDesc() {
    return desc;
  }

  @Override
  public String toString() {
    return "Season{" +
            "name='" + name + '\'' +
            ", desc='" + desc + '\'' +
            '}';
  }
}

枚举类一些方法

package com.hspedu.enum_;/** * @author 何江龙 * @version 1.0 * 演示enum类各种方法 */public class EnumMethod {    public static void main(String[] args) {        //使用Season2 枚举类,演示各种方法        Season2 autumn = Season2.AUTUMN;        //输出枚举对象的名字        System.out.println(autumn.name());        //ordinal()输出该枚举对象的次序/编号        System.out.println(autumn.ordinal());        //从反编译看出 values方法,返回Season2[]        //含有定义的所有枚举对象        Season2[] values = Season2.values();        System.out.println("===遍历取出灭据对象(增强for)");        for (Season2 season : values) { //增强for循环:依次从values数组中取出数据交给 season            System.out.println(season);        }        //valueOf:将字符串转换成枚举对象,要求字符串必须 为已有常量名,否则报异常        //1.根据输入的字符串到Season2的枚举对象中去查找        //2.如果找到了,就返回,没有找到就报错        Season2 autumn1 = Season2.valueOf("AUTUMN");        System.out.println("autumn=" + autumn1);        System.out.println(autumn == autumn1);        //compareTo:比较两个枚举常量,比较的就是编号        //1.将Season2.AUTUMN 枚举对象的编号 和 Season2.SUMMER枚举对象的编号比较        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));    }}

enum 注意事项

  1. 使用enum关键字后,不能再继承其他类,应为enum会隐式继承Enum,而Java是单继承机制
  2. 枚举类和普通类一样,可以实现接口,形式:enum 类名 implements 接口1,接口2 {}

注解

注解的理解

  1. 注解(Annotation)也被称为元数据(Metadata),用于修饰解释包,类,方法,属性,构造器,局部变量等数据信息
  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息
  3. 在JavaSE中,注解使用目的比较简单,例如标记过时功能,忽略警告等。在JavaEE中注解占据更重要的角色,例如配置应用程序的任何切面,代替JavaEE旧版中遗留的繁冗代码和XML配置等。

基本Annotation介绍

使用Annotation时要在前面加上@符号,并把该Annotation当成一个修饰符使用,用于修饰它支持的程序元素

  1. @Override: 限定某个方法,重写父类方法,该注解只能用于方法
  2. @Deprecated: 用于表示某个程序元素(类,方法)已过时
  3. @SuppressWarnings: 抑制编译器警告

  1. SuppressWarnings的作用范围和放置的范围有关,通常我们可以放在类上

JDK的元注解

@Retention 注解(保留)

@Target

@Documented

@Inherited注解

异常(Exception)

基本概念

开发过程中逻辑错误和语法错误不算是异常

分类

  1. Error: java虚拟机无法解决严重问题。如:JVM系统内部错误,资源耗尽等严重情况。如:StackOverfError(栈溢出),OOM(out of memory)等
  2. Exception: 其它因编程错误或偶让的外在因素导致的一般性问题,可以使用针对性代码进行处理,如空指针访问,试图读取不存在的文件。Exception 可以分成两类:运行时异常[程序运行时,发生异常],编译时异常[编程时,编译器检查出异常]

异常体系图

  1. 异常分为编译时异常,和运行时异常

  2. 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常

  3. 对于运行时异常,可以不做处理,因为这类异常很普遍,若全部处理可能会对程序的可读性和运行雄安路产生影响

  4. 编译时异常,是编译器要求必须处置的异常

常见运行时异常

NullPointerException 空指针异常

ArithmeticException 数学运算异常

说明:出现异常运算条件时,抛出此异常

ArrayIndexOutOfBoundsException

ClassCastException异常

说明:当试图将对象强制转换成不是实例的子类时,抛出该异常

NumberFormatException数字格式不正确异常

说明:当应用程序试图将字符串转换成一种数值类型,当该字符串不能转换成适当格式时,抛出该异常 = > 使用异常我们可以确保输入时满足条件数字

编译异常

异常处理

try - catch异常处理

package com.hspedu.exception_;/** * @author 何江龙 * @version 1.0 */public class TryCatchDetail {    public static void main(String[] args) {        try {//            String str = "name";            String str = "123";            int a = Integer.parseInt(str);            System.out.println("数字" + a);        } catch (NumberFormatException e) {            System.out.println("异常信息" + e.getMessage());        } finally {            System.out.println("finally代码块被执行");        }    }}

package com.hspedu.exception_;import java.util.Scanner;/** * @author 何江龙 * @version 1.0 */public class TryCatchExercise {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        int num;        String inputStr = "";        while(true) {            System.out.println("请输入一个整数:");            try {                inputStr = scanner.next();                num = Integer.parseInt(inputStr); //这里可能抛出异常                break;            } catch (NumberFormatException e) {                System.out.println("你输入的不是一个整数:");            }        }        System.out.println("你输入的值是=" + num);    }}

throws异常处理

throws异常处理细节

?

自定义异常

package com.hspedu.customexception;/** * @author 何江龙 * @version 1.0 */public class CustomException {    public static void main(String[] args) {        int age = 80;        if (age >= 18 && age <= 120) {            throw new AgeExcepiton("年龄需要在18-120之间");        }        System.out.println("你的年龄范围正确");    }}//自定义一个异常//1.一般情况我们将自定义异常做成运行时异常,好处是使用默认处理机制class AgeExcepiton extends RuntimeException {    public AgeExcepiton(String message) {        super(message);    }}

throw 和throws的区别

本章作业

package homework;/** * @author 何江龙 * @version 1.0 */public class Homework01 {    public static void main(String[] args) {        try {            //先验证输入的参数个数是否正确            if (args.length != 2) {                throw new ArrayIndexOutOfBoundsException("参数个数不对");            }            //把接收到的参数转成整数            int n1 = Integer.parseInt(args[0]);            int n2 = Integer.parseInt(args[2]);            //可能存在除0操作            double res = cal(n1, n2);            System.out.println("res = " + res);        } catch (ArrayIndexOutOfBoundsException e) {            System.out.println(e.getMessage());        } catch (NumberFormatException e) {            System.out.println("参数的格式不正确,需要输出整数");        } catch (ArithmeticException e) {            System.out.println("出现除0异常");        }    }    //编写cal方法,返回两个数的商    public static double cal(int n1, int n2) {        return n1 / n2;    }}

说明:catch捕获异常后程序接着运行

常用类

包装类

包装类分类

包装类和基本数据类型的转换

习题:

包装类型和String 类型的相互转换

package com.hspedu.wrapper;/** * @author 何江龙 * @version 1.0 */public class WrapperVSString {    public static void main(String[] args) {        //包装类(Integer)->String        Integer i = 100; //自动装箱        //方式1, 并没有影响到i        String str1 = i + "";        //方式2,        String str2 = i.toString();        //方式3        String str3 = String.valueOf(i);        //String -> 包装类        String str4 = "1234";        Integer i2 = Integer.parseInt(str4);//使用到自动装箱        Integer i3 = new Integer(str4);//可以直接使用构造器    }}

Integer类和Character类的常用方法

Integer面试题

String类

String类的理解和创建对象

创建String对象的两种方式和区别

习题:

字符串的特性

习题:

String 类的常见方法

package com.hspedu.string_;/** * @author 何江龙 * @version 1.0 */public class StringMethod {    public static void main(String[] args) {        //1.equals 比较内容是否相同,区分大小写        String str1 = "hello";        String str2 = "Hello";        System.out.println(str1.equals(str2));        //2.equalsIgnoreCase 忽略大小写的判断内容是否相等        String username = "john";        if ("john".equalsIgnoreCase(username)) {            System.out.println("Success!");        } else {            System.out.println("Failure!");        }        //3.length 获取字符的个数,字符串的长度        System.out.println("何江龙".length());        //4.indexOf 获取字符在字符串对象中第一次出现的索引,索引从0开始,如果找不到,返回-1        String s1 = "wer@terwe@g";        int index = s1.indexOf('@');        System.out.println(index); //3        System.out.println("weIndex =" + s1.indexOf("we"));//0        //5.lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从0开始,如果找不到,返回-1        s1 = "wer@terwe@g@";        index = s1.lastIndexOf('@');        System.out.println(index); //11        //6.substring 截取指定范围的字串        String name = "hello,张三";        //下面name.substring(6)  从索引6,开始截取后面所有的内容        System.out.println(name.substring(6));        //从索引0开始截取到索引5        System.out.println(name.substring(0, 5));    }}
package com.hspedu.string_;import java.util.Locale;/** * @author 何江龙 * @version 1.0 */public class StringMethod02 {    public static void main(String[] args) {        //1.toUpperCase转换成大写        String s = "hello";        System.out.println(s.toUpperCase());        //2.toLoverCase        System.out.println(s.toLowerCase());        //3.concat拼接字符串        String s1 = "宝玉";        s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");        System.out.println(s1);        //4.replace 替代字符串中的字符        s1 = "宝玉 and 薛宝钗 薛宝钗 薛宝钗";        s1 = s1.replace("林黛玉","薛宝钗");        System.out.println(s1);        //5.split 分割字符串,对于默写分割字符,我们需要转义比如 | \\等        String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";        //用 , 为标准,对poem进行分割,返回一个数组        //对字符进行分割时,如果有特殊字符,需要加入转义符\        String[] split = poem.split(",");//        String poem = "E:\\aaa\\bbb";//        split = poem.split("\\\\");        for (int i = 0; i < split.length; i++) {            System.out.println(split[i]);        }        //6.toCharArray 转换成字符数组        s = "happy";        char[] chs = s.toCharArray();        for (int i = 0; i < chs.length; i++) {            System.out.println(chs[i]);        }        //7.compareTo 比较两个字符串大小,如果前者大,则返回整数,后者大,则放回负数,如果相等,则放回0        //解读:(1)如果长度相同,并且每个字符也相同,就返回0        //(2)如果长度相同,或者不同,但是正在进行比较,可以区分大小写        //如果前面部分相同,就返回str1.len - str2.len        String a = "jcck";        String b = "jack";        System.out.println(a.compareTo(b));        //8.format 格式字符串        //占位符:%s 字符串  %d 整形  %.2f 浮点型        String name  = "john";        int age = 10;        double score = 98.3 / 3;        char gender = '男';        //将所有信息拼接到一个字符串        String info2 = String.format("我的名字是%s 年龄是%d 成绩是%.2f 性别是%c", name, age, score, gender);        System.out.println("info2= " + info2);    }}

StringBuffer类

基本介绍

String VS StringBuffer

StringBuffer的构造器

StringBuilder类

基本介绍

StringBuilder类的使用方法

Math类

基本介绍

Math类常用方法

Arrays类

package com.hspedu.arrays_;import java.util.Arrays;import java.util.Comparator;/** * @author 何江龙 * @version 1.0 */public class ArraysSortCustom {    public static void main(String[] args) {        int[] arr = {1, -1, 8, 0, 20};//        bubble01(arr);        bubble02(arr, new Comparator() {            @Override            public int compare(Object o1, Object o2) {                int i1 = (Integer) o1;                int i2 = (Integer) o2;                return i1 - i2;            }        });        System.out.println(Arrays.toString(arr));    }        //使用冒泡完成排序    public static void bubble01(int[] arr) {        int temp = 0;        for (int i = 0; i < arr.length - 1; i++) {            for (int j = 0; j < arr.length; j++) {                //从小到大                if (arr[j] > arr[j + 1]) {                    temp = arr[j];                    arr[j] = arr[j + 1];                    arr[j + 1] = temp;                }            }        }    }    //结合冒泡 + 定制    public static void bubble02(int[] arr, Comparator c) {        int temp = 0;        for (int i = 0; i < arr.length - 1; i++) {            for (int j = 0; j < arr.length; j++) {                //数组排序由c.compare(arr[j], arr[j + 1])返回的值决定                if (c.compare(arr[j], arr[j + 1]) > 0) { //动态绑定                    temp = arr[j];                    arr[j] = arr[j + 1];                    arr[j + 1] = temp;                }            }        }    }}

练习:

package com.hspedu.arrays_;

import java.util.Arrays;
import java.util.Comparator;


/**
 * @author 何江龙
 * @version 1.0
 */
public class ArrayExercise {
    public static void main(String[] args){
        Book[] books = new Book[4];
        books[0] = new Book("红楼梦",100);
        books[1] = new Book("金梅新",90);
        books[2] = new Book("青年文摘20年",5);
        books[3] = new Book("java从入门到放弃",300);

        Arrays.sort(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book book1 = (Book) o1;
                Book book2 = (Book) o2;
                double priceVal = book2.getPrice() - book2.getPrice();
                if (priceVal > 0) {
                    return -1;
                } else if (priceVal < 0) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });

//        Arrays.sort(books, new Comparator() {
//            @Override
//            public int compare(Object o1, Object o2) {
//                Book book1 = (Book) o1;
//                Book book2 = (Book) o2;
//                return book2.getName().length() - book1.getName().length();
//            }
//        });
        System.out.println(Arrays.toString(books));

    }
}
class Book {
    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

System类

System类常见方法和案例

BigInteger和BigDecimal类

介绍

BigInteger的常用方法

日期类

第一代日期类

第二代日期类

第三代日期类

本章习题

package com.hspedu.homework;/** * @author 何江龙 * @version 1.0 */public class HomeWork01 {    public static void main(String[] args) {        String str = "abcdef";        String reverse = null;        try {            reverse = reverse(str, 1, 4);        } catch (Exception e) {            System.out.println(e.getMessage());            return;        }        System.out.println(reverse);    }    /**     * 思路分析     * (1)先把方法定义明确     * (2)把String转成char[],应为char[]的元素是可以交换的     * (3)画出分析示意图     * (4)代码实现     */    public static String reverse(String str, int start, int end) {        //对输入的参数做一个验证        //重要的编程技巧        //(1)写出正确的情况        //(2)然后取反        if (!(str != null && start >=0 && end > start && end < str.length())) {            throw new RuntimeException("参数不正确");        }        char[] chars = str.toCharArray();        char temp = ' '; //交换辅助变量        for (int i = start, j = end; i < j; i++, j--) {            temp = chars[i];            chars[i] = chars[j];            chars[j] = temp;        }        //使用chars重新构建一个String返回即可        return new String(chars);    }}
package com.hspedu.homework;/** * @author 何江龙 * @version 1.0 */public class Homework02 {    public static void main(String[] args) {        String name = "jack";        String pwd = "123456";        String email = "jack@sohu.com";        try {            userRegister(name, pwd, email);            System.out.println("恭喜你,注册成功!");        } catch (Exception e) {            System.out.println(e.getMessage());        }    }    /**     * (1)先确定方法名(userRegister(String name, String pwd, String email)     * (2)针对输入的内容进行比较,如果发现有问题,就抛出异常,给出提示     * (3)单独写一个方法,判断密码是否全部是数字字符 boolean     */    public static void userRegister(String name, String pwd, String email){        //1.校验名字长度        int userLength = name.length();        if (!(userLength >= 2 && userLength <= 4)) {            throw RuntimeException("用户名长度为2或3或4");        }        //2.校验密码        if (!(pwd.length() == 6 && isDigital(pwd))) {            throw new RuntimeException("密码长度为6,要求全是数字");        }        //3.验证邮箱        int i = email.indexOf('@');        int i1 = email.indexOf('.');        if (!(i > 0 && i1 >i)) {            throw new RuntimeException("邮箱有问题");        }    }    //单独写一个方法,判断密码是否全部是数字字符 boolean    public static boolean isDigital(String str) {        char[] chars = str.toCharArray();        for (int i = 0; i < chars.length; i++) {            if (chars[i] < '0' || chars[i] > '9') {                return false;            }        }        return true;    }}
package com.hspedu.homework;import java.util.Locale;/** * @author 何江龙 * @version 1.0 */public class Homework03 {    public static void main(String[] args) {        String name = "Han shun Ping";        printName(name);    }    /**     * 编写方法:完成输出格式要求的字符串     * 思路分析     * (1)对输入的字符串进行 分割split("")     * (2)对得到的String[] 进行格式化String.format()     * (3)对输入的字符串进行校验即可     */    public static void printName(String str) {        if (str == null) {            System.out.println("str 不能为空");            return;        }        String[] names = str.split(" ");        if (names.length != 3) {            System.out.println("输入的字符串格式不对");            return;        }        String format = String.format("%s,%s .%c", names[2], names[0], names[1].toUpperCase().charAt(0));        System.out.println(format);    }}
package com.hspedu.homework;/** * @author 何江龙 * @version 1.0 */public class Homework04 {    public static void main(String[] args) {        String str = "abcHsp u 2134";        countStr(str);    }    /**     * 思路分析     * (1)遍历字符串,如果char 在字符 0~9 就是一个数字     * (2) 如果 char 在 字符 a~z,就是一个小写字母     * (3) 如果char 在字符 A~Z 就是一个大写字符     * (4) 使用三个变量来记录 统计结果     */    public static void countStr(String str) {        if(str == null) {            System.out.println("输入不能为null");            return;        }        int strLen = str.length();        int numCount = 0;        int lowerCount = 0;        int upperCount = 0;        int otherCount = 0;        for (int i = 0; i < strLen; i++) {            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {                numCount++;            } else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {                lowerCount++;            }else if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {                upperCount++;            } else {                otherCount++;            }        }        System.out.println("数字有 " + numCount);        System.out.println("小写字母有 " + lowerCount);        System.out.println("大写字母有 " + upperCount);        System.out.println("其他字符有有 " + otherCount);    }}

集合

集合的理解和好处

集合的框架体系图(背下来)

单列集合

双列集合

Collection接口和常用的方法

package com.hspedu.collection_;import java.util.ArrayList;import java.util.List;/** * @author 何江龙 * @version 1.0 */public class CollectionMethod {    @SuppressWarnings({"all"})    public static void main(String[] args) {        List list = new ArrayList();        // add: 添加单个元素        list.add("jack");        list.add(10);        list.add(true);        System.out.println("list=" + list);        //remove:删除指定元素//        list.remove(0);//删除第一个元素        list.remove(true);//指定删除某个元素        System.out.println("lsit=" + list);        //contains:查找元素是否存在        System.out.println(list.contains("jack")); //T        //size:获得元素个数        System.out.println(list.size());        //isEmpty:判断是否为空        System.out.println(list.isEmpty());        //clear:清空        list.clear();        System.out.println("list=" + list);        //addAll:添加多个元素        ArrayList list2 = new ArrayList();        list2.add("红楼梦");        list2.add("三国演义");        list.addAll(list2);        System.out.println("list=" + list);        //containsAll:查找多个元素是否都存在        System.out.println(list.containsAll(list2));        //removeAll:删除多个元素        list.add("聊斋");        list.removeAll(list2);        System.out.println("list=" + list); //[聊斋]    }}

Collection 接口遍历元素方式1-使用Iterator(迭代器)

package com.hspedu.collection_;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;/** * @author 何江龙 * @version 1.0 */public class CollectionIterator {    public static void main(String[] args) {        Collection col = new ArrayList();        col.add(new Book("三国演义", "罗贯中", 10.1));        col.add(new Book("小李飞刀", "古龙", 5.1));        col.add(new Book("红楼梦", "曹雪芹", 34.6));//        System.out.println("col=" + col);        //现在老师希望能够遍历col集合        //1.先得到col对应的迭代器        Iterator iterator = col.iterator();        //2.使用while循环遍历//        while (iterator.hasNext()) {//            //返回下一个元素,类型是Object//            Object obj = iterator.next();//            System.out.println("obj=" + obj);//        }        //快捷键使用itit        while (iterator.hasNext()) {            Object next =  iterator.next();            System.out.println("next=" + next);        }        //3.当退出while循环后,这时iterator迭代器,指向最后的元素//        iterator.next(); //NoSuchElementException//        4.如果希望再次遍历,需要重置我们的迭代器        iterator = col.iterator();//        使用while循环遍历        while (iterator.hasNext()) {            //返回下一个元素,类型是Object            Object obj = iterator.next();            System.out.println("obj=" + obj);        }    }}class Book {    private String name;    private String author;    private double price;    public Book(String name, String author, double price) {        this.name = name;        this.author = author;        this.price = price;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getAuthor() {        return author;    }    public void setAuthor(String author) {        this.author = author;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }    @Override    public String toString() {        return "Book{" +                "name='" + name + '\'' +                ", author='" + author + '\'' +                ", price=" + price +                '}';    }}

增强for 遍历

package com.hspedu.collection_;import java.util.ArrayList;import java.util.Collection;/** * @author 何江龙 * @version 1.0 */public class CollectionFor {    public static void main(String[] args) {        Collection col = new ArrayList();        col.add(new Book("三国演义", "罗贯中", 10.1));        col.add(new Book("小李飞刀", "古龙", 5.1));        col.add(new Book("红楼梦", "曹雪芹", 34.6));        //使用增强for,在collection集合        //增强for,底层还是迭代器        //增强for可以理解成就是简化版的 迭代器遍历        //快捷键//        for (Object book : col) {//            System.out.println("book=" + book);//        }        for (Object o : col) {            System.out.println("book=" + o);        }    }}

list 接口方法

list接口的常用方法

list接口三种遍历方法

list接口的排序方法

ArrayList 底层结构和源码分析

ArrayList 的注意事项

ArrayList的底层操作机制源码分析(重点)

无参构造器底层源码追溯

package com.hspedu.collection_;import java.util.ArrayList;import java.util.Arrays;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class ArrayListSource {    public static void main(String[] args) {        //注意IDEA默认情况下,Debug显示的数据是简化后的,要看完整数据需要做设置        //使用无参构造器创建ArrayList对象        ArrayList list = new ArrayList();        //使用for给list集合添加1-10数据        for (int i = 1; i <= 10; i++) {            list.add(i);        }        //使用for给list集合添加11-15数据        for (int i = 11; i <= 15; i++) {            list.add(i);        }        list.add(100);        list.add(200);        list.add(null);    }}

Vector底层结构和源码刨析

Vector的基本介绍

Vector和ArrayList的比较

LinkedList的底层结构

LinkedList的全面说明

LinkedList 的底层操作机制

ArrayList 和LinkedList 的比较

Set接口和常用方法

Set 接口基本介绍

set 接口常用方法

HashSet的全面说明

HashSet 的底层机制说明

练习题:

package com.hspedu.hashset_;import java.util.HashSet;import java.util.Objects;/** * @author 何江龙 * @version 1.0 */public class Hashsetexercise_ {    /**     * 定义一个Employee 类,该类包含private 成员属性name,sal,     * birthday(MyDate类型),其中birthday为MyDate类型(属性包括:year,     * month,day),要求:     * 1.创建3个Employee放入HashSet     * 2.当name和birthday的值相同,认为是相同员工,不能添加到HashSet集合中     */    public static void main(String[] args) {        HashSet hashSet = new HashSet();        System.out.println(hashSet.add(new Employee("何江龙", 2000, new MyDate(12, 2, 3))));        System.out.println(hashSet.add(new Employee("何江龙", 2000, new MyDate(12, 2, 3))));    }}class Employee {    private String name;    private double sal;    private MyDate birthday;    public Employee(String name, double sal, MyDate birthday) {        this.name = name;        this.sal = sal;        this.birthday = birthday;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getSal() {        return sal;    }    public void setSal(double sal) {        this.sal = sal;    }    public MyDate getBirthday() {        return birthday;    }    public void setBirthday(MyDate birthday) {        this.birthday = birthday;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Employee employee = (Employee) o;        return Double.compare(employee.sal, sal) == 0 && Objects.equals(name, employee.name) && Objects.equals(birthday, employee.birthday);    }    @Override    public int hashCode() {        return Objects.hash(name, sal, birthday);    }}class MyDate {    private int year;    private int month;    private int day;    public MyDate(int year, int month, int day) {        this.year = year;        this.month = month;        this.day = day;    }    public int getYear() {        return year;    }    public void setYear(int year) {        this.year = year;    }    public int getMonth() {        return month;    }    public void setMonth(int month) {        this.month = month;    }    public int getDay() {        return day;    }    public void setDay(int day) {        this.day = day;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        MyDate myDate = (MyDate) o;        return year == myDate.year && month == myDate.month && day == myDate.day;    }    @Override    public int hashCode() {        return Objects.hash(year, month, day);    }}

Set接口实现类——LinkedHashSet

LinkedHashSet底层机制示意图

练习题:

package com.hspedu.LinkedHashSet;import java.util.LinkedHashSet;import java.util.Objects;import java.util.Set;/** * @author 何江龙 * @version 1.0 */public class LinkedHashSetExercise {  /**   * Car类(属性:name,price),如果name和price一样,   * 则认为是相同元素不能添加   */@SuppressWarnings({"all"})  public static void main(String[] args) {      Set linkedHashSet = new LinkedHashSet();      System.out.println(linkedHashSet.add(new Car("box", 299999)));      System.out.println(linkedHashSet.add(new Car("box", 299999)));      System.out.println(linkedHashSet.add(new Car("bos", 299999)));  }}class Car {    private String name;    private double price;    public Car(String name, double price) {        this.name = name;        this.price = price;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Car car = (Car) o;        return Double.compare(car.price, price) == 0 && Objects.equals(name, car.name);    }    @Override    public int hashCode() {        return Objects.hash(name, price);    }}

Map接口和特点

Map体系的继承图

Map接口常用方法

Map接口遍历方法

练习题:

package com.hspedu.map_;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class MapExercise {    public static void main(String[] args) {        Map map = new HashMap();        map.put(1,new Emp("jack", 1, 12000));        map.put(2,new Emp("tom", 2, 200000));        map.put(3,new Emp("milan", 3, 32000));        //遍历的2种方式        //1.使用keSet ->增强for        Set keys = map.keySet();        for (Object key : keys) {            //先获取value            Emp emp = (Emp)map.get(key);            if (emp.getSal() > 18000) {                System.out.println(emp);            }        }        //2.使用EntrySet -> 迭代器 体现出不断包装  entrySet -> Node -> value        Set entrySet = map.entrySet();        Iterator iterator = entrySet.iterator();        while (iterator.hasNext()) {            Map.Entry entry = (Map.Entry) iterator.next();            //通过entry获得key和value            Emp emp = (Emp) entry.getValue();            if (emp.getSal() > 18000) {                System.out.println(emp);            }        }    }}@SuppressWarnings({"all"})class Emp {    private String name;    private int id;    private double sal;    public Emp(String name, int id, double sal) {        this.name = name;        this.id = id;        this.sal = sal;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public double getSal() {        return sal;    }    public void setSal(double sal) {        this.sal = sal;    }    @Override    public String toString() {        return "Emp{" +                "name='" + name + '\'' +                ", id=" + id +                ", sal=" + sal +                '}';    }}

HashMap小结

Map接口实现类HashMap

HashMap底层机制和源码刨析

package com.hspedu.map_;import java.util.HashMap;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class HashMapSource01 {    public static void main(String[] args) {        HashMap map = new HashMap();        map.put("java", 10);        map.put("php", 10);        map.put("java", 20);        System.out.println("map = " + map);        /*1.执行构造器 new HashMap()         初始化加载因子 loadfactor = 0.75         HashMap$Node[] table = null        2. 执行put 调用hash方法,计算key的 hash 值        public V put(K key, V value) { //K = "java" value = 10            return putVal(hash(key), key, value, false, true);        }         static final int hash(Object key) {            int h;            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);         }        3.执行putVal         final V putVal(int hash, K key, V value, boolean onlyIfAbsent,                   boolean evict) {        Node[] tab; Node p; int n, i;        //如果底层的table 数组为null,或者length = 0,就扩容到16        if ((tab = table) == null || (n = tab.length) == 0)            n = (tab = resize()).length;        //取出hash值对应的table的索引位置的Node,如果为null,就直接把加入的k-v        //创建一个Node,加入该位置即可        if ((p = tab[i = (n - 1) & hash]) == null)            tab[i] = newNode(hash, key, value, null);        else {            Node e; K k; //辅助变量            if (p.hash == hash && //如果table的索引位置的key的hash和新的key的hash值相同,            //并满足 (table现有的节点的key和准备添加key是同一个对象 || equals返回真            //就认为不能加入新的k-v                ((k = p.key) == key || (key != null && key.equals(k))))                e = p;            else if (p instanceof TreeNode)//如果当前table已有的Node是红黑树,就按照红黑树的的方式处理                e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);            else {            //如果找到的节点,后面是链表,就循环比较                for (int binCount = 0; ; ++binCount) {//死循环                    if ((e = p.next) == null) { //如果整个链表没有和他相同,就加到该链表的最后                        p.next = newNode(hash, key, value, null);                        //加入后判断当前链表的个数,是否已经到8个,到8个后                        //就调用treeifyBin方法进行红黑树的转换                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st                            treeifyBin(tab, hash);                        break;                    }                    if (e.hash == hash && //如果在循环比较过程中,发现有相同,就break,就只替换value                        ((k = e.key) == key || (key != null && key.equals(k))))                        break;                    p = e;                }            }            if (e != null) { // existing mapping for key                V oldValue = e.value;                if (!onlyIfAbsent || oldValue == null)                    e.value = value;                afterNodeAccess(e);                return oldValue;            }        }        ++modCount; //每增加一个Node,就size++        if (++size > threshold)//如果size > threshold 就扩容            resize();        afterNodeInsertion(evict);        return null;    }    5. 关于树化    //如果table为null,或者大小还没有到64,暂时不树化,而是进行扩容    //否则才会真正的树化         */    }}
package com.hspedu.map_;import java.util.HashMap;import java.util.Objects;/** * @author 何江龙 * @version 1.0 */public class HashMapSource02 {    public static void main(String[] args) {        HashMap hashMap = new HashMap();        for (int i = 1; i < 12 ; i++) {            hashMap.put(new A(i), "hello");        }        System.out.println("hashMap=" + hashMap);    }}class A {    private int num;    public A(int num) {        this.num = num;    }    @Override    public String toString() {        return "A{" +                "num=" + num +                '}';    }    //所有A对象的hashCode都是一样的    @Override    public int hashCode() {        return 100;    }}

Map接口实现类-Hashtable

HashTable的基本介绍

package com.hspedu.map_;import java.util.Hashtable;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class HashTableExercise {    public static void main(String[] args) {        Hashtable table = new Hashtable();        //table.put(null, 100);异常NullPointerException        //table.put("john", 100); 异常NullPointerException        table.put("lucy", 100);        table.put("lic", 100);        table.put("lic", 88);        table.put("hello1", 1);        table.put("hello2", 1);        table.put("hello3", 1);        table.put("hello4", 1);        table.put("hello5", 1);        table.put("hello6", 1);        table.put("hello7", 1);        table.put("hello8", 1);        table.put("hello9", 1);        table.put("hello10", 1);        table.put("hello11", 1);        table.put("hello12", 1);        System.out.println(table);        //Hashtable的底层        //1.底层有数组Hashtable$Entry[] 初始化大小为11        //2.临界值 threshold 8 = 11 * 0.75        //3.扩容:        //4.执行方法 addEntry(hash,key,value,index);添加k-v封装到Entry        //5.当if(count >= threshold)满足时,就进行扩容        //按照 两倍加一的大小扩容    }}

Map接口实现类-Properties

基本介绍

package com.hspedu.map_;import java.util.Properties;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class Properties_ {    public static void main(String[] args) {        //1.Properties 继承 Hashtable        //2.可以通过k-v 存放数据,当然key 和value不能为null        //增加        Properties properties = new Properties();        properties.put("john",100);//        properties.put(null, "abc"); //抛出空指针异常        properties.put("john", 100);        properties.put("lucy", 100);        properties.put("lic", 100);        properties.put("lic", 80);        //通过k 获取对应值        System.out.println(properties.get("lic"));        //删除        properties.remove("lic");        System.out.println("properties=" + properties);        //修改        properties.put("john","he");        System.out.println("properties = " + properties);    }}

TreeSet 和TreeMap

package com.hspedu.hashset_;import java.util.Comparator;import java.util.TreeSet;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class TreeSet_ {    public static void main(String[] args) {        //1.当我们使用无参构造器,创建TreeSet时,还是无序的        //2.按照字符串大小来排序        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)        //并指定排序规则        TreeSet treeSet = new TreeSet(new Comparator() {            @Override            public int compare(Object o1, Object o2) {                //调用String的compareTo方法,进行字符串大小比较                return ((String)o1).compareTo((String)o2);            }        }        );        //添加数据        treeSet.add("jack");        treeSet.add("tom");        treeSet.add("sp");        treeSet.add("a");        //1.构造器把传入的比较器对象,赋给TreeSet 底层的TreeMap        /*         public TreeMap(Comparator<? super K> comparator) {             this.comparator = comparator;        }        2. 在调用 treeset.add("tom"),在底层会执行到    if (cpr != null) { //cpr 是我们的匿名内部类(对象)            do {                parent = t;                cmp = cpr.compare(key, t.key);//动态绑定到我们匿名内部类(对象)                if (cmp < 0)                    t = t.left;                else if (cmp > 0)                    t = t.right;                else //如果相等,即返回0,这个Key就没有加入进去                      return t.setValue(value);            } while (t != null);        }         */    }}

总结- 开发中选择集合实现类

Collection 工具类

package com.hspedu.collections_;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class Collections_ {    public static void main(String[] args) {        //创建ArrayList集合,用于测试        List list = new ArrayList();        list.add("tom");        list.add("smith");        list.add("king");        list.add("milan");        //reverse(list): 反转List中元素的顺序        Collections.reverse(list);        System.out.println("list=" + list);        //shuffle(list):对list集合元素进行随机排序        Collections.shuffle(list);        System.out.println("list = " + list);        //sort(list):根据元素的自然顺序对指定的list集合元素按升序排序        Collections.sort(list);        System.out.println("自然排序后:" + list);        //sort(list, Comparator):根据知道你过的comparator产生的顺序对list集合元素排序        Collections.sort(list, new Comparator() {            @Override            public int compare(Object o1, Object o2) {                //可以加入校验代码:if(o1 instanceof String)                return ((String) o1).length() - ((String) o2).length();            }        });        //swap(List,int,int):将指定list集合中的i处元素和j处元素进行交互        Collections.swap(list, 2, 1);        System.out.println("list=" + list);        //Object max(Collection):根据元素的自然排序,返回给定集合中最大元素        System.out.println("自然顺序最大元素:" + Collections.max(list));        //Object max(Collection, Comparator):根据Comparator指定的舒徐,返回给定集合中最大元素        Object maxObject = Collections.max(list, new Comparator() {            @Override            public int compare(Object o1, Object o2) {                return ((String) o1).length() - ((String) o2).length();            }        });        System.out.println("长度最大的元素:" + maxObject);        //Object min(Collection)        //Object min(Collection, Comparatro)        //int frequency(Collection, Object):返回指定集合中指定元素出现的次数        System.out.println("tom出现的次数" + Collections.frequency(list, "tom"));        //void copy(list dest, List src):将src中的内容复制到dest中        ArrayList dest = new ArrayList();        //需要先给dest赋值,大小和list.size()一样        for (int i = 0; i < list.size(); i++) {            dest.add("");        }        Collections.copy(dest,list);        System.out.println("dest=" + dest);        //boolean replaceAll(List list, Object oldVal, Object newVal):使用心智替换list对象中所有旧只        Collections.replaceAll(list,"tom","汤姆");        System.out.println("list" + list);    }}

本章练习:

package com.hspedu.homework14;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class Homework01 {    /*     */    public static void main(String[] args) {        List list = new ArrayList();        list.add(new news("新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴"));        list.add(new news("男子突然想起2个月前钓的鱼还在网兜,捞起一看赶紧放生"));//        Collections.reverse(list);//        System.out.println(list);        int size = list.size();        for (int i = size - 1; i >= 0; i++) {            news nw = (news) list.get(i);            System.out.println(processTitle(nw.getTitle()));        }    }    public static String processTitle(String title) {        if (title == null) {            return "";        }        if (title.length() > 15) {            return title.substring(0, 15) + "....";        } else {            return title;        }    }}class news{    private String title;    private String body;    public news(String title) {        this.title = title;    }    public news(String title, String body) {        this.title = title;        this.body = body;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public String getBody() {        return body;    }    public void setBody(String body) {        this.body = body;    }    @Override    public String toString() {        return "news{" +                "title='" + title + '\'' +                '}';    }}
package com.hspedu.homework14;import java.util.ArrayList;import java.util.Iterator;import java.util.List;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class Homework02 {    public static void main(String[] args) {        Car car = new Car("宝马", 400000);        Car car1 = new Car("宾利", 5000000);        List arrayList = new ArrayList();        arrayList.add(car);        arrayList.add(car1);        arrayList.remove(car);        arrayList.contains(car);        System.out.println("集合有多少个元素" + arrayList.size());        arrayList.isEmpty();        arrayList.clear();        List list1 = new ArrayList();        list1.add(car);        list1.add(car1);        arrayList.addAll(list1);        arrayList.containsAll(list1);        arrayList.removeAll(list1);        arrayList.addAll(list1);        for (Object o : arrayList) {            Car car2 = (Car) o;            System.out.println(car2);        }        Iterator iterator = arrayList.iterator();        while (iterator.hasNext()) {            Car car2 = (Car)iterator.next();            System.out.println(car2);        }    }}@SuppressWarnings({"all"})class Car {    private String name;    private double price;    public Car(String name, double price) {        this.name = name;        this.price = price;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getPrice() {        return price;    }    public void setPrice(double price) {        this.price = price;    }    @Override    public String toString() {        return "Car{" +                "name='" + name + '\'' +                ", price=" + price +                '}';    }}
package com.hspedu.homework14;import java.util.*;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class Homework03 {    public static void main(String[] args) {        Map map = new HashMap();        map.put("jack", 650); //int -> Integer        map.put("tom", 1200);        map.put("smith", 2900);        map.put("jack", 2600);        Set keys = map.keySet();        for(Object key : keys) {            //更新            map.put(key, (Integer) map.get(key) + 100);        }        System.out.println(map);        //遍历        Set entrySet = map.entrySet();        //迭代器        Iterator iterator = entrySet.iterator();        while (iterator.hasNext()) {            Map.Entry entry = (Map.Entry)iterator.next();            System.out.println(entry.getKey() + "-" + entry.getValue());        }        Collection values = map.values();        for (Object value : values) {            System.out.println("工资" + value);        }    }}

泛型

泛型的好处

泛型介绍

泛型语法

使用举例:

package com.hspedu.generic.improve;import java.util.*;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class GenericExercise {    public static void main(String[] args) {        //使用泛型方式给HashSet 放入3个学生对象        HashSet students =  new HashSet();        students.add(new Student("jack", 18));        students.add(new Student("tom", 28));        students.add(new Student("mary", 19));        //遍历        for (Student student : students) {            System.out.println(student);        }        //使用泛型方式给HashMap 放入3个学生对象        HashMap hm = new HashMap();        hm.put("milan", new Student("milan", 28));        hm.put("smith", new Student("smith", 48));        hm.put("hsp", new Student("hsp", 28));        //迭代器        Set> entries = hm.entrySet();        Iterator> iterator = entries.iterator();        while (iterator.hasNext()) {            Map.Entry next = iterator.next();            System.out.println(next.getKey() + "-" + next.getValue());        }    }}@SuppressWarnings({"all"})class Student {    private String name;    private int age;    public Student(String name, int age) {        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

泛型使用的注意事项和细节

习题:

package com.hspedu.generic.improve;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;/** * @author 何江龙 * @version 1.0 */@SuppressWarnings({"all"})public class GenericExercise02 {    public static void main(String[] args) {        ArrayList employees = new ArrayList<>();        employees.add(new Employee("smith", 2300, new MayDate(1, 23, 2003)));        employees.add(new Employee("dog", 3200, new MayDate(3, 30, 2001)));        employees.add(new Employee("mack", 43000, new MayDate(5, 22, 2004)));        employees.sort(new Comparator() {            @Override            public int compare(Employee emp1, Employee emp2) {                //首先比较员工的姓名                //首先对参数进行验证                if (!(emp1 instanceof Employee && emp2 instanceof Employee)) {                    return 0;                }                //比较name                int i = emp1.getName().compareTo(emp2.getName());                if (i != 0) {  //如果名字不同,直接返回                    return i;                }                //名字相同,比较出生年月                return emp1.getBirthday().compareTo(emp2.getBirthday());            }        });        System.out.println(employees);    }}class Employee {    private String name;    private double sal;    private MayDate birthday;    public Employee(String name, double sal, MayDate birthday) {        this.name = name;        this.sal = sal;        this.birthday = birthday;    }       public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public double getSal() {        return sal;    }    public void setSal(double sal) {        this.sal = sal;    }    public MayDate getBirthday() {        return birthday;    }    public void setBirthday(MayDate birthday) {        this.birthday = birthday;    }    @Override    public String toString() {        return "Employee{" +                "name='" + name + '\'' +                ", sal=" + sal +                ", birthday=" + birthday +                '}';    }}class MayDate implements Comparable{    private int month;    private int day;    private int year;    public MayDate(int month, int day, int year) {        this.month = month;        this.day = day;        this.year = year;    }    public int getMonth() {        return month;    }    public void setMonth(int month) {        this.month = month;    }    public int getDay() {        return day;    }    public void setDay(int day) {        this.day = day;    }    public int getYear() {        return year;    }    public void setYear(int year) {        this.year = year;    }    @Override    public String toString() {        return "MayDate{" +                "month=" + month +                ", day=" + day +                ", year=" + year +                '}';    }    @Override    public int compareTo(MayDate o) {        //比较年份        int yearMinus = getYear() - o.getYear(); //当前对象和o之间的比较        if (yearMinus != 0) { //如出生年份不同            return yearMinus;        }        //比较月份        int monthMinus = getMonth() - o.getMonth();        if (monthMinus != 0) {            return monthMinus;        }        //比较天数         return getDay() - o.getDay();    }}

自定义泛型

自定义泛型接口

基本语法

应用实例

自定义泛型方法

泛型的继承和通配符说明

泛型的继承和通配符说明

JUnit

基本介绍

package com.hspedu.junit_;

import org.junit.jupiter.api.Test;

/**
 * @author 何江龙
 * @version 1.0
 */
public class JUnit {
    public static void main(String[] args) {

    }
    @Test
    public void m1() {
        System.out.println("m1方法被调用");
    }
    @Test
    public void m2() {
        System.out.println("m2方法被调用");
    }
}




本章习题:

package com.hspedu.exercise;

import org.junit.jupiter.api.Test;

import java.util.*;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {

    }
    @Test
    public void testList() {
        //给T指定类型是User
        DAO dao = new DAO<>();
        dao.save("001",new User(1, 10,"jack"));

        List list = dao.list();
        System.out.println(list);
        
        
    }
}
class DAO {
    Map map = new HashMap<>();
    //保存T类型的对象到Map成员变量中
    public void save(String id, T entity) {
        map.put(id, entity);
    }

    //从map中获取id对应的对象
    public T get(String id) {
        return map.get(id);
    }

    //替换map中key为id内容,改为entity对象
    public void update(String id, T entity) {
        map.put(id, entity);
    }

    //返回map中存放的所有T对象
    public List list() {
        List list = new ArrayList<>();

        //遍历map
        Set keySet = map.keySet();
        for (String key : keySet) {
            list.add(get(key));
        }
        return list;
    }

    //删除指定id对象
    public void delete(String id) {
        map.remove(id);
    }

}

class User {
    private int id;
    private int age;
    private String name;

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

坦克大战

Java绘图技术

快速入门

绘图原理

package com.hspedu.draw;

import javax.swing.*;
import java.awt.*;

/**
 * @author 何江龙
 * @version 1.0
 * 如何在面板上画出圆形
 */
public class DrawCircle extends JFrame{ //相当于画框
    //定义一个面板
    private MyPanel mp = null;
    public static void main(String[] args) {
        new DrawCircle();
    }

    public DrawCircle() { //构造器
        //初始化面板
        mp = new MyPanel();
        //把面板放入到画框
        this.add(mp);
        //设置窗口大小
        this.setSize(400, 300);
        //单点击窗口退出,就能够退出
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

//1.先定义一个面板MyPanel,继承JPanel,画图形
class MyPanel extends JPanel {
    //说明:
    //1.MyPanel 对象就是一个画板
    //2.Graphics g 把g 理解成画笔
    //3.Graphics 提供很多画图的方法
    @Override
    public void paint(Graphics g) { //绘图方法
        super.paint(g); //调用父类的方法完成初始化
        //画出一个圆形
        g.drawOval(10, 10, 100, 100);
    }
}

Graphics类

Java事件处理机制

基本说明

实例:

package com.hspedu.event;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * @author 何江龙
 * @version 1.0
 * 小球通过键盘控制上下左右移动,讲解Java的事件控制
 */
public class BallMove extends JFrame{
    MyPanel mp = null;
    public static void main(String[] args) {
        BallMove ballMove = new BallMove();
    }
    //构造器
    public BallMove() {
        mp = new MyPanel();
        this.add(mp);
        this.setSize(400, 300);
        //窗口JFrame 对象可以监听键盘事件,即可以监听到面板发生的键盘事件
        this.addKeyListener(mp); //接口可以指向实现该接口的实例对象
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

//面板
//keyListener是一个监听器,可以监听键盘事件
class MyPanel extends JPanel implements KeyListener {
    //为了小球可以移动,把他的左上角坐标(x,y)设置变量
    int x = 10;
    int y = 10;
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillOval(x, y, 20, 20);
    }

    //有字符输出时,该方法就会触发
    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当某个键按下,该方法就会触发
    @Override
    public void keyPressed(KeyEvent e) {
        //根据用户按下不同键,来处理小球移动
        if (e.getKeyCode() == KeyEvent.VK_DOWN) { //KeyEvent.VK_DOWN就是向下箭头对应的code
            y++;
        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
            y--;
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            x--;
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            x++;
        }

        //让面板充型绘画
        this.repaint();
    }

    //当某个键松开,该方法就会触发
    @Override
    public void keyReleased(KeyEvent e) {

    }
}

事件处理机制深入了解

代码:

package com.hspedu.tankgame2.tankgame;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Tank {
    private int x;//坦克的横坐标
    private int y; //坦克的纵坐标
    private int direct; //坦克方向 0 1 2 3
    private int speed = 3;

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getDirect() {
        return direct;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    //上右下左移动
    public void moveUp() {
        y -= speed;
    }

    public void moveRight() {
        x += speed;
    }

    public void moveDown() {
        y += speed;
    }

    public void moveLeft() {
        x -= speed;
    }
}

package com.hspedu.tankgame2.tankgame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * @author 何江龙
 * @version 1.0
 */
public class MyPanel extends JPanel implements KeyListener {
    //定义我的坦克
    Hero hero = null;
    Vector enemyTanks = new Vector<>();
    int enemyTanksSize = 3;

    public MyPanel() {
        hero = new Hero(100, 100); //初始化自己的坦克
//        hero.setSpeed(4);//控制我方坦克的速度

        //初始化敌人坦克情况
        for (int i = 0; i < enemyTanksSize; i++) {
            //创建敌人坦克
            EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
            //改变敌人坦克面向方向
            enemyTank.setDirect(2);
            //添加到集合中
            enemyTanks.add(enemyTank);
        }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0 , 1000, 750); //填充矩形,默认为黑色

        //画出我方坦克-方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);

        //画出敌方坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
        }
    }

    /**
     *
     * @param x 坦克左上角x坐标
     * @param y 坦克左上角y坐标
     * @param g 画笔
     * @param direct 坦克方向
     * @param type 坦克类型
     */
    //编写方法,画出坦克
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
        //根据不同类型的坦克,设置颜色
        switch (type) {
            case 0: //自己的坦克
                g.setColor(Color.cyan);
                break;
            case 1://敌人的坦克
                g.setColor(Color.yellow);
                break;
        }

        //根据坦克的方向,来绘制对应形状坦克
        //0:向上 1:向右 2:向下 3:向左
        switch (direct) {
            case 0: //0表示向上
                g.fill3DRect(x, y, 10, 60, false);// 画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);// 画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40,false);//画出坦克的盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y, x + 20, y + 30);//画出炮筒
                break;
            case 1: //0表示向右
                g.fill3DRect(x, y, 60, 10, false);// 画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);// 画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20,false);//画出坦克的盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //0表示向下
                g.fill3DRect(x, y, 10, 60, false);// 画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);// 画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40,false);//画出坦克的盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //0表示向左
                g.fill3DRect(x, y, 60, 10, false);// 画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);// 画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20,false);//画出坦克的盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
            default:
                System.out.println("暂时没有处理");
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //处理wasd 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
            //改变坦克方向
            hero.setDirect(0);
            //修改坦克坐标
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//按下d键
            hero.setDirect(1);
            //修改坦克坐标
            hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//按下s键
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//按下a键
            hero.setDirect(3);
            hero.moveLeft();
        }
        //让面板重绘
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

package com.hspedu.tankgame2.tankgame;

/**
 * @author 何江龙
 * @version 1.0
 */
public class EnemyTank extends Tank{
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

package com.hspedu.tankgame2.tankgame;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Hero extends Tank {
    public Hero(int x, int y) {
        super(x, y);
    }

}

package com.hspedu.tankgame2.tankgame;

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * @author 何江龙
 * @version 1.0
 */

//为了监听 键盘事件,实现KeyListener
public class HspTankGame02 extends JFrame {

    //定义MyPanel
    MyPanel mp = null;
    public static void main(String[] args) {
        HspTankGame02 hspTankGame01 = new HspTankGame02();
    }

    public HspTankGame02() {
        mp = new MyPanel();
        this.add(mp); //把面板
        this.setSize(1000, 750);
        this.addKeyListener(mp);//让JFrame 监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }


}

线程

线程的基本使用

创建线程的两种方式

线程使用案例-继承Thread类

方式1:

package com.hspedu.threaduse;

/**
 * @author 何江龙
 * @version 1.0
 * 演示通过继承Thread 类创建线程
 */
public class Thread01 {
    public static void main(String[] args) {
        //创建一个cat对象,可以当作线程使用
        Cat cat = new Cat();

        /*
        (1)
        public synchronized void start() {
            start0();
            }
        (2)
        start0() 是本地方法,是JVM调用,底层是c/c++实现
        //真正实现多线程的效果是start0(),而不是run
        private native void start0();
         */
        cat.start();  //启动线程
    }
}

//1.当一个类继承Thread类,该类就可以当作线程使用
//2.一般会重写run方法,写自己的业务代码
//3.run Thread类,实现了Runnable 接口的run方法
/*
     @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
 */
class Cat extends Thread {

    int times = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("喵喵,我是小猫咪" + (++times));
            //休眠1秒 ctrl + alt + t
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times == 8) {
                break; //当times等于8就退出
            }
        }
    }
}

线程使用案例-实现Runnable接口

方式2:

package com.hspedu.threaduse;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        //创建一个Thread对象,把dog对象(实现Runnalbe),放入Thread
        //这里使用设计模式[代理模式]
        Thread thread = new Thread(dog);
        thread.start();
    }
}

class Dog implements Runnable {

    int count = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("小狗叫" + (++count) + Thread.currentThread().getName());

            //休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                break;
            }
        }
    }
}

Runnalbe的使用: 创建一个实现接口Runnable的类,通过Thread类调用新创建的类,并使用start方法。因为动态绑定,运行start方法时会调用创建类的run()方法

线程使用案例 - 多线程执行

package com.hspedu.threaduse;

/**
 * @author 何江龙
 * @version 1.0
 * main线程启动两个子线程
 */
public class Thread03 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread = new Thread(t1);
        Thread thread1 = new Thread(t2);
        thread.start();
        thread1.start();
    }

}
class T1 implements Runnable {

    int count = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("hello, world" + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 50) {
                break;
            }
        }
    }
}
class T2 implements Runnable {

    int count = 0;
    @Override
    public void run() {
        while(true) {
            System.out.println("hi" + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 60) {
                break;
            }
        }
    }
}

线程终止

package com.hspedu.exit_;

/**
 * @author 何江龙
 * @version 1.0
 */
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        t1.start();

        Thread.sleep(10 * 1000);
        t1.setLoop(false);
    }
}
class T extends Thread {
    int count = 0;
    private boolean loop = true;
    @Override
    public void run() {
        while (loop) {

            try {
                Thread.sleep(50);//让当前线程休眠50ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("AThread 运行中" + (++count));
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

线程的常用方法

常用方法

课堂练习:

package com.hspedu.exit_;

/**
 * @author 何江龙
 * @version 1.0
 */
public class ThreadMethodExercise {
    public static void main(String[] args) throws InterruptedException {

        T1 t1 = new T1();
        Thread thread = new Thread(t1);
        for (int i = 0; i < 9; i++) {
            System.out.println("hi");
            Thread.sleep(1000);
            if (i == 5) {
                thread.start();
                thread.join();
            }
        }
    }

}
class T1 implements Runnable {

    int count = 0;
    @Override
    public void run() {
        while(true) {
            try {
                System.out.println("hello" + (++count));
                Thread.sleep(1000);
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) { //输出10次后退出
                break;
            }
        }
    }
}

用户线程和守护线程

线程的生命周期

线程的同步

线程的同步

同步具体方法-Synchronized

互斥锁

基本介绍

注意事项和细节

线程死锁

基本介绍

应用案例

线程释放锁

释放锁

以下操作不会释放锁

本章习题:

package com.hspedu.threaduse;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Locale;
import java.util.Random;
import java.util.Scanner;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {
        PrintNum printNum = new PrintNum();
        Key key = new Key(printNum);
        printNum.start();
        key.start();
    }
}
class PrintNum extends Thread {
    private boolean loop = true;
    Random random = new Random();
    public void setLoop(boolean loop) {
        this.loop = loop;
    }
    @Override
    public void run() {
        while (loop) {

                System.out.println(random.nextInt(100) + 1);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }



class Key extends Thread {
    private PrintNum printNum;



    public Key(PrintNum printNum) { //构造器中直接传入A类对象
        this.printNum = printNum;
    }

    private Scanner scanner = new Scanner(System.in);

    @Override
    public void run() {
        while (true) {
            System.out.println("请输入你的指令Q表示退出");
            char key = scanner.next().toUpperCase().charAt(0);
            if (key == 'Q') {
                printNum.setLoop(false);
                System.out.println("线程自己退出");
                break;
            }
        }
    }
}
package com.hspedu.threaduse;

/**
 * @author 何江龙
 * @version 1.0
 */
public class Homework02 {
    public static void main(String[] args) {
        User user = new User();
        Thread thread = new Thread(user);
        thread.setName("t1");
        Thread thread1 = new Thread(user);
        thread1.setName("t2");
        thread.start();
        thread1.start();
    }
}

//1.因为设计多个线程共享资源,所以使用Runnable方法
//2.
class User implements Runnable {
    private int money = 10000;

    @Override
    public void run() {
        while (true) {
            System.out.println(this.getClass().getName());
            //这里使用synchronized实现线程同步
            //多个线程执行到这里,就争夺this 对象,谁先争取到就先执行
            synchronized (this) {//
                //判断余额是否足够
                if (money < 1000) {
                    System.out.println("余额不够");
                    break;
                }
                money -= 1000;
                System.out.println(Thread.currentThread().getName() + "取出1000,当前余额=" + money);
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

转载韩顺平老师视频
https://space.bilibili.com/651245581?spm_id_from=333.788.b_765f7570696e666f.1