泛型
是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
泛型的格式:<数据类型> 注意:泛型只能支持引用数据里类型。
泛型的好处:
①统一数据类型
②把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来。
泛型可以在很多地方进行定义:
类后面 → 泛型类
方法申明上 → 泛型方法
接口后面 → 泛型接口
自定义泛型类
泛型类的概述
定义类时同时定义了泛型的类就是泛型类。
泛型类的格式:修饰符 class 类名<泛型变量>{ }
public class MyArrayList<T>{}
此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等。
作用:编译阶段可以指定数据类型
泛型类的核心思想
把出现泛型变量的地方全部替换成传输的真实数据类型
泛型类的作用
编译阶段约定操作的数据类型
泛型方法
- 定义方法时同时定义了泛型的方法就是泛型方法。
- 泛型方法的格式:修饰符 <泛型变量> 方法返回值方法名称 (形参列表){ }
public <T> void show(){ }
作用:方法中可以使用泛型接受一切实际类型的参数,方法更具备通用性
泛型方法不一定要在泛型类里
泛型类里不一定要有泛型方法
在定义泛型方法时,要首先定义泛型类型。定义在方法中间,泛型的使用处之前。
泛型接口
- 使用了泛型定义的接口就是泛型接口。
- 泛型接口的格式:修饰符interface接口名称<泛型变量>{ }
public interface Data<E> { }
**作用:**泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作。
**原理:**实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
package com.afternoon;
public interface Data<E> {
void add(E id);
void del(E id);
void revise(E e);
void search(E id);
}
现在,要对学生类进行增删改查,创建一个学生类,实现Data接口,约束自己操作哪一个实现类型,由于是泛型接口,在实现接口要声明类型,因此要把传Student类型,并重写方法。
package com.afternoon;
public class Student implements Data<Student>{
@Override
public void add(Student id) {
}
@Override
public void del(Student id) {
}
@Override
public void revise(Student student) {
}
@Override
public void search(Student id) {
}
}
定义一个教师类,中传入Teacher。
package com.afternoon;
public class Teacher implements Data<Teacher>{
@Override
public void add(Teacher id) {
}
@Override
public void del(Teacher id) {
}
@Override
public void revise(Teacher teacher) {
}
@Override
public void search(Teacher id) {
}
}
通配符:?
- ?可以在“使用泛型”的时候代表一切类型。
- E、T、K、V是在定义泛型的时候使用的。
- 如果使用Object类型,就不要写泛型。
- 泛型约束类的数据类型。
继承关系
泛型类在继承时:
- 1.父类是一个泛型类,子类要不要是泛型类?
- 2.永远记住,泛型的声明只能在当前类名后或者方法中间,而且声明的泛型是自己的。
- 3.在子类继承父类时,子类泛型和父类泛型都写出来的情况下,父跟子
- 4.如果在继承时,没有写出任何泛型,当前子类就不是泛型类。
案例:举办一个赛车比赛,定义一个Car类,有两辆车去继承Car。
package com.jr.morning;
import java.util.ArrayList;
public class DemoCar {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
System.out.println(new BMW());
go(bmws);
ArrayList<MAYBACH> maybaches = new ArrayList<>();
System.out.println(new MAYBACH());
go(maybaches);
}
public static void go(ArrayList<?> cars) {
}
}
class BMW extends Car {
}
class MAYBACH extends Car {
}
可以看到,加了通配符?之后,品牌不同的车都能比赛,那如果再定义一只狗呢?
package com.jr.morning;
import java.util.ArrayList;
public class DemoCar {
public static void main(String[] args) {
ArrayList<BMW> bmws = new ArrayList<>();
System.out.println(new BMW());
go(bmws);
ArrayList<MAYBACH> maybaches = new ArrayList<>();
System.out.println(new MAYBACH());
go(maybaches);
ArrayList<Dog> dogs = new ArrayList<>();
System.out.println(new Dog());
go(dogs);
}
public static void go(ArrayList<?> cars) {
}
}
class Dog {
}
class BMW extends Car {
}
class MAYBACH extends Car {
}
狗不能和赛车比赛,这个时候就要用到泛型的上下限。
泛型的上下限
- ? extends car:?必须是Car或者其子类泛型上限?
- super car:?必须是Car或者其父类泛型下限
public static void go(ArrayList<? extends Car> cars) {
}
强调能够比赛的是Car的子类,狗没有继承Car,所以报错不能比赛。
枚举
Java中的一种特殊类型
枚举的作用:为了做信息的标志和信息的分类。
定义枚举的格式:
定义一个枚举,春、夏、秋、冬季节。表示,当前这个枚举类的对象名称。(多例模式)
package com_enum;
/*枚举*/
public enum Season {
//第一行必须罗列枚举类对象名称,全部大写
SPRING,SUMMER,AUTUMN,WINTER;
}
反编译后观察枚举的特征:
在桌面创建记事本,将代码放在记事本中,修改名字和后缀名为:Season.java。然后win+r,输入cmd,记事本右键——属性——安全,将记事本的地址复制。回到命令处理器,输入命令:
cd C:\Users\Pro16\Desktop(你自己复制的地址)
javac Season.java 会生成.class文件
javap Season.class 实现反编译,就会看到枚举的真实代码
枚举的特征
- 枚举类都是继承了枚举类型:java.lang.Enum
- 枚举都是最终类,不可以被继承。
- 枚举类的构造器都是私有的,枚举对外不能创建对象。
- 枚举类的第一行默认都是罗列枚举对象的名称的。(说明它的每一个名称都是常量,存的都是当前类的对象)
- 枚举类相当于多例模式。
枚举的优势:
- int类型不具备安全性。假如某个程序员在定义int时少写了个final。会存在被他人修改的风险。枚举类,它天然就是一个常量类
- 使用int类型,语义不够明确。如果说在控制台打印输入1。
- 枚举里面都是常量,静态
- 推荐枚举的比较使用 ==
枚举在switch中使用
package com.jsoft.afternoon;
public class Ch03 {
public static void main(String[] args) {
SeasonEnum season = SeasonEnum.SPRING;
switch (season) {
case SPRING:
case SUMMER:
case AUTUMN:
case WINNER:
}
}
}
线程
进程
一个正在执行中的程序就是一个进程,系统就会为这个进程发配独立的【运行资源】
进程是程序的一次执行过程,它有自己的生命周期,它会在启动程序时产生,运行程序时存在,关闭程序时消亡。
随着计算机的发展,CPU的计算能力大幅提升,按照时间线交替执行不同继承的方式。每个执行一点点时间,感官上觉得这么多的进程是同时在运行。一个进程有多个任务。如果为每一个任务分配单独的进程去执行,进程间通信。CPU在调度。
引入了线程
线程是由进程创建,是进程的一个实体,是具体干活的。一个进程有多个线程。线程不独立分配内存,而是共享进程的内存资源,线程可以共享CPU资源。
进程更强调的是【内存资源分配】,线程更强调的是【计算的资源的分配】
因为有了线程的概念,一个进程的线程不能修改另一个线程的数据,线程之间是相互隔离的。安全性更好。
理论上,一个核在一个时间点只能跑一个线程,但是CPU同一个时间能跑16线程
1.物理CPU内核,每颗物理CPU可以有1个或多个物理内核,通常情况下物理CPU内核数都是固定,单核CPU就只有1个物理内核。
2.逻辑CPU内核,操作系统可以使用逻辑CPU来模拟真实CPU。在没有多核心CPU情况下,单核CPU只有一个核,可以把一个CPU当做多个CPU使用,逻辑CPU的个数就是作用的CPU物理内核数。