Java基础第二阶段
- 定义语法
- 访问方法
- 类变量使用注意事项和细节讨论
- 类方法基本介绍
- 类方法的调用
- 类方法使用的注意事项和细节讨论
- 理解mian方法语法
Java基础第二阶段
、类变量和类方法
定义语法
访问修饰符 static 数据类型 变量名;
static 访问修饰符 数据类型 变量名;
访问方法
类名.类变量名
对象名.类变量名【静态变量的访问修饰符的访问权限和范围和普通属性是一样的】
类变量使用注意事项和细节讨论
-
什么时候需要用类变量
当我们要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量),如:定义学生类,统计所有学生共交多少钱
-
类变量与实例变量(普通属性)区别
类变量是该类的所有对象共享的,而实例变量是每个对象共享的
-
加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
-
类变量可通过 类名.类变量名 或者 对象名.类变量名 来访问,但Java设计者推荐我们使用 类名.类变量名方式访问
-
实例变量不能通过 类名.类变量名 访问
-
类变量是类加载时就初始化了,也就是说,即使没有创建对象,只要类加载,就可以使用类变量
-
类变量的生命周期是随类的加载开始,随着类消亡而销毁
类方法基本介绍
访问修饰符 static 数据返回类型 方法名(){}
static 访问修饰符 数据返回类型 方法名(){}
类方法的调用
使用方式:类名.类方法名 或者 对象名.类方法名 【前提是满足访问修饰符的权限和范围】
类方法使用的注意事项和细节讨论
-
类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区
类方法中无this的参数
普通方法中隐含this的参数
-
类方法可以通过类名调用,也可以通过对象名调用
-
普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用
-
类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以
-
类方法(静态方法)中只能访问 静态变量或静态方法。
-
普通成员方法,既可以访问 普通方法(方法),也可以访问静态成员和非静态成员(必须遵守访问权限)
理解mian方法语法
- java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
- java虚拟机在执行main()方法是不必创建对象,所以该方法必须是static
- 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
- java执行的程序 参数1 参数2 参数3
特别提示:
- 静态方法main可以访问本类的静态方法
- 静态方法main不能访问本类的非静态方法
代码块
基本语法
[修饰符] {
? 代码;
};
说明:
- 修饰符可选,要写的话,只能写static
- 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通/非静态代码块
- 逻辑语句可以为任何逻辑语句
- ;可以写,也可以省略
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;
}
}
注意事项和细节讨论
-
static代码块叫做静态代码块,作用是对类进行初始化,并且随着类的加载而执行,并且只会执行一次。而普通代码块,每创建一个对象,就执行
-
类什么时候被加载
-
创建子类对象实例时
-
创建子类对象实例,父类也会被加载,而且父类先被加载,子类后被加载
-
使用类的静态成员(静态属性,静态方法)
-
-
普通代码块,在创建对象实例时,会被隐式调用。被创建一次,就会被调用一次。如果只使用类的静态成员时,普通代码块不会被执行。
-
创建一个对象时,在一个类调用顺序是:
- 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
- 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用
- 最后调用构造器
-
构造器最前面隐含super()和调用普通代码块 ,新写一个类演示,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。
-
创建一个子类对象(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下
- 父类静态代码块和静态属性(优先级一样,安定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,安定义顺寻执行)
- 父类的普通代码块和普通属性初始化(优先级一样,案定义顺序执行)
- 父类构造器
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类构造方法
-
静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员
单例模式
单例
- 所谓单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
- 单例模式两种方式:1)饿汉式 2)懒汉式
饿汉式(存在资源浪费问题)
- 将构造器私有化
- 在类的内部直接创建
- 提供一个公共的static方法,返回gf对象
懒汉式(存在线程安全问题)
-
构造器私有化
-
定义一个static静态属性对象
-
提供一个public的static方法,可以放回一个cat对象
-
只有当用户使用getInstance时,才返回cat对象,后面再次调用时,回访会上次创建cat对象,从而保持单例
final关键字
使用final时刻
-
我们要求某一个类不能被其他类继承,可以用 final 修饰
-
不希望父类的方法不被子类重写可以使用 final 修饰
-
当不希望类的某个属性的值被修改,可以用final修改
-
当不希望某个局部变量被修改,可以用final修饰
final使用注意事项和细节讨论
- final修饰的属性又叫做常量,一般用XX_XX_XX命名
- final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以再如下位置
- 在定义时:public final double TAX_RATE = 0.08
- 在构造器中
- 在代码块中
- 如果final修饰的属性是静态的(public static final ...),则初始化位置只能是
- 定义时
- 静态代码块
- 不能再构造器中赋值
- final类不能继承,但是可以实例化对象
- 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承,
- 一般来说,如果一个类是final类,就不需要再将方法修饰成final方法
- final不能修饰构造器
- final和static往往搭配使用,效率更高,不会导致类加载
- 包装类(Integer,Double,Float,Boolean等都是final)String也是final类,不能被继承
抽象类
抽象类介绍
- 用abstract 关键字修饰一个类时,这个类叫做抽象类 访问修饰符 abstract 类名 { }
- 用abstract 关键字修饰一个方法时,这个方法就是抽象方法 访问修饰符 abstract 返回类型 方法名 (参数列表); 没有方法体
- 抽象类的价值更多作用于设计,是设计者设计好后,让子类继承并实现抽象类
抽象类的细节
-
抽象类,不能被实例化
-
抽象类不一定要包含abstract方法,还能有实现方法
-
一旦类包含abstract方法,则这个类必须声明为abstract类
-
abstract 只能修饰类和方法,不能修饰属性和其他
-
抽象类可以有任意成员
-
抽象方法不能有主体
-
如果一个类继承抽象类,则它必须实现抽象类所有抽象方法,除非自己也是abstract方法
-
抽象方法不能使用private、final 和 static来修饰,这些关键字都是和重写相违背
抽象模板模式
接口
接口的基本介绍
接口就是给一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出。语法:
interface 接口名{
? //属性
? //方法 (1.抽象方法 2. 默认实现方法 3.静态方法)
class 类名 implements 接口{
? 自己属性
? 自己方法
? 必须实现的接口的抽象方法
总结:
-
在Jdk7.0前接口里的所有方法都没有方法体,都是抽象方法
-
Jdk8.0 后接口可以有静态方法,默认方法(default public void .....),也就是说接口中可以有方法的具体实现
接口的注意事项
-
接口不能被实例化,但可以指向 实现了接口的实例对象
-
接口中所有的方法是public方法,接口中抽象方法,可以不用abstract 修饰:
void aaa();实际上是 abstract void aaa();
-
一个普通类实现接口,必须将该接口的所有方法都实现,可以使用alt + enter 来解决
-
抽象类实现接口,可以不用实现接口的抽象方法
-
一个类同时可以实现多个接口
-
接口中的属性,只能是final的,而且是 public static final修饰符
-
接口中属性的访问形式:接口名.属性名
-
一个接口不能继承其他的类,但是可以继承多个别的接口
-
接口的修饰符只能是public 和默认,这点和类的修饰符是一样的
接口的多态性
- 多态参数:既可以接收手机对象,又可以接收相机对象,体现接口多态
- 多态数组:
- 接口存在多态传递现象
内部类
基本介绍
一个类的内部又完整的嵌套另一个类结构。被嵌套的类被称为内部类,嵌套其他类的类称为外部类,是我们类的第五大成员。最大特点:可以直接访问私有
属性、方法、构造器、代码块、内部类
基本语法
class Outer{ //外部类
? class Inner{ //内部类
? }
class Other{ // 外部其他类
内部类的分类
- 定义在外部类局部位置上,(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
- 定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用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)同时还是一个对象
-
匿名内部类的基本语法
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修饰
-
可以直接访问外部类的所有成员,包含私有的
-
可以添加任意访问修饰符(public, protected, 默认,private)因为它的地位就是一个成员
-
作用域和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。
-
成员内部类 可以 直接访问外部类
-
外部类 ------访问------》内部类 访问方式:创建对象,再访问
-
外部其他类 ------访问-------》成员内部类
第一种方式:
Outer08 outer08 = new Outer08();
Outer08.Inner08 innner08 = outer08.new Inner08();
? 第二种方式:在外部类中编写一个方法,可以返回Inner08对象
? Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
- 如果外部类和内部类中成员重名,会遵守就近原则,可以通过 外部类名.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修饰
-
可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
-
可以添加任意访问修饰符,(public,protected,默认,private),因为它就是一个成员
-
作用域:同其他成员一样,是整个类体
-
静态内部类 -------访问------》外部类(静态属性)访问方式:直接访问所有静态成员
-
外部类-------访问--------》静态内部类 访问方式: 创建对象, 再访问
-
外部其他类 使用静态内部类
第一种方法:静态内部类可以通过类名直接访问,要满足访问权限
Outer.Inner10 inner10 = new Outer10.Inner10();
? 第二种方法:编写一个方法,可以返回静态内部类的对象实例
- 如果外部类和静态内部类成员重名,静态内部类访问的顺序遵循就近原则,如果想访问外部类的成员,可以使用(外部类名.成员)访问。
枚举和注解
枚举(enumeration—简写enum),枚举是一组常量的集合,它是一种特殊的类,其中只有一组有限的特定对象
枚举实现方式
自定义实现枚举
- 不需要提供setXXX方法,因为枚举对象通常为只读
- 对枚举对象/属性使用final + static 共同修饰,实现底层优化
- 枚举对象名通常使用全部大写,常量的命名规则
- 枚举对象根据需要,也能有多个属性
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关键字实现注意事项
- 当我们使用enum 关键字开发一个枚举类时,默认会继承Enum类,并且是一个final类,使用javap进行演示
- 传统的 public static final Season2 SPRING = new Seanson2("春天","温暖");简化成SPRING("春天","温暖"),需要知道调用那个构造器
- 如果使用无参构造器 创建 枚举类,则实参列表和小括号都可以省略
- 当有多个枚举对象时,使用 , 间隔,最后有一个分号结尾
- 枚举对象必须放在枚举类的首行
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 注意事项
- 使用enum关键字后,不能再继承其他类,应为enum会隐式继承Enum,而Java是单继承机制
- 枚举类和普通类一样,可以实现接口,形式:enum 类名 implements 接口1,接口2 {}
注解
注解的理解
- 注解(Annotation)也被称为元数据(Metadata),用于修饰解释包,类,方法,属性,构造器,局部变量等数据信息
- 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息
- 在JavaSE中,注解使用目的比较简单,例如标记过时功能,忽略警告等。在JavaEE中注解占据更重要的角色,例如配置应用程序的任何切面,代替JavaEE旧版中遗留的繁冗代码和XML配置等。
基本Annotation介绍
使用Annotation时要在前面加上@符号,并把该Annotation当成一个修饰符使用,用于修饰它支持的程序元素
- @Override: 限定某个方法,重写父类方法,该注解只能用于方法
- @Deprecated: 用于表示某个程序元素(类,方法)已过时
- @SuppressWarnings: 抑制编译器警告
- SuppressWarnings的作用范围和放置的范围有关,通常我们可以放在类上
JDK的元注解
@Retention 注解(保留)
@Target
@Documented
@Inherited注解
异常(Exception)
基本概念
开发过程中逻辑错误和语法错误不算是异常
分类
- Error: java虚拟机无法解决严重问题。如:JVM系统内部错误,资源耗尽等严重情况。如:StackOverfError(栈溢出),OOM(out of memory)等
- Exception: 其它因编程错误或偶让的外在因素导致的一般性问题,可以使用针对性代码进行处理,如空指针访问,试图读取不存在的文件。Exception 可以分成两类:运行时异常[程序运行时,发生异常],编译时异常[编程时,编译器检查出异常]
异常体系图
-
异常分为编译时异常,和运行时异常
-
运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常
-
对于运行时异常,可以不做处理,因为这类异常很普遍,若全部处理可能会对程序的可读性和运行雄安路产生影响
-
编译时异常,是编译器要求必须处置的异常
常见运行时异常
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