、
15泛型
15.3泛型的语法
泛型的声明
interface 接口 {}和class类<K,V> {}
T,K,V不代表值,而是表示类型
任意字母都可以,常用T表示,是Type的缩写
泛型的实例化
要在类名的后面指定类型参数的值
15.4泛型的使用细节
1、interface 接口 {}和public class HashSet{}
T和E只能是引用类型
2、在给泛型指定具体类型后,可以传入类型或者其子类类型
3、编译器会进行类型推断
HashMap<String,Student> hm = new HashMap<>();
此方法比较推荐
4、如果写成HashMap hm = new HashMap();这个样子其实等价于泛型默认为Object
15.5自定义泛型
class 类名<T,R …>{
成员
}
注意细节
普通成员可以使用泛型(属性、方法)
使用泛型的数组,不能初始化:由于不能确定T的类型,就无法在内存开空间
静态方法中不能使用类的泛型由于静态是和类相关的,在类加载时,对象还没有创建,而泛型只有在类创建的时候才能初始化
泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
如果在创建对象时,没有指定类型,默认为Object
15.5自定义泛型接口
interface 接口名 <T ,R ...>{
}
注意细节
接口中,静态成员也不能使用泛型
泛型接口的类型,在继承接口或者实现接口时确定
没有指定类型,默认为Object
15.5自定义泛型方法
修饰符 <T,R...>返回类型 方法名(参数列表){
}
注意细节
泛型方法,可以定义在普通类中,也可以定义在泛型类中
当泛型方法被调用时,类型会确定
public void eat(E e){ },修饰符后没有<T,R…>eat方法不是泛型方法,而是使用了泛型
15.5泛型的继承和通配符
泛型不具备继承性
ArrayList<Object> strings = new ArrayList<String>();
//这样写是不正确的
<?>支持任意泛型类型
<? extends A>支持A类以及A类的子类,规定了泛型的上限
<? super A>支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
15.6 JUnit
@Test的单元测试
enter+ctrl进行导入包
16坦克大战,由于坦克大战涉及到多线程和IO流,先不进行,最后再进行
17多线程(基础)
17.1线程介绍(408已经学完)
**程序:**是为了完成特定任务,用某种语言编写的一组指令的集合(就是我们写的代码)
**进程:**运行中的程序,用QQ时,OS就会为该进程分配一个内存空间,用迅雷时,OS就会为该进程分配一个内存空间
进程是程序的一次执行过程,或者是正在运行的一个程序,是动态过程
**线程:**线程由进程创建,是进程的一个实体
一个进程可以拥有多个线程
单线程:同一时刻,只允许执行一个线程
多线程:同一时刻,可以执行多个线程,一个QQ程序可以同时打开多个聊天窗口
**并发:**同一时刻,多个任务交替执行,单核Cpu实现的多任务就是并发
**并行:**同一时刻,多个任务同时执行,多核CPU可以实现并行
17.2线程使用
17.2.1 创建线程的两种方式
17.2.1.1 继承Thread类,重写run方法
public class cpu01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();//启动线程
}
}
class Cat extends Thread{
int times =0;
@Override
public void run() {
//重写run方法,写上自己的逻辑
while(true) {
System.out.println("喵喵,我是小猫咪"+(++times));
//alt+ctrl+t添加try,catch
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (times==8){
break;
}
}
}
}
使用JConsole监控线程执行情况
利用终端进行探勘,当主程序执行完毕之后,会消失
为什么是start方法而不是run方法呢
run方法就是一个普通的方法,并没有真正的启动一个线程,就会把run执行完毕才继续向下执行
而start方法是本地方法,是JVM调用的,底层是C或者C++实现
真正实现多线程的是start,而不是run
start()方法调用start0()方法后,该线程并不一定会马上执行,只是将线程变成了可运行状态
17.2.1.2实现Runnable接口,重写run方法
由于JAVA是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能
JAVA设计者提供了另一个方式创建线程,就是通过实现Runnable接口来创建线程
底层使用了设计模式【代理模式】
public class thread02 {
public static void main(String[] args) {
Dog dog = new Dog();
//创建了Thread对象,把dog对象(实现Runnable)放入了Thread
Thread thread = new Thread(dog);
thread.start();
dog.run();
}
}
class Dog implements Runnable{//通过实现Runnable接口,开发线程
int count =0;
@Override
public void run() {//普通方法,并不能实现多线程
while (true){
System.out.println("小狗汪汪叫"+(++count)+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count==10){
break;
}
}
}
}
17.2.1.3多线程执行
public class exe01 {
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
Thread thread1= new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
class T1 implements Runnable{
public void run(){
int times=0;
while (true){
System.out.println("hello,word! ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (++times==10){
break;
}
}
}
}
class T2 implements Runnable{
public void run(){
int times=0;
while(true){
System.out.println("hi ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(++times==5){
break;
}
}
}
}
17.2.1.4继承Thread VS Runnable的区别
继承Thread和实现Runnable接口来创建线程本质没有区别
实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制