JavaSE-汇总


前言

JavaSE 完结,撒花🌸🌸🌸,Java-基础的学习就将告一段落,今天我将之前发布的《Java-XXX》系列学习笔记进行汇总一下,此系列是我做的一个 “Java 从 0 到 1” 实验,给自己一年左右时间,按照我自己总结的 Java-学习路线,从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后的蜕变吧!<有同样想法的小伙伴,可以联系我一起交流学习哦!>

笔记汇总

环境配置

Mac M1 JDK安装

JDK 推荐使用 Zulu JDK,因为适配了 ARM 架构,下载 Download Azul Zulu Builds of OpenJDK

根据需求选择 .dmg 格式的 JDK 下载就可以了,下载后点击安装,按照步骤进行,完成后,在控制台输入java -version 查看是否安装成功

$ java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (Zulu 8.58.0.13-CA-macos-aarch64) (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (Zulu 8.58.0.13-CA-macos-aarch64) (build 25.312-b07, mixed mode)

Zulu JDK默认安装在/Library/Java/JavaVirtualMachines目录下

/usr/libexec/java_home -V #查看安装Java路径

多版本安装

参考:Mac下安装多个版本的JDK并随意切换

我安装了一个Zulu的JDK8 和一个HotSpot 的JDK8,所以进行如下配置

# Java config
## Zulu
export JAVA_Z8_HOME="/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home"
## HotSpot
export JAVA_H8_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_351.jdk/Contents/Home"

# config alias
alias jdkz8="export JAVA_HOME=$JAVA_Z8_HOME"
alias jdkh8="export JAVA_HOME=$JAVA_H8_HOME"

# config default jdk
export JAVA_HOME=$JAVA_Z8_HOME
export PATH="$JAVA_HOME:$PATH"
source ~/.zshrc

JDK版本切换

$ jdkz8
$ java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (Zulu 8.58.0.13-CA-macos-aarch64) (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (Zulu 8.58.0.13-CA-macos-aarch64) (build 25.312-b07, mixed mode)

$ jdkh8
$ java -version
java version "1.8.0_351"
Java(TM) SE Runtime Environment (build 1.8.0_351-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.351-b10, mixed mode)

IDEA插件

  1. Translation 翻译,可以翻译英文注释

  2. Alibaba Java Coding Guidelines 阿里巴巴编码规范检查工具(option+enter)

  3. SequenceDiagram 一个时序图插件,右键方法名能看到方法里整个的调用流程

  4. Rainbow Brackets 花括号和大括号颜色配对显示

  5. RestfulToolkit 可以通过 url 定位到 controller 和通过接口生成完整 url

  6. Randomness 可以在代码里生成随机数用来测试

  7. MyBatisX 添加从 mapper 跳转到对应 xml 的功能

  8. CamelCase 变量下划线转驼峰命名

  9. .ignore 可以生成 ignore 文件比如 .gitignore

  10. Key Promoter X 快捷键提示 鼠标操作后右下角会提示有什么快捷键能快速完成刚刚鼠标的操作

枚举

引入枚举

首先创建一个季节(Season) 对象

package com.jwt.enum_;

public class Enumeration01 {
    public static void main(String[] args) {
        //使用
        Season spring = new Season("春天", "温暖");
        Season winter = new Season("冬天", "寒冷");
        Season summer = new Season("夏天", "炎热");
        Season autumn = new Season("秋天", "凉爽");
        autumn.setName("XXX");//可以修改秋天的名字
        autumn.setDesc("非常的热..");//可以修改秋天的描述
        Season other = new Season("红天", "~~~");//可以增加其他季节
        System.out.println(autumn);
    }
}

class Season {
    private String name;
    private String desc;//描述

    public Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

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

}

Season 对象要有如下特点

  • 1.季节的值是有限的几个值(spring, summer, autumn, winter)

  • 2.季节只读,不需要修改。

上面代码的方法不满足上面的两个特点,要如何实现呢?答:使用枚举

枚举实现

枚举有二种实现方式:1.自定义类实现、2.使用 enum 关键字实现

  1. 枚举对应英文(enumeration, 简写enum)

  2. 枚举是一组常量的集合。

  3. 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。

自定义类实现枚举

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

public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season.AUTUMN);
        System.out.println(Season2.SUMMER);
    }
}

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 关键字实现枚举

  • 1.使用关键字 enum 替代 class
  • 2.定义常量对象方式:常量名(实参列表) eg:SPRING(“春天”, “温暖”)
  • 3.如果有多个常量(对象), 使用 “,” 号间隔,最后有一个分号结尾
  • 4.如果使用 enum 来实现枚举,要求将定义常量对象写在最前面
  • 5.如果我们使用的是无参构造器,创建常量对象,则可以省略()
package com.jwt.enum_;

public class Enumeration03 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        System.out.println(Season2.SUMMER);
    }
}

enum Season2 {
  
    SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
    SUMMER("夏天", "炎热")/*, 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 + '\'' +
                '}';
    }
}

注意事项

1.当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类,使用javap 工具可以看到

2.传统的public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成SPRING(“春天”, “温暖”), 这里必须知道,它调用的是哪个构造器

3.如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略

4.当有多个枚举对象时,使用 “,” 间隔,最后有一个分号结尾

5.枚举对象必须放在枚举类的行首

Javap 反编译上面生成的 class,可以分析出跟自定义实现方法差不多

$ javac Enumeration03.java
$ javap Season2.class
Compiled from "Enumeration03.java"
final class com.jwt.enum_.Season2 extends java.lang.Enum<com.jwt.enum_.Season2> {
  public static final com.jwt.enum_.Season2 SPRING;
  public static final com.jwt.enum_.Season2 WINTER;
  public static final com.jwt.enum_.Season2 AUTUMN;
  public static final com.jwt.enum_.Season2 SUMMER;
  public static com.jwt.enum_.Season2[] values();
  public static com.jwt.enum_.Season2 valueOf(java.lang.String);
  public java.lang.String getName();
  public java.lang.String getDesc();
  public java.lang.String toString();
  static {};
}

enum 常用方法

使用关键字enum 时,会隐式继承Enum 类, 这样我们就可以使用Enum 类相关的方法。

  • toString:Enum 类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息

  • name:返回当前对象名(常量名),子类中不能重写

  • ordinal:返回当前对象的编号(定义时的位置),默认从 0 开始

  • values:返回当前枚举类中所有的常量

  • valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!

  • compareTo:比较两个枚举常量,比较的就是编号

package com.jwt.enum_;

public class EnumMethod {
    public static void main(String[] args) {
        //使用Season2 枚举类,来演示各种方法
        Season2 autumn = Season2.AUTUMN;
        //输出枚举对象的名字
        System.out.println(autumn.name());
        //ordinal() 输出的是该枚举对象的次序/编号,从0 开始编号
        //AUTUMN 枚举对象是第三个,因此输出2
        System.out.println(autumn.ordinal());
        //从反编译可以看出values 方法,返回Season2[]
        //含有定义的所有枚举对象
        Season2[] values = Season2.values();
        System.out.println("===遍历取出枚举对象(增强for)====");
        for (Season2 season : values) {//增强for 循环
            System.out.println(season);
        }
        //valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
        //1. 根据你输入的"AUTUMN" 到Season2 的枚举对象去查找
        //2. 如果找到了,就返回,如果没有找到,就报错
        Season2 autumn1 = Season2.valueOf("AUTUMN");
        System.out.println("autumn1=" + autumn1);
        //compareTo:比较两个枚举常量,比较的就是编号
        //1. 就是把Season2.AUTUMN 枚举对象的编号和Season2.SUMMER 枚举对象的编号比较
        /*源码
        public final int compareTo(E o) {
            return self.ordinal - other.ordinal;
        }
        */
        //Season2.AUTUMN 的编号[2] - Season2.SUMMER 的编号[3]
        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
    }
}

实例练习🌰

  • 声明 Week 枚举类,其中包含星期一至星期日的定义

  • MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,SATURDAY, SUNDAY;

  • 使用 values 返回所有的枚举数组, 并遍历

package com.jwt.enum_;

public class EnumExercise02 {
    public static void main(String[] args) {
        //获取到所有的枚举对象, 即数组
        Week[] weeks = Week.values();
        //遍历,使用增强for
        for (Week w:weeks) {
            System.out.println(w);
        }
    }

}

enum Week{
    MONDAY("星期一"),TUESDAY("星期二"), WEDNESDAY("星期三"),
    THURSDAY("星期四"), FRIDAY("星期五"),SATURDAY("星期六"), SUNDAY("星期天");
    private String name;

    Week(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

enum 实现接口

  • 使用 enum 关键字后,就不能再继承其它类了,因为 enum 会隐式继承 Enum,而Java 是单继承机制。

  • 枚举类和普通类一样,可以实现接口

  • enum 类名 implements 接口1,接口2{}
    
package com.jwt.enum_;

/**
 * @author:简简
 * @createTime:[2022/3/13 13:20]
 **/
public class EnumDetail {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing();
    }
}

class A {
}

interface Playing {
    public void playing();
}

enum Music implements Playing {
    CLASSICMUSIC;//无参构造器,创建常量对象,则可以省略()

    @Override
    public void playing() {
        System.out.println("播放好听的音乐...");
    }
}

注解

  • 注解(Annotation)也被称为元数据(Metadata),用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息。

  • 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。

  • 在JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 JavaEE 旧版中所遗留的繁冗代码和 XML 配置等。

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

三个基本的 Annotation

  1. @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法

  2. @Deprecated: 用于表示某个程序元素(类, 方法等)已过时,该注解可以修饰方法,类,字段, 包, 参数等等

  3. @SuppressWarnings(“all”): 抑制编译器警告

    • 可以指定的警告类型有

      all,抑制所有警告
      boxing,抑制与封装/拆装作业相关的警告
      cast,抑制与强制转型作业相关的警告
      dep-ann,抑制与淘汰注释相关的警告
      deprecation,抑制与淘汰的相关警告
      fallthrough,抑制与switch 陈述式中遗漏break 相关的警告
      finally,抑制与未传回finally 区块相关的警告
      hiding,抑制与隐藏变数的区域变数相关的警告
      incomplete-switch,抑制与switch 陈述式(enum case)中遗漏项目相关的警告
      javadoc,抑制与javadoc 相关的警告第497页
      nls,抑制与非nls 字串文字相关的警告
      null,抑制与空值分析相关的警告
      rawtypes,抑制与使用raw 类型相关的警告
      resource,抑制与使用Closeable 类型的资源相关的警告
      restriction,抑制与使用不建议或禁止参照相关的警告
      serial,抑制与可序列化的类别遗漏serialVersionUID 栏位相关的警告
      static-access,抑制与静态存取不正确相关的警告
      static-method,抑制与可能宣告为static 的方法相关的警告
      super,抑制与置换方法相关但不含super 呼叫的警告
      synthetic-access,抑制与内部类别的存取未最佳化相关的警告
      sync-override,抑制因为置换同步方法而遗漏同步化的警告
      unchecked,抑制与未检查的作业相关的警告
      unqualified-field-access,抑制与栏位存取不合格相关的警告
      unused,抑制与未用的程式码及停用的程式码相关的警告
      

元注解的基本介绍

  • JDK 的元 Annotation 用于修饰其他 Annotation

  • 元注解的种类

    • Retention //指定注解的作用范围,三种SOURCE,CLASS,RUNTIME
      • RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释
      • RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中,当运行 Java 程序时, JVM 不会保留注解。这是默认值
      • RetentionPolicy.RUNTIME:编译器将把注解记录在 class 文件中,当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注解
    • Target // 指定注解可以在哪些地方使用
    • Documented //指定该注解是否会在javadoc 体现
    • Inherited //子类会继承父类注解

异常

基本概念

Java语言中,将程序执行中发生的不正常情况称为”异常”。(开发过程中的语法错误和逻辑错误不是异常)

执行过程中所发生的异常事件可分为两大类

  1. Error(错误):
  • Java虚拟机无法解决的严重问题。 如: JVM系统内部错误、 资源耗尽等严重情况。比如: StackOverflowError[栈溢出]和OOM(out of memory), Error 是严重错误,程序会崩溃。
  1. Exception:
  • 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等,
  • Exception 分为两大类:
    • 运行时异常[程序运行时,发生的异常]
      • 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常
      • 对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程
        序的可读性和运行效率产生影响
    • 编译时异常[编程时,编译器检查出的异常]
      • 编译时异常,是编译器要求必须处置的异常。

常见运行时异常

  • NullPointerException 空指针异常
  • ArithmeticException 数学运算异常
  • ArrayIndexOutOfBoundsException 数组下标越界异常
  • ClassCastException 类型转换异常
  • NumberFormatException 数字格式不正确异常

NullPointerException

当应用程序试图在需要对象的地方使用null 时,抛出该异常

public class NullPointerException_ {
    public static void main(String[] args) {
        String name = null;
        System.out.println(name.length());
    }
}

ArithmeticException

当出现异常的运算条件时,抛出此异常。

public class ArithmeticException_ {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 0;
        int res = num1 / num2;
    }
}

ArrayIndexOutOfBoundsException

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引

public class ArrayIndexOutOfBoundsException_ {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4};
        for (int i = 0; i <= arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

ClassCastException

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

public class ClassCastException_ {
    public static void main(String[] args) {
        A b = new B(); //向上转型
        B b2 = (B)b;//向下转型,这里是OK
        C c2 = (C)b;//这里抛出ClassCastException
    }
}
class A {}
class B extends A {}
class C extends A {}

NumberFormatException

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常

public class NumberFormatException_ {
    public static void main(String[] args) {
        String name = "教育";
        //将String 转成int
        int num = Integer.parseInt(name);//抛出NumberFormatException
        System.out.println(num);
    }
}

常见编译时异常

  • SQLException //操作数据库时,查询表可能发生异常
  • IOException //操作文件时,发生的异常
  • FileNotFoundException //当操作一个不存在的文件时,发生异常
  • ClassNotFoundException //加载类,而该类不存在时,异常
  • EOFException //操作文件,到文件末尾,发生异常
  • IllegalArguementException //参数异常

异常处理

异常处理就是当异常发生时,对异常处理的方式。

异常处理的方式

  • try-catch-finally
    • 程序员在代码中捕获发生的异常,自行处理
  • throws
    • 将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM

try-catch 异常处理

Java提供try和catch块来处理异常。 try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有多个try..catch块。

  • 1.如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
  • 2.如果异常没有发生,则顺序执行try的代码块,不会进入到catch块
  • 3.如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码finally
public class TryCatchDetail {
    public static void main(String[] args) {
        try {
            String str = "测试";
            int a = Integer.parseInt(str);
            System.out.println("数字:" + a);
        } catch (NumberFormatException e) {
            System.out.println("异常信息:" + e.getMessage());
        } finally {
            System.out.println("finally 代码块被执行...");
        }
        System.out.println("程序继续...");
    }
}
  • 4.可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception 在后,NullPointerException 在前),如果发生异常,只会匹配一个catch
public class TryCatchDetail02 {
    public static void main(String[] args) {
        //1.如果try 代码块有可能有多个异常
        //2.可以使用多个catch 分别捕获不同的异常,相应处理
        //3.要求子类异常写在前面,父类异常写在后面
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getName());//NullPointerException
        } catch (NullPointerException e) {
            System.out.println("空指针异常:" + e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

class Person {
    private String name = "jack";

    public String getName() {
        return name;
    }
}
  • 5.可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
public class TryCatchDetail03 {
        public static void main(String[] args) {
                try{
            int n1 = 10;
            int n2 = 0;
            System.out.println(n1 / n2);
            }finally {
                    System.out.println("执行了finally..");
            }
            System.out.println("程序继续执行..");
    }
}

泛型

什么是泛型

  • Java泛型(generics)是 JDK 5 中引入的一个新特性,在很大的程度上方便在集合上的使用。
  • 泛型的本质是 参数化类型,最熟悉的就是定义方法的时候需要形参,调用方法的时候,需要传递实参。那”参数化类型”就是将原来具体的类型参数化

泛型目的

  • 泛型的出现避免了在运行时强制类型转换而出现 ClassCastException (类型转化异常)。

泛型引出

请编写程序,在 ArrayList 中,添加 3 个 Dog 对象,Dog 对象含有 name 和 age,并输出 name 和age (要求使用getXxx())

传统方法

package com.jwt.generic;

import java.util.ArrayList;

public class Generic01 {
    public static void main(String[] args) {

        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("小黄",10));
        arrayList.add(new Dog("小白",2));
        arrayList.add(new Dog("小黑",5));
        for (Object o : arrayList){
            Dog dog = (Dog) o;//需要向下转型Object ->Dog
            System.out.println(dog.getName());
        }

    }
}

class Dog {
    private String name;
    private int age;

    public Dog() {
    }

    public Dog(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.jwt.generic;

import java.util.ArrayList;

public class Generic02 {
    public static void main(String[] args) {
        ArrayList<Dog> arrayList = new ArrayList<>();
        arrayList.add(new Dog("小黄",10));
        arrayList.add(new Dog("小白",2));
        arrayList.add(new Dog("小黑",5));
        for (Dog dog : arrayList){
            System.out.println(dog.getName());
        }
    }
}

class Dog {
    private String name;
    private int age;

    public Dog() {
    }

    public Dog(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;
    }
}

泛型优点

  • 编译时,检查添加元素的类型,提高了安全性
  • 不再提示编译警告
  • 减少了类型转换的次数,提高效率
    • 不使用泛型 Dog -> Object -> Dog //放入到 ArrayList 会先转成 Object,在取出时,还需要转换成 Dog
    • 使用泛型 Dog-> Dog -> Dog //放入和取出时,不需要类型转换,提高效率

泛型使用

泛型有三种常用的使用方式:泛型类,泛型接口和泛型方法

泛型类

class Person<E>{//如果创建对象时没有指定类型,默认是 Object
                E s;
                public Person(E s) {
                this.s = s;
                }
}
  • 泛型类型必须是引用类型(非基本数据类型)

    List<Integer> list = new ArrayList<Integer>(); //正确
    List<int> list2 = new ArrayList<int>();//错误
    
  • 泛型的使用形式

    List<Integer> list = new List<Integer>();
    List<Integer> list = new List<>();//推荐使用简写
    
  • 静态方法和静态属性不能使用泛型

  • 泛型默认是Object

    List List = new List();
    //等价
    List<Object> List = new List<>();
    
  • 由于使用自定义泛型的类,只有在实例化的时候才知道这个类型参数是什么,所以导致

    • (1)使用泛型的数组不能初始化;

    • (2)静态方法和静态属性并不能使用泛型。

泛型接口

public interface Test_ <E>{
    //...
}

泛型接口的类型,在继承接口 或者 实现接口时确定。(默认Object)

例子

/**
 * 泛型接口的定义格式:  修饰符  interface 接口名<数据类型> {}
 */
public interface Inter<T> {
    public abstract void show(T t) ;
}

/**
 * 子类是泛型类
 */
public class InterImpl<E> implements Inter<E> {
    @Override
    public void show(E t) {
        System.out.println(t);
    }
}


Inter<String> inter = new InterImpl<String>() ;
inter.show("hello") ;

泛型方法

public <E> void Come(E e){
   //...
}
  • 泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型

    class Fish<T, R> {//泛型类
      public void run() {//普通方法
      }
      public<U,M> void eat(U u, M m) {//泛型方法
      }
      //说明
      //1. 下面hi 方法不是泛型方法
      //2. 是hi 方法使用了类声明的泛型
      public void hi(T t) {
      }
      //泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
      public<K> void hello(R r, K k) {
      System.out.println(r.getClass());//ArrayList
      System.out.println(k.getClass());//Float
      }
    }
    

例子

class Demo{  
  public <T> T fun(T t){   // 可以接收任意类型的数据  
   return t ;     // 直接把参数返回  
  }  
};  
public class GenericsDemo{  
  public static void main(String args[]){  
    Demo d = new Demo() ; // 实例化Demo对象  
    String str = d.fun("汤姆") ; // 传递字符串  
    int i = d.fun(30) ;  // 传递数字,自动装箱  
    System.out.println(str) ; // 输出内容  
    System.out.println(i) ;  // 输出内容  
  }  
};

源码中泛型使用

下面是List接口和ArrayList类的代码片段

//定义接口时指定了一个类型形参,该形参名为E
public interface List<E> extends Collection<E> {
   //在该接口里,E可以作为类型使用
   public E get(int index) {}
   public void add(E e) {} 
}

//定义类时指定了一个类型形参,该形参名为E
public class ArrayList<E> extends AbstractList<E> implements List<E> {
   //在该类里,E可以作为类型使用
   public void set(E e) {
   .......................
   }
}

实例

  • 定义Employee类

    • 该类包含: private成员变量name,sal,birthday, 其中birthday为MyDate类的对象;
    • 为每一个属性定义getter, setter方法;
    • 重写toString方法输出name, sal, birthday
  • 定义MyDate类

    • 包含: private成员变量month,day,year;
    • 并为每一个属性定义getter,setter方法;
  • 创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList需使用泛型来定义)

    • 对集合中的元素进行排序,并遍历输出
    • 排序方式:调用ArrayList 的sort方法,传入Comparator对象[使用泛型],先按照
      name排序,如果name相同,则按生日日期的先后排序。 即:定制排序

Employee.java

package com.jwt.generic;

public 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 String toString() {
        return "\nEmployee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}

MyDate.java

package com.jwt.generic;

class MyDate implements Comparable<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 String toString() {
        return "MyDate{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }


    @Override
    public int compareTo(MyDate o) {
        int yearMinus = year - o.getYear();
        if (yearMinus != 0) {
            return yearMinus;
        }
        //如果year相同,比较month
        int monthMinus = month - o.getMonth();
        if (monthMinus != 0) {
            return monthMinus;
        }
        //如果year和month相同
        return day - o.getDay();
    }
}

Main.java

package com.jwt.generic;

import java.util.ArrayList;
import java.util.Comparator;

public class GenericExercise02
{
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("小明",10000, new MyDate(2000,7,2)));
        employees.add(new Employee("小红",20000, new MyDate(2002,10,2)));
        employees.add(new Employee("小明",30000, new MyDate(2000,6,2)));

        System.out.println("employees=" + employees);

        employees.sort(new Comparator<Employee>() {
        @Override
        public int compare(Employee emp1, Employee emp2) {
            //先按照name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】
            //先对传入的参数进行验证
            if (!(emp1 instanceof Employee && emp2 instanceof Employee)) {
                System.out.println("类型不正确..");
                return 0;
            }
            //比较name
            int i = emp1.getName().compareTo(emp2.getName());
            if (i != 0) {
                return i;
            }
            //封装后,将来可维护性和复用性,就大大增强.
            return emp1.getBirthday().compareTo(emp2.getBirthday());
        }
        });
        System.out.println("==对雇员进行排序==");
        System.out.println(employees);
    }
}

泛型的继承和通配符

  • 泛型不具备继承性

    //Object是String的父类
    Object o = new String("xx");//正确
    List<Object> list = new ArrayList <String>; //错误
    
  • 通配符

    • <?> :支持任意泛型类型

    • <? extends A>:支持A类以及A类的子类,规定了泛型的上限

    • <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

package com.jwt.generic;

import java.util.ArrayList;
import java.util.List;

public class GenericExtends {
    public static void main(String[] args) {
        
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<AA> list3 = new ArrayList<>();
        List<BB> list4 = new ArrayList<>();
        List<CC> list5 = new ArrayList<>();
        
        //如果是List<?> c ,可以接受任意的泛型类型
        printCollection1(list1);
        printCollection1(list2);
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);
        
        //List<? extends AA> c: 表示上限,可以接受AA 或者AA 子类
        printCollection2(list1);//×
        printCollection2(list2);//×
        printCollection2(list3);//√
        printCollection2(list4);//√
        printCollection2(list5);//√

        //List<? super AA> c: 支持AA 类以及AA 类的父类,不限于直接父类
        printCollection3(list1);//√
        printCollection3(list2);//×
        printCollection3(list3);//√
        printCollection3(list4);//×
        printCollection3(list5);//×

    }

    
    //说明: List<?> 表示任意的泛型类型都可以接受
    public static void printCollection1(List<?> c) {
        for (Object object : c) { // 通配符,取出时,就是Object
            System.out.println(object);
        }
    }
    
    // ? extends ,可以接受AA 或者AA 子类
    public static void printCollection2(List<? extends AA> c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }
    
    // ? super,支持AA 类以及AA 类的父类,不限于直接父类,
    public static void printCollection3(List<? super AA> c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }
}

class AA {
}

class BB extends AA {
}

class CC extends BB {
}

正则

。。。

其他

类型转换

  • new String(char[]):将char[]转换成String
  • new String(char[],off,len):将char[]的指定部分转换成String
  • str.toCharArray():将String转换成char[]
  • Integer.parseInt(str):将String转换成int

Junit

  • 1.一个类有很多功能代码需要测试, 为了测试,就需要写入到main方法中
  • 2.如果有多个功能代码测试,就需要来回注销,切换很麻烦
  • 3.如果可以直接运行一个方法,就方便很多,并且可以给出相关信息,就好了

JUnit是一个Java语言的单元测试框架,多数Java的开发环境都已经集成了JUnit作为单元测试的工具

传统方法

package com.jwt.generic;

public class JUnit_ {
    public static void main(String[] args) {
        //传统方式
        new JUnit_().m1();
        new JUnit_().m2();
    }
  
    public void m1 () {
        System.out.println("m1 方法被调用");
    }
  
    public void m2 () {
        System.out.println("m2 方法被调用");
    }
}

使用JUnit

package com.jwt.generic;

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

快捷操作

添加构造函数

Mac:Ctrl + enter

Win:AIt + Inster

自动导包

首先进入设置选项–>编辑器–>常规–>自动导包–>勾选对应项

包围代码

使用if..else, try..catch, for, synchronized等包围选中的代码

Win:Ctrl + Alt + t

Mac:option + command + t

选择导包

Win:Alt + enter

Mac:option + enter

补全括号或者分号

Shift + command + enter

显示所有的快捷键

Win:Ctrl + j

Mac:Command + j

快捷生成代码

快速生成打印:sout

快速生成打印当前值:soutv

快速生成增强for:I

快速生成main方法:main

快速生成迭代器while:输入 itit

多行操作

Win:AIt+鼠标左键不放,拖动即可

Mac:option+鼠标左键不放,拖动即可

转到任意类

Win:Ctrl+Shift+t

Mac:Command+o

搜索类中的方法

Win:Ctrl+F12

Mac:Command+F12

代码上下移动

Win:Ctrl+Shift+↑/↓

Mac:Command+Shift+↑/↓

查看函数参数

Win:Ctrl+p

Mac:Command+p

大小写转换

Win:Ctrl+Shift+u

Mac:Command+Shift+u

封装代码成方法

Win:Ctrl+Alt+m

Mac:Command+option+m

源码函数回退

Win:Ctrl+Alt+→/←

Mac:Command+option+→/←

统一修改代码

Win:Shift+F6

Mac:Shift+F6

隐藏指定文件

  1. 【Files】→【Settings】
  2. 【Editor】→【File Types】→【Ignored Files and Folders】
  3. 输入要隐藏的名称,支持*号通配符
  4. 回车确认添加

❤️Sponsor

您的支持是我不断前进的动力,如果您恰巧财力雄厚,又感觉本文对您有所帮助的话,可以考虑打赏一下本文,用以维持本博客的运营费用,拒绝白嫖,从你我做起!🥰🥰🥰

支付宝支付 微信支付

文章作者: 简简
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 简简 !
评论
填上邮箱会收到评论回复提醒哦!!!
 上一篇
数据结构:二叉树 数据结构:二叉树
树的诞生1、数组存储方式的分析 数组未排序 优点:在数组尾添加元素,速度快 缺点:查找速度慢 数组排序 优点:可以使用二分查找,查找速度快 缺点:为了保证数组有序,在添加新数据时,找到插入位置后,后面的数据需整体移动,速度慢
2022-04-11
下一篇 
Java-反射 Java-反射
前言哈喽!大家好,我是小简。今天开始学习《Java-反射》,此系列是我做的一个 “Java 从 0 到 1 ” 实验,给自己一年左右时间,按照我自己总结的 Java-学习路线,从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后
2022-04-06
  目录