2022-08-01 第八组 卢睿 学习心得
JAVA泛型
今日重点
- 泛型
- 泛型方法
- 泛型类继承
- 静态泛型方法
- 类型擦除
- 枚举
- 枚举类实现单例模式
- 多线程前置
学习内容
JavaSE高级部分
- 泛型
- 枚举
- 多线程 前3年(难)
- 集合(数据结构,树,二叉树,红黑树,B+树,B-树)
- IO流(文件)
- 反射和注解
- 网络通信Socket(tomcat)
泛型:(Generics)
之前咱们写的超级数组中要么只能存数字,要么啥都能存。有一些鸡肋。
利用泛型可以解决问题。
什么是泛型?
泛型广泛的、普通的类型。
泛型能够帮助我们把【类型明确】的工作推迟到创建对象或者调方法的时候。
意思就是:我定义类的时候,不需要考虑这个数组到底要存什么类型。创建这个超级数组对象的时候把里面要存的数据的类型确定下来。
泛型的修饰:
- 泛型类
- 泛型方法
- 泛型接口
泛型类把泛型定义在类上,用户在使用类的时候才能把类型给确定。
具体的使用方法使用<>加上一个未知数。通常用T K V E等大写字母表示。
实际上用啥都行,只要是个单词就可以。
public class Ch02 {
public static void main(String[] args) {
// 如果一个泛型类,在创建对象的时候没有指定泛型类型
// 默认还是Object
// 在使用这个类的时候,去确定泛型类型
// 现在这个超级数组就只能存String类型
// 不规范
SuperArray<String> superArray = new SuperArray();
superArray.add("a");
// superArray.add(1);
// 这个超级数组superArray1就只能存Employee类型
// 在JDK7以后,可以省略等号右边的泛型的声明,<>必须得写,规范
// 类型推断
SuperArray<Employee> superArray1 = new SuperArray<>();
superArray1.add(new Employee());
superArray1.add(new Employee());
superArray1.add(new Employee());
superArray1.add(new Employee());
// 完整写法,JDK7以前
SuperArray<Employee> superArray2 = new SuperArray<Employee>();
}
}
泛型方法:
我们如果只关心某个方法,可以不定义泛型类。只定义泛型方法。
泛型方法是不是一定要在泛型类里?不是
泛型类里是不是一定要有泛型方法?不是
在定义泛型方法时,要首先定义泛型类型。
定义在方法中间,泛型的使用处之前
使用泛型方法,最好要结合返回值,和Object一样。
我们到后面学习反射的时候再说!!!
public class Ch03 {
public <T> T show(T t) {
// 拿着这个t在方法中做好多事情,再把t返回回去
// 调用另一个方法
System.out.println(t);
return t;
}
public static void main(String[] args) {
new Ch03().show("哈哈");
}
}
继承关系
泛型类在继承时:
- 父类是一个泛型类,子类要不要是泛型类?
- 永远记住,泛型的声明只能在当前类名后或者方法中间,而且声明的泛型是自己的。
- 在子类继承父类时,子类泛型和父类泛型都写出来的情况下,父跟子
- 如果在继承时,没有写出任何泛型,当前子类就不是泛型类。
class Father<T> {
T t;
}
// 在确定子类泛型的时刻,父类的泛型和子类一样
class Son<T> extends Father<T> {
}
//
class Son2 extends Father {
}
public class Ch04 {
public static void main(String[] args) {
Son<Employee> son = new Son<>();
son.t = new Employee();
Son2 son2 = new Son2();
son2.t.notify();
}
}
如果在一个泛型类中,尽量就不要再使用泛型方法。
泛型方法多数都是出现在非泛型类。
静态泛型方法:
- 静态方法如果是泛型方法,泛型的声明必须写。
- 因为静态结构是属于类的,不属于某个对象。
interface Inter<T> {
T show(T t);
static <T> T info(T t){
return t;
}
}
class Demo01<T> implements Inter<T> {
// @Override
// public Object show(Object o) {
// return null;
// }
@Override
public T show(T t) {
return t;
}
}
public class Ch05 {
public static void main(String[] args) {
Inter.info(1);
}
}
类型参数化。
类型擦除:
类型擦除:
为了兼容性,使用原始类型(没有泛型)是可以的。
泛型刚刚出现的时候,还存在大量的不适用泛型的代码。
保证代码的兼容性,将参数化类型的实例传递给设计用于原始类型的方法必须是合法的。
为了保持兼容性,Java泛型中,其实有一种类似伪泛型,因为Java在编译期间,所有的泛型都会被擦掉。
Java的泛型语法是在编译期这个维度上实现的。
正常来说在生成的字节码文件中,不包含泛型的类型信息的。
在JVM中看到的只是SuperArray,由泛型附加的类型信息对JVM是看不到的。
可以理解为,泛型的本质就是让程序员在编写代码时遵守的一个规则。
比如SuperArray:在确定了泛型之后,这个超级数组中就统一只放同一类型的数据。
如果放入其他类型,编译不通过。
经验:开发中,能够在业务上解决的问题,尽量不要在技术上解决。
- 泛型不能是基本数据类型。(原则上来说,数组可以作为泛型,语法角度,不可以)
<>里面放的就应该是类名。数组是在编译后才会生成一个类($xxxx) - 方法重载:a.同一个类里 b.方法名相同 c.参数不同
原理:类型擦除。 - 多态上。
泛型的应用场景:
1.父类(接口),起到的是一个规范的作用,对里面的数据类型没有明确要求。
2.容器类。(超级数组,链表,队列,栈)
当类型无法确定时,使用泛型。
开发中,我们更多的是会使用到一些泛型类或泛型接口。
枚举类型
应用场景:
在某些情况下,一个类的对象的个数是有限的,如季节,春夏秋冬,比如24节气,星期。。。
规定这个类的对象的个数。
大更新
JDK1.5更新了枚举类
枚举类中:
把需要用到的对象声明出来
写对应的构造器
可以有set,get方法
枚举在switch中使用
JDK1.5之后
枚举类的命名规则:所有的枚举类要以Enum结尾。
public class Ch03 {
public static void main(String[] args) {
SeasonEnum season = SeasonEnum.SPRING;
switch (season) {
case SPRING:
case SUMMER:
case AUTUMN:
case WINNER:
}
}
}
枚举的静态导入
*号代表导入枚举类的所有对象
public class Ch04 {
public static void main(String[] args) {
System.out.println(SPRING.getName());
}
}
单例模式(重要)
使用枚举类实现单例模式。
单元素的枚举类型已经成为实现单例模式的最佳方案。
class Singleton {
// 私有化构造器
private Singleton() {}
// 提供公有的获取实例的静态方法
public static Singleton getInstance(){
return SingletonHolder.INSTANT.instant;
}
// 声明一个枚举类(内部类)
private enum SingletonHolder{
INSTANT;
private final Singleton instant;
SingletonHolder() {
instant = new Singleton();
}
}
}
public class Ch05 {
public static void main(String[] args) {
System.out.println(Singleton.getInstance() == Singleton.getInstance());
}
}
枚举的优势
- int类型不具备安全性。假如某个程序员在定义int时少写了个final,会存在被他人修改的风险。枚举类,它天然就是一个常量类
- 使用int类型,语义不够明确。如果说在控制台打印输入1。
public class Ch06 {
public static void main(String[] args) {
// Integer seasonStr = 1;
// if(seasonStr == SeasonConstant.SPRING) {
// System.out.println(1);
// }
// 枚举里面都是常量,静态
// 推荐枚举的比较使用 ==
SeasonEnum spring = SeasonEnum.SPRING;
String name = "春天";
SeasonEnum1 spring1 = SeasonEnum1.SPRING;
// if(name.equals(spring.getName())){
// System.out.println("春天");
// }
if(spring1.equals(spring)) {
System.out.println(123);
}
}
}
多线程前置
我们要学习多线程,需要学习一些计算机组成的一些知识。
cpu8核以上和内存16G。
开一个虚拟机,开一个数据库,开git,开xshell,开idea,
开Nginx,开redis,启动N多个微服务。
为了完成特定的任务,用某种编程语言写一个软件(程序)。
程序要想运行就必须加载到内存中执行。
在执行程序的时候,实时的指令加载到cpu内存的指令寄存器中执行。
执行过程中产生的数据要加载到数据寄存器中。ALU负责进行算术逻辑运算的操作。
系统总线(System Bus):连接计算机系统的主要组件,用来降低成本和促进模块化。
可以通过软件来控制硬件。
进程:
一个正在执行中的程序就是一个进程,系统就会为这个进程发配独立的【运行资源】
进程是程序的一次执行过程,它有自己的生命周期
它会在启动程序时产生
运行程序时存在
关闭程序时消亡
比如:QQ,idea,腾讯会议,PDF
早期的计算机,单进程,同一时间只能执行一个进程。
计算器。同一时间只能执行一段代码。
随着计算机的发展,CPU的计算能力大幅提升,按照时间线交替执行不同继承的方式。
引入了线程。
线程是由进程创建,是进程的一个实体,是具体干活的人
一个进程有多个线程。线程不独立分配内存,而是共享进程的内存资源,线程可以共享cpu资源。
进程更强调的是【内存资源分配】,线程更强调的是【计算的资源的分配】
因为有了线程的概念,一个进程的线程不能修改另一个线程的数据,线程之间是相互隔离的,
安全性更好。
我使用浏览器打开两个腾讯视频,他们同时播放视频,
我一个浏览器也可以同时下载多个文件,
同时播放两个视频,在多线程的作用下。
下载,网络资源,IO问题。
核心,线程(8核16线程)
理论上,一个核在一个时间点只能跑一个线程,但是cpu同一个时间能跑16线程
- 物理cpu内核,每颗物理CPU可以有1个或多个物理内核,
通常情况下物理CPU内核数都是固定,单核CPU就只有1个物理内核 - 逻辑CPU内核,操作系统可以使用逻辑CPU来模拟真实CPU。
在没有多核心CPU情况下,单核CPU只有一个核,可以把一个CPU当做多个
CPU使用,逻辑CPU的个数就是作用的CPU物理内核数。英特尔研发的一种技术
超线程,2002发布。和硬件有关,了解。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类