1. 枚举类的使用
1.1 枚举类的理解
/* 一、枚举类:类的对象只有有限个,确定的。
*
* 二、举例如下:
* 星期:Monday(星期一)、......、Sunday(星期天)
* 性别:Man(男)、Woman(女)
* 季节:Spring(春节)......Winter(冬天)
* 支付方式:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、CreditCard(信用卡)
* 就职状态:Busy、Free、Vocation、Dimission
* 订单状态:Nonpayment(未付款)、Paid(已付款)、Delivered(已发货)、Return(退货)、Checked(已确认)、Fulfilled(已配货)
* 线程状态:创建、就绪、运行、阻塞、死亡
* * 三、当需要定义一组常量时,强烈建议使用枚举类
* * 补充:如果枚举类的对象只有一个,则也是单例模式的体现。
*/
1.2 如何创建枚举类
* 方式一:自定义类的方式
* 方式二:使用enum关键字 (jdk5.0)
- 方式一
public class EnumTest {
public static void main(String[] args) {
Season spring = Season.SPRING;
System.out.println(spring);
System.out.println(spring.getSeasonName());
System.out.println(spring.getSeasonDesc());
}
}
class Season{//季节
//对象的实例变量
private final String seasonName;//季节的名称
private final String seasonDesc;//季节的描述
//提供私有的构造器
private Season(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//内部提供4个枚举类的对象
public static final Season SPRING = new Season("春天","春暖花开");
public static final Season SUMMER = new Season("夏天","夏日炎炎");
public static final Season AUTUMN = new Season("秋天","秋高气爽");
public static final Season WINTER = new Season("冬天","白雪皑皑");
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
- 方式二
/**
* 使用enum定义枚举类
*
* 使用enum定义的枚举类默认继承于ava.lang.Enum类
*/
public class EnumTest1 {
public static void main(String[] args) {
Season1 spring = Season1.SPRING;
System.out.println(spring);
System.out.println(spring.getClass().getSuperclass());
}
}
enum Season1{//季节
//内部提供4个枚举类的对象
SPRING("春天","春暖花开"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
//对象的实例变量
private final String seasonName;//季节的名称
private final String seasonDesc;//季节的描述
//提供私有的构造器
private Season1(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
// @Override
// public String toString() {
// return "Season1{" +
// "seasonName='" + seasonName + '\'' +
// ", seasonDesc='" + seasonDesc + '\'' +
// '}';
// }
}
1.3 Enum类中的常用方法
1.4 枚举类的对象实现接口中的方法
/**
* 一、枚举类的使用
* 1. 枚举类的理解
* 2. 自定义类的方式,体现枚举类
* 3. jdk5.0:使用enum关键字定义
* 4. enum定义的方式中,常用的方法
* toString():没有重写的情况下,默认返回当前枚举类对象的名字
* values():返回当前枚举类所有的对象构成的数组
* valueOf(String name):返回指定名称的枚举类的对象
* 5. 枚举类的对象实现接口的操作
*
*/
public class EnumTest {
public static void main(String[] args) {
Season1 summer = Season1.SUMMER;
System.out.println(summer.getClass().getSuperclass());
System.out.println(summer.toString());
System.out.println("##############");
Season1[] season1s = Season1.values();
for (int i = 0; i < season1s.length; i++) {
System.out.println(season1s[i]);
season1s[i].show();
}
System.out.println("##############");
Season1 winter = Season1.valueOf("WINTER");
System.out.println(winter);
//如果枚举类中不存在指定名称的枚举类的对象的话,报IllegalArgumentException
// winter = Season1.valueOf("WINTER1");
// summer.show();
}
}
//enum Season1{//季节
// //内部提供4个枚举类的对象
// SPRING,
// SUMMER,
// AUTUMN,
// WINTER;
//
// //提供私有的构造器
// private Season1(){
//
// }
//
//}
interface Info{
void show();
}
enum Season1 implements Info{//季节
//内部提供4个枚举类的对象
SPRING("春天","春暖花开"){
public void show(){
System.out.println("春天在哪里?");
}
},
SUMMER("夏天","夏日炎炎"){
public void show(){
System.out.println("宁夏");
}
},
AUTUMN("秋天","秋高气爽"){
public void show(){
System.out.println("秋天不回来");
}
},
WINTER("冬天","白雪皑皑"){
public void show(){
System.out.println("大约在冬季");
}
};
//对象的实例变量
private final String seasonName;//季节的名称
private final String seasonDesc;//季节的描述
//提供私有的构造器
private Season1(String seasonName,String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
// @Override
// public void show() {
// System.out.println("这是一个季节");
// }
}
2. 注解的使用
2.1 注解的理解
/**
* 注解(Annotation)的使用
* * 1. jdk 5.0的新特性
* 2. Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。
* 3. Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明,
* 这些信息被保存在 Annotation 的 “name=value” 对中。
*/
- 注解的作用
2.2 Java阶段常见注解
在编译时进行格式检查(JDK内置的三个基本注解)
_@Override: 限定重写父类方法, 该注解只能用于方法
_@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
_@SuppressWarnings: 抑制编译器警告
2.3 如何定义注解
参照@SuppressWarnings定义。
/**
* 自定义注解
*
* 说明:
* Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。其方法名和返回值定义了该成员的名字和类型。我们称为配置参数。
* 类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上所有类型的数组。
*
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
String value();
}
2.4 元注解
/* 6. 元注解
* ① @Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 的生命周期
* 三种生命周期状态:SOURCE:字节码文件中不保存
* CLASS:会保留到字节码文件中,但是运行时内存中不保存。默认行为
* RUNTIME:运行时会保留到内存中。 可以后期通过反射获取。
* ② @Target: 用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。
* ③ @Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。
* 默认情况下,javadoc是不包括注解的。
* ④ @Inherited: 被它修饰的 Annotation 将具有继承性。
* 如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
*
*
* 上述的元注解中的@Retention、@Target一般在定义注解时,都会使用。
*/
2.5 注解的获取
如何通过反射获取注解信息(在反射章节讲)
3. 程序、进程、线程的理解
4. 如何创建多线程
4.1 继承Thread类
/**
* 创建一个分线程,用于遍历100以内的偶数
*
* 方式一:使用继承Thread类的方式
*
* 1. 创建一个继承于Thread类的子类
* 2. 重写Thread类的run() : 方法体的内容即为当前创建的线程要执行的操作
* 3. 创建子类的对象
* 4. 通过子类对象调用其start(): ① 启动线程 ② 调用当前线程的run()
*
*/
//1. 创建一个继承于Thread类的子类
class EvenNumber extends Thread {
int maxNumber;
public EvenNumber(int maxNumber){
this.maxNumber = maxNumber;
}
//2. 重写Thread类的run()
@Override
public void run() {
//遍历100以内的偶数
for(int i = 0;i <= maxNumber;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
public class EvenNumberTest {
public static void main(String[] args) {
//3. 创建子类的对象
EvenNumber thread1 = new EvenNumber(100);
//4. 通过子类对象调用其start()
thread1.start();
//问题一:能不能通过直接调用run()的方式替换start(),启动线程? No!
// thread1.run();
//问题二:需要再创建一个遍历100以内偶数的线程?如何做?
// thread1.start();//此时报IllegalThreadStateException异常。
//正确的:
EvenNumber thread2 = new EvenNumber(100);
thread2.start();
//遍历100以内的偶数
for(int i = 0;i <= 100;i++){
if(i % 2 == 0){
System.out.println(i + "*************");
}
}
}
}
4.2 实现Runnable接口
/**
* 遍历100以内的奇数。
*
* 方式二:实现Runnable接口的方式:
* 1. 提供实现Runnable接口的实现类
* 2. 实现接口中的抽象方法run():方法体的内容即为当前创建的线程要执行的操作
* 3. 创建实现类的对象
* 4. 将实现类的对象作为参数,传递到Thread类的构造器中,创建Thread类的对象
* 5. 通过Thread类的对象调用start():① 启动线程 ② 调用当前线程的run()
*
*
* 对比继承Thread类和实现Runnable接口的方式
* 1. 哪个更好?实现Runnable接口
* 2.
* ① 继承的方式受到类的单继承性的局限性的影响
* ② 对于多个线程操作共享数据的场景,实现的方式更适合。
* ③ 实现的方式更好的体现了数据与操作逻辑的分离。
* 3. 二者的联系:
* public class Thread implements Runnable
*
*/
//1. 提供实现Runnable接口的实现类
class OddNumber implements Runnable{
//2. 实现接口中的抽象方法run()
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i % 2 != 0){
System.out.println(i);
}
}
}
}
public class OddNumberTest {
public static void main(String[] args) {
//3. 创建实现类的对象
OddNumber o = new OddNumber();
//4. 将实现类的对象作为参数,传递到Thread类的构造器中,创建Thread类的对象
Thread t1 = new Thread(o);
//5. 通过Thread类的对象调用start()
t1.start();
// 再创建一个线程,用于遍历100以内的奇数
Thread t2 = new Thread(o);
t2.start();
System.out.println("========hello========");
}
}
- 练习题
/**
* 练习:创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数?
*/
class EvenNumber extends Thread{
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
class OddNumber extends Thread{
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i % 2 != 0){
System.out.println(i + "**********");
}
}
}
}
public class NumberTest {
public static void main(String[] args) {
// EvenNumber t1 = new EvenNumber();
// OddNumber t2 = new OddNumber();
//
// t1.start();
// t2.start();
//方式一:创建Thread类的匿名子类的匿名对象
// new Thread(){
// @Override
// public void run() {
// for (int i = 0; i <= 100; i++) {
// if(i % 2 == 0){
// System.out.println(i);
// }
// }
//
// }
// }.start();
//
// new Thread(){
// @Override
// public void run() {
// for (int i = 0; i <= 100; i++) {
// if(i % 2 != 0){
// System.out.println(i + "***************");
// }
// }
//
// }
// }.start();
//方式二:提供Runnable接口匿名实现类的匿名对象
new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i % 2 == 0){
System.out.println(i);
}
}
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if(i % 2 != 0){
System.out.println(i + "***********");
}
}
}
}).start();
}
}
- 例题
/**
*
* 例题:开启三个窗口售票,总票数为100张。
*
* 使用继承Thread类的方式实现
*
*/
class Window extends Thread{
static int ticket = 100;//初始票数100张
@Override
public void run() {
while(true){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "卖票,当前票号为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.start();
t2.start();
t3.start();
}
}
/**
*
* 例题:开启三个窗口售票,总票数为100张。
*
* 使用实现Runnable接口的方式
*
*/
class Window1 implements Runnable{
int ticket = 100;
@Override
public void run() {
while(true){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + "卖票,当前票号为:" + ticket);
ticket--;
}else{
break;
}
}
}
}
public class WindowTest1 {
public static void main(String[] args) {
Window1 w = new Window1();
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.start();
t2.start();
t3.start();
}
}
/* 对比继承Thread类和实现Runnable接口的方式
* 1. 哪个更好?实现Runnable接口
* 2.
* ① 继承的方式受到类的单继承性的局限性的影响
* ② 对于多个线程操作共享数据的场景,实现的方式更适合。
* ③ 实现的方式更好的体现了数据与操作逻辑的分离。
* 3. 二者的联系:
* public class Thread implements Runnable
*/
5. 线程中的常用方法
/**
* 测试Thread类中的常用方法
* 1. run(): 执行分线程的操作
* 2. start(): ① 启动线程 ② 调用线程的run()
* 3. currentThread():获取当前执行代码的线程
* 4. getName():获取线程的名称
* 5. setName():设置线程的名称
* 6. yield():一旦执行此方法,cpu就释放对当前线程的执行。
* 7. join(): 在线程a中调用了线程b的join(),此时线程a进入阻塞状态,
* 直到线程b执行结束之后,才结束阻塞状态继续执行。
* 8. sleep(long millis):静态方法,让当前线程“睡眠”指定的毫秒数
* 9. isAlive():是否存活
*
* 测试线程的优先级:
*
* getPriority():获取线程的优先级
* setPriority():设置线程的优先级
*
* 线程的优先级中: MIN_PRIORITY = 1
* NORM_PRIORITY = 5 (默认优先级)
* MAX_PRIORITY = 10
*
* 理解:高优先级的线程会抢占低优先级的线程的cpu资源。
* 此时的抢占是从概率上来讲,以更高的概率被cpu执行而已。
*
*/
class EvenNumber extends Thread {
@Override
public void run() {
//遍历100以内的偶数
for(int i = 0;i <= 100;i++){
if(i % 2 == 0){
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + ":" +
Thread.currentThread().getPriority() + ":" + i);
}
// if(i % 20 == 0){
// this.yield();
// }
}
}
}
public class ThreadMethodTest {
public static void main(String[] args) {
EvenNumber thread1 = new EvenNumber();
thread1.setName("线程1");
thread1.setPriority(Thread.MAX_PRIORITY);
thread1.start();
Thread.currentThread().setName("主线程");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
//遍历100以内的偶数
for(int i = 0;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" +
Thread.currentThread().getPriority() + ":" + i);
}
// if(i == 40){
// try {
// thread1.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// }
}
// System.out.println(thread1.isAlive());
}
}