day17-day18

1.泛型

1.1泛型的安全机制

软件升级 : 安全性提高,修复Bug错误,改善用户体验,增加功能,提升性能

JDK1.5里程碑版本

泛型作用 : 强制了集合存储固定的数据类型

泛型的书写格式 :

集合类<存储的数据类型>  变量名 = new 集合类<存储的数据类型>();
                                       类型可以不写:钻石操作符

加入泛型后,程序的安全性提升了

  • 使用泛型的好处 :
    • 安全性提高了
    • 程序的代码量减少
    • 避免了类型的强制转换
    • 程序的问题,由运行时期,提前到编译时期

1.2自定义泛型类

/**
 *  定义类,类名叫工厂
 *  自定义泛型类
 *  Factory<什么都可以写> 只是变量名而已
 */
public class Factory<QQ> {
    private QQ q;

    public void setQ(QQ q){
        this.q = q;
    }

    public QQ getQ(){
        return q;
    }
}

1.3泛型方法 

/**
 * 泛型的方法,方法参数上
 */
public class Factory<Q> {

    /*
     * 静态方法
     * Q是非静态的, Q的数据类型,是new的时候指定的
     *
     * 静态方法参数中的泛型,不能和类一样
     * 静态方法的泛型,需要在方法上单独定义
     * 写在返回值类型的前面
     */
    public static <T> void staticMethod(T q){
        System.out.println(q);
    }

    public void print(Q q){
        System.out.println(q);
    }
}

1.4泛型接口 

  • 实现类实现接口,不实现泛型
  • 实现类实现接口,同时指定泛型
//泛型接口
public interface Inter <T> {
    public abstract void inter(T t);
}
/**
 * 实现接口,不理会泛型
 * 对象创建的时候,指定类型
 */
public class InterImpl<T> implements Inter<T>{
    public void inter(T t){
        System.out.println(t);
    }
}
/**
 * 实现接口,同时指定泛型
 */
public class InterImpl2 implements Inter<String> {

    public void inter(String s) {
        System.out.println("s=="+s);
    }
}

1.5泛型通配符 

//泛型的通配符
public class GenericTest {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<String>();
        stringList.add("abc");
        stringList.add("bbc");

        List<Integer> integerList =  new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);

        each(stringList);
        each(integerList);
    }
    /**
     * 定义方法,可以同时迭代器 遍历这两个集合
     * 方法的参数,是要遍历的集合,不确定是哪个集合
     * 定义参数,写接口类型,不要写实现类
     */
    public static void each(List<?> list){
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }
    }
}

1.7泛型限定 

泛型限定 : 限制的是数据类型

  • 传递类型可以是Company或者是他的子类
  • 传递E类型或者是E的子类,泛型上限限定
  • 传递E类型或者是E的父类,泛型下限限定

2.增强for循环 

for(数据类型 变量名 : 集合或者数组){}

3.Map集合 

java.util.Map接口,是双列集合的顶级接口.

Map集合容器每次存储2个对象,一个对象称为键(Key),一个对象称为值(Value)

在一个Map的集合容器中,键保证唯一性,不包含重复键,每个键只能对应一个值 

3.1Map接口方法 

  •  put(K,V)存储键值对,存储重复键,返回被覆盖之前的值
  •  get(K)通过键获取值,参数传递键,找这个键对应的值,没有这个键返回null
  •  boolean containsKey(K)判断集合是否包含这个键,包含返回true
  •  boolean containsValue(V)判断集合是否包含这个值,包含返回true
  •  int size() 返回集合长度,Map集合中键值对的个数
  •  V remove(K)移除指定的键值对,返回被移除之前的值
  •  Collection values() Map集合中的所有的值拿出,存储到Collection集合

3.2Map集合遍历,用键找值 

  • 实现思想 :
    • Map接口定义了方法 keySet() 所有的键,存储到Set集合
    • 遍历Set集合
    • 取出Set集合元素 Set集合的元素是Map集合的键
    • Map集合方法get()传递键获取值
public static void mapKeySet(){
    Map<String,String> map = new HashMap<String, String>();
    map.put("a","java");
    map.put("b","c++");
    map.put("c","php");
    map.put("d","python");
    map.put("e","erlang");
    //Map接口定义了方法  keySet() 所有的键,存储到Set集合
    Set<String> set = map.keySet();
    //遍历Set集合
    Iterator<String> it = set.iterator();
    //取出Set集合元素 **Set集合的元素是Map集合的键**
    while (it.hasNext()){
        String key = it.next();
        //Map集合方法get()传递键获取值
        String value =  map.get(key);
        System.out.println(key+"==="+value);
    }
}

3.3Map集合遍历,键值对映射关系 

  • 实现思想 :
    • Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()
      • 方法返回Set集合,集合中存储的元素,比较特别
      • 存储的是Map集合中,键值对映射关系的对象 , 内部接口 Map.Entry
    • 遍历Set集合
    • 取出Set集合的元素
      • 是Map.Entry接口对象
      • 接口的对象方法: getKey() ,getValue()
public static void mapEntrySet(){
     Map<String,String> map = new HashMap<String, String>();
     map.put("a","java");
     map.put("b","c++");
     map.put("c","php");
     map.put("d","python");
     map.put("e","erlang");
     //Map接口的方法 Set< Map.Entry<Key,Value> > entrySet()
     Set<Map.Entry<String,String>>  set = map.entrySet();
     //- 遍历Set集合
     Iterator<Map.Entry<String,String>> it = set.iterator();
     while (it.hasNext()){
         //取出Set集合的元素
         Map.Entry<String,String> entry =  it.next();
         //- 接口的对象方法: getKey() ,getValue()
         String key = entry.getKey();
         String value = entry.getValue();
         System.out.println(key +"==="+ value);
     }
 }

4.HashMap 

  • HashMap集合特点
    • 是哈希表结构
    • 保证键唯一性,用于键的对象,必须重写hashCode,equals方法
    • 线程不安全集合,运行速度快
    • 集合运行使用null,作为键或者值

5.LinkedHashMap 

LinkedHashMap继承HashMap实现Map接口,LinkedHashMap底层实现原理是哈希表,双向链,存取有序. 其它的特性和父类HashMap一样. 

6.Hashtable 

Map接口的实现类Hashtable, Hashtable类诞生于JDK1.0版本, Map接口诞生于JDK1.2版本. Hashtable类从JDK1.2开始,改进为实现Map接口

  • Hashtable类的特点
    • 底层数据结构是哈希表
    • 线程安全的,运行速度慢,被更加先进的HashMap取代
    • 不允许null值,null键, 存储null直接抛出空指针异常

7.Vector集合类 

List接口的实现Vector,命运和Hashtable一样.

  • Vector类的特点
    • 底层实现结构是数组
    • 数组的默认容量是10,每次扩容是原来的长度*2
    • 线程安全,运行速度慢,被ArrayList取代

8.TreeMap集合 

  • TreeMap集合的特点
    • 底层实现是红黑树结构 (添加查询速度比较快)
    • 存储到TreeMap中元素,对键进行排序
    • 排序依据 :
      • 对象的自然顺序,作为键的对象,实现了接口Comparable
      • 自己提供比较器,实现接口Comparator,优先级高
    • 线程不安全的,运行速度快

9.Properties 

  • Properties集合特点
    • 继承Hashtable,实现Map接口
    • 底层是哈希表结构
    • 线程是安全的,运行速度慢
    • 集合没有泛型的写法,键和值的数据类型锁定为String类型
    • 集合有自己的特有方法
    • 此集合可以和IO流对象结合使用,实现数据的持久存储
    • 方法和IO相关 : load(输入流)

10.线程的基本概念 

10.1进程 

任何的软件存储在磁盘中,运行软件的时候,OS使用IO技术,将磁盘中的软件的文件加载到内存,程序在能运行。

进程的概念 : 应用程序(typerpa,word,IDEA)运行的时候进入到内存,程序在内存中占用的内存空间(进程).

10.2线程 

线程(Thread) : 在内存和CPU之间,建立一条连接通路,CPU可以到内存中取出数据进行计算,这个连接的通路,就是线程.

一个内存资源 : 一个独立的进程,进程中可以开启多个线程 (多条通路)

并发: 同一个时刻多个线程同时操作了同一个数据

并行: 同一个时刻多个线程同时执行不同的程序

11.Java实现线程程序 

11.1 java.lang.Thread类

一切都是对象,线程也是对象,Thread类是线程对象的描述类

  • 实现线程程序的步骤 :
    • 定义类继承Thread
    • 子类重写方法run
    • 创建子类对象
    • 调用子类对象的方法start()启动线程
//- 定义类继承Thread
//- 子类重写方法run
public class SubThread extends Thread {
    public void run(){
        for(int x = 0 ; x < 50 ;x++)
            System.out.println("run..."+x);
    }
}
public static void main(String[] args) {
    //创建线程程序
    SubThread subThread = new SubThread();
    //调用子类对象的方法start()启动线程
    //启动线程,JVM调用方法run
    subThread.start();
    for(int x = 0 ; x < 50 ;x++)
        System.out.println("main..."+x);
}

11.2 Thread类方法 

  • Thread类的方法 getName()返回线程的名字,返回值是String类型
public class ThreadName extends Thread {
    public void run (){
        System.out.println("线程名字:: "+ super.getName());
    }
}
   public static void main(String[] args) {
        ThreadName threadName = new ThreadName();
        //threadName.setName("旺财");
        threadName.start();

        ThreadName threadName1 = new ThreadName();
        //threadName1.setName("小强");
        threadName1.start();
    }
  • Thread类静态方法 : Thread currentThread()
    • 静态调用,作用是放回当前的线程对象
    • "当前" , 当今皇上. 本地主机
  • Thread类的方法 join()
    • 解释,执行join()方法的线程,他不结束,其它线程运行不了
  • Thread类的方法 static yield()
    • 线程让步,线程把执行权让出

11.3 java.lang.Runnable接口

  • 实现线程程序的步骤 :
    • 定义类实现接口
    • 重写接口的抽象方法run()
    • 创建Thread类对象
      • Thread类构造方法中,传递Runnable接口的实现类对象
    • 调用Thread对象方法start()启动线程
//- 定义类实现接口
// - 重写接口的抽象方法run()
public class SubRunnable implements Runnable{
    @Override
    public void run() {
        for(int x = 0 ; x < 50 ;x++){
            System.out.println(Thread.currentThread().getName()+"x.."+x);
        }
    }
}
    public static void main(String[] args) {
        //创建接口实现类对象
        Runnable r = new SubRunnable();
        //创建Thread对象,构造方法传递接口实现类
        Thread t0 = new Thread(r);
        t0.start();

        for(int x = 0 ; x < 50 ;x++){
            System.out.println(Thread.currentThread().getName()+"x.."+x);
        }
    }

11.4实现接口的好处 

接口实现好处是设计上的分离效果 : 线程要执行的任务和线程对象本身是分离的.

继承Thread重写方法run() : Thread是线程对象,run()是线程要执行的任务

实现Runnable接口 : 方法run在实现类,和线程无关,创建Thread类传递接口的实现类对象,线程的任务和Thread没有联系, 解开耦合性

12线程安全 

出现线程安全的问题需要一个前提 : 多个线程同时操作同一个资源

线程执行调用方法run,同一个资源是堆内存的

12.1同步代码块 

同步代码块可以解决线程安全问题 : 格式 synchronized关键字 

synchronized(任意对象){
    //线程操作的共享资源
}

任意对象 : 在同步中这个对象称为对象锁,简称锁,官方的稳定称为 对象监视器

同步代码块,如何保证线程的安全性.

  • 同步代码块的执行原理 : 关键点就是对象锁
    • 线程执行到同步,判断锁是否存在
      • 如果锁存在,获取到锁,进入到同步中执行
      • 执行完毕,线程出去同步代码块,讲锁对象归还
    • 线程执行到同步,判断锁所否存在
      • 如果锁不存在,线程只能在同步代码块这里等待,锁的到来

       

使用同步 : 线程要先判断锁,然后获取锁,出去同步要释放锁, 增加了许多步骤,因此线程安全运行速度慢. 牺牲性能,不能牺牲数据安全 

12.2同步方法 

当一个方法中,所有代码都是线程操作的共享内容,可以在方法的定义上添加同步的关键字 synchronized , 同步的方法,或者称为同步的函数.

  • 同步方法中有对象锁吗 , this对象
  • 静态同步方法中有对象锁吗,锁对象是本类.class属性. 这个属性表示这个类的class文件的对象.
    @Override
    public void run() {
        while (true)
          sale();
    }

private static synchronized void sale(){
    //  synchronized (Ticket.class) {
    if (tickets > 0) {
    try {
        Thread.sleep(20);//线程休眠,暂停执行
        } catch (Exception ex) {
    }
    System.out.println(Thread.currentThread().getName() + " 出售第" + tickets + "张");
    tickets--;
    }
//  }
}

13 死锁 

死锁程序 : 多个线程同时争夺同一个锁资源,出现程序的假死现象.

面试点 : 考察开发人员是否充分理解同步代码的执行原理

同步代码块 : 线程判断锁,获取锁,释放锁,不出代码,锁不释放

完成死锁的案例 : 同步代码块的嵌套

14 JDK5新特性Lock锁 

JDK5新的特性 : java.util.concurrent.locks包. 定义了接口Lock.

Lock接口替代了synchronized,可以更加灵活

  • Lock接口的方法
    • void lock() 获取锁
    • void unlock()释放锁
  • Lock接口的实现类ReentrantLock
/**
 *  优化为juc包的接口Lock
 */
public class Ticket implements Runnable {

    //定义票源
    private  int tickets = 100;
    //获取Lock接口的实现类对象
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true)
          sale();
    }

    private void sale(){
        //获取锁
        lock.lock();
        if (tickets > 0) {
            try {
                Thread.sleep(20);//线程休眠,暂停执行
            } catch (Exception ex) {
            }
            System.out.println(Thread.currentThread().getName() + " 出售第" + tickets + "张");
            tickets--;
        }
        //释放锁
        lock.unlock();
    }
}

 

 

  • 线程通信的方法 wait() notify()

    • 方法的调用必须写在同步中
    • 调用者必须是作为锁的对象
    • wait(),notify()为什么要定义在Object类
      • 同步中的锁,是任意对象,任何类都继承Object

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值