18.枚举类、注解、多线程

本文详细介绍了Java中的枚举类,包括枚举的理解、创建方式、枚举类的常用方法以及如何实现接口。同时,探讨了注解的基本概念、作用、定义方式以及元注解。在多线程方面,讲解了通过继承Thread类和实现Runnable接口创建线程的区别和实践。最后,给出了多线程售票窗口的示例,展示了线程同步的重要性。
摘要由CSDN通过智能技术生成

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());
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值