前言
JavaSE 完结,撒花🌸🌸🌸,Java-基础的学习就将告一段落,今天我将之前发布的《Java-XXX》系列学习笔记进行汇总一下,此系列是我做的一个 “Java 从 0 到 1” 实验,给自己一年左右时间,按照我自己总结的 Java-学习路线,从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后的蜕变吧!<有同样想法的小伙伴,可以联系我一起交流学习哦!>
笔记汇总
环境配置:见本文下方
IDEA 插件:见本文下方
面向对象:Java-面向对象 | 简简
枚举:Java-枚举 | 简简
注解:Java-注解 | 简简
常用类:Java-常用类 | 简简
集合:Java-集合 | 简简
异常:Java-异常 | 简简
泛型:Java-泛型 | 简简
线程:Java-线程 | 简简
IO流:Java-IO流 | 简简
网络编程:Java-网络编程 | 简简
JDBC:Java-JDBC | 简简
Java8 新特性:Java 8 新特性 | 简简
反射:Java-反射 | 简简
正则: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路径
多版本安装
我安装了一个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插件
Translation 翻译,可以翻译英文注释
Alibaba Java Coding Guidelines 阿里巴巴编码规范检查工具(option+enter)
SequenceDiagram 一个时序图插件,右键方法名能看到方法里整个的调用流程
Rainbow Brackets 花括号和大括号颜色配对显示
RestfulToolkit 可以通过 url 定位到 controller 和通过接口生成完整 url
Randomness 可以在代码里生成随机数用来测试
MyBatisX 添加从 mapper 跳转到对应 xml 的功能
CamelCase 变量下划线转驼峰命名
.ignore 可以生成 ignore 文件比如 .gitignore
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 关键字实现
枚举对应英文(enumeration, 简写enum)
枚举是一组常量的集合。
可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
自定义类实现枚举
- 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
@Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时,该注解可以修饰方法,类,字段, 包, 参数等等
@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 //子类会继承父类注解
- Retention //指定注解的作用范围,三种SOURCE,CLASS,RUNTIME
异常
基本概念
Java语言中,将程序执行中发生的不正常情况称为”异常”。(开发过程中的语法错误和逻辑错误不是异常)
执行过程中所发生的异常事件可分为两大类
- Error(错误):
- Java虚拟机无法解决的严重问题。 如: JVM系统内部错误、 资源耗尽等严重情况。比如: StackOverflowError[栈溢出]和OOM(out of memory), Error 是严重错误,程序会崩溃。
- 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
隐藏指定文件
- 【Files】→【Settings】
- 【Editor】→【File Types】→【Ignored Files and Folders】
- 输入要隐藏的名称,支持*号通配符
- 回车确认添加
❤️Sponsor
您的支持是我不断前进的动力,如果您恰巧财力雄厚,又感觉本文对您有所帮助的话,可以考虑打赏一下本文,用以维持本博客的运营费用,拒绝白嫖,从你我做起!🥰🥰🥰
支付宝支付 | 微信支付 |