2021-05-29

JavaSE基础(W5)总结

Day1

增强for循环(JDK5)以后出现

使用场景:
遍历集合或数组,遍历集合居多,增强for`循环是为了简化迭代器的书写方式,替代集合的迭代器  集合中使用较为广泛
​
格式:
    //for(集合中存储的数据类型  变量名 : 集合对象){
    for(Student s : stuList){
    
    //使用变量名
    System.out.println(s.getName()+"---"+s.getAge());
    
    //}
    
注意事项:使用增强for循环,前提条件是集合不能为空,否则空指针异常.

List集合的获取功能

ListIterator<E> listIterator()  :获取列表迭代器
​
ListIterator
            正向遍历
            boolean hasNext()判断是否有下一个可迭代的元素
            E next() 获取下一个元素
            
            逆向遍历
            boolean hasPrevious()判断是否有下一个可迭代的元素
            E previous()获取上一个元素
得现有正向遍历才能逆向遍历,否则输出没有结果
​
无参构造创建的时候默认构造一个初始容量为10的空列表,当传递容量大小(有参构造方法)会自动扩容grow方法: 1.5倍的机制来进行扩容

线程安全的类

StringBuffer:字符缓冲区
Vector集合(其中的元素称之为"组件")
​
特有功能:
public void addElement(Object obj)添加元素
public Enumeration<E> elements():获取向量组件的枚举  (类似于 Iterator iterator())
        Enumeration:
        boolean hasMoreElements()判断是否有很多元素 类似于:boolean hasNext()
        Object nextElement():                    类似于:Object next()
        
public E elementAt(int index):-------类似于:List集合中的get(int index)
        获取索引值对应的"组件"
        和size()相结合----普通for循环的遍历方式

LinkedList特有功能:

 public void addFirst(E e):将元素添加到开头
 public void addLast(E e):将元素添加到链表的末尾
 
 public   Object removeFirst():删除列表的第一个元素,并返回的是第一个元素
 public   Object removeLast():
 
 public E getFirst():获取列表的开头元素
 public E getLast()

Set集合与List的区别

List有序(存储和取出一致)
     允许元素重复
Set无序(存储和取出不一致)
     不允许元素重复
     
Set接口不能实例化,最具体的子类:使用HashSet以及TreeSet
HashSet(线程不安全的类:它允许null元素可以出现,执行效率高)----底层由HashMap实现
​
HashSet的add方法---依赖于HashMap的put方法
因为中文比较特殊,有哈希码值一样的情况,所以要重写哈希码值+equals
依赖于:hash方法需要计算每一个元素的hash码值(hashCode())
依赖equals方法:比较内容是否相同
​
当使用set集合存储自定义对象,要保证元素唯一,
    就需要set集合底层依赖于hashCode和equals方法!
    Set集合特点:它不保证遍历顺序恒久不变(哈希表决定的)
​

TreeSet集合:

基于TreeMap的实现(红黑树结构:自平衡的二叉树结构)
自然排序        public TreeSet()
比较器排序      public TreeSet(Comparator<? super E> comparator)
取决于使用的构造方法!
​
TreeSet集合:存储元素后,按照某种规则输出,规则提示明确主要条件,自己判断次要条件
​
TreeSet的add方法基于TreeMap的put方法有关系
特点:将第一个元素(节点)成为"root"根节点,后面的元素依次比较(小了作为左孩子,大了作为右孩子),重复不会添加(不会进入节点)
​
​
TreeSet存储自定义对象有两种排序:
自然排序:自定义对象所在类必须实现一个接口:Comparable,重写接口中的compareTo(T t)
比较器排序
         方式1:自定义一个类实现Comparator接口,重写接口中的compare(T o1,T o2)(T泛型)
         方式2:直接使用Comparator接口匿名内部类

自然排序

自然排序注意:存储自定义对象所在的了欸必须实现一个接口,Comparable接口,必须要给定一个排序的主要条件
重写compareTo()方法,否则报错:ClassCastException
自然排序:执行无参构造方法TreeSet<E>()
​
 @Override//重写compareTo()方法
    public int compareTo(Student s) {
        //主要条件:按照学生的姓名长度从大到小
        int num = s.name.length() - this.name.length() ;
        //次要条件:如果姓名长度相同,比较姓名的内容是否一样
        int num2 = (num==0)?this.name.compareTo(s.name):num ;
​
        //如果姓名长度相同,姓名内容也一样,比较年龄是否一样
        int num3 = (num2==0)? this.age-s.age : num2 ;
        return num3  ;
    }

比较器排序

方式1):利用comparator比较器函数接口的子实现类
public class MyCoparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        //按照年龄从小到大排序
        int num = s1.getAge() - s2.getAge() ;      
        int num2 = (num==0)?(s1.getName().compareTo(s2.getName())):num ;
        return num2;
    }
}
​
方式2)使用匿名内部类(书写简单,而且节省空间)
import java.util.Comparator;
import java.util.TreeSet;
public class TreeDemo {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
            @Override
            public int compare(Student s1, Student s2) {
                //按照年龄从小到大排序
                int num = s2.getAge() - s1.getAge() ;
                int num2 = (num==0)?(s1.getName().compareTo(s2.getName())):num ;
​
                return num2;
            }
        }) ;

 

Day21

Map集合和Collection集合的区别

 
Collection:单例集合:只能存储一种类型(引用类型)
    Set集合和Map集合有一定的间接关系
    HashSet<E>的添加功能add依赖Map里面的HashMap<K,V>的put方法
    TreeSet<E>的add方法依赖于Map里面TreeMap<K,V>的put方法
    
 Map:双列集合,可以存储键和值:两种类型
   存储的一系列的键值对元素   Map集合:针对键有效,跟值无关,键必须唯一的!
   默认的使用HashMap:允许元素出现null键和null值,线程不安全的类!

Map集合的功能:

添加
    V put(K key,V value) :添加一个键值对元
    注意事项: 细节:返回什么意思?
    如果键是第一次添加,那么返回是null
    如果键不是第一次添加,后面添加键对应的值将第一次的值覆盖掉,将第一次的值返回!
​
删除
    void clear()
    V remove(Object key):删除指定的键,返回被删除键对应的值
判断
    boolean containsKey(Object key):判断是否包含指定的键
    boolean containsValue(Object value):判断是否包含指定的值
获取
    Collection<V> values():获取Map集合中的所有的值的集合
 
 
方式1:Map的遍历
      Set<K> keySet():获取Map集合的中的所有的键
      V get(Object key):然后在通过键获取值
​
 //方式2:Map的遍历
      Set<Map.Entry<K,V>> entrySet():获取键值对对象
      HashMap:底层数据结构:哈希表:键必须唯一!值可以重复,存储和取出无序

Map的遍历

方式1

HashMap<String,String> hm = new HashMap<String,String>() ;
   
        hm.put("杨过","小龙女") ; //添加元素
        hm.put("郭靖","黄蓉") ;
        hm.put("陈玄风","梅超风") ;
        hm.put("令狐冲","任盈盈") ;
​
        Set<String> keySet = hm.keySet(); //遍历:
        for(String key :keySet){
            //在键获取值
            //V get(Object key)
            String value = hm.get(key);
            System.out.println(key+"="+value);
        }

方式2

HashMap<String,String> hm = new HashMap<String,String>() ;
   
        hm.put("杨过","小龙女") ;    //添加元素
        hm.put("郭靖","黄蓉") ;
        hm.put("陈玄风","梅超风") ;
        hm.put("令狐冲","任盈盈") ;
        
Set<Map.Entry<String, String>> entrySet = hm.entrySet();
        for(Map.Entry<String,String> entry:entrySet ){
            //分别获取键和值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"="+value);
        }

Map的键值

键:自定义类型:如何保证key是唯一的呢?
   put方法----依赖于hashCode和equals方法,存自定义对象所在类必须重写!
   HashMap<String,String>:Key:String String类型底层重写hashCode和equals方法!

针对集合操作的工具类

public static <T extends Comparable<? super T>> void sort(List<T> list):针对List集合进行自然
​
public static <T> void sort(List<T> list,Comparator<? super T> c):针对List集合进行比较器排序
​
public static <T> int binarySearch(List<<? extends Comparable<? super T>>,  T key)
​
集合中的二分搜索 :前提条件:当前集合中的元素必须有序的!
​
 public static <T> void sort(List<T> list,Comparator<? super T> c):对列表元素进行随机置换
                           
  public static  T max(Collection<? extends T> coll)     :求最大值
  
 public static T min(Collection<? extends T> coll):求最小值
            //创建List集合对象
        List<Integer> list = new ArrayList<Integer>() ;
​
        list.add(20) ;
        list.add(17) ;
        list.add(19) ;
        list.add(23) ;
        list.add(21) ;
        list.add(16) ;
        list.add(24) ;
​
        System.out.println(list);
​
        Collections.sort(list);
        System.out.println(list);
​
        //public static <T> int binarySearch(List<<? extends Comparable<? super T>>,  T key)
        int index = Collections.binarySearch(list,20) ;
        System.out.println(index);//排序后查找元素20的角标
        System.out.println("-------------------------------------");
        Collections.shuffle(list);  //随机置换
        System.out.println(list);
        System.out.println(Collections.max(list));//求最大值
        System.out.println(Collections.min(list));//求最小值

进程

进程:(程序的实体)由系统资源分配和调度的最小单元,而线程依赖于进程存在,程序执行的最小单位!
线程:程序执行时期的最小单元,所有线程都存在线程组(ThreadGroup)
​
Java语言不能够创建系统资源, 借助于底层语言C语言来操作,Java提供类Thread类
​
并发:在一个时间点同时发生
并行:在一个时间段内同时发生
​
开发步骤:
1)自定义一个类 继承自 Thread(线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。 )
2)该子类应重写 Thread 类的 run 方法(重写的run内部存放的耗时的代码:循环,io流读写操作...)
3)创建当前子类对象,然后启动线程:start()而非run方法()
​
 启动线程:使用start 方法
 成员方法:
   设置线程名称
          public final void setName(String name)
   获取线程名称:
          public final String getName()
          
重写run方法出现的异常:start()方法只能重写一次,否则IllegalThreadStateException:非法状态异常
​
​
public static void yield():暂停当前正在执行的线程,执行其他线程!

throws InterruptedException :等待该线程终止

public final void join()
    throws InterruptedException  :等待该线程终止
//try...catch...捕获异常
//throws:抛出异常:方法声明上
try {
         tj1.join(); //等待tj1终止
  } catch (InterruptedException e) {
         e.printStackTrace();//日志: 跟踪堆栈,将异常信息打印在控制台上
}

Thread类的常量字段表

Thread类的常量字段表
 public static final int MAX_PRIORITY 10
 public static final int MIN_PRIORITY 1
 public static final int NORM_PRIORITY 5  :默认值
 
 public final void setPriority(int newPriority)设置优先级
 public final int getPriority()
​
 优先级越大的线程,抢占CPU的执行权(cpu一点点时间片,可以高效的进行切换)的资格大
 优先级越小的线程:抢占CPU的执行权越小!
 
 线程的执行具有随机性!

Day3

线程的六种状态

state{
    NEW                 新建状态
    RUNNABLE            运行状态
    BLOCKED             阻塞状态,通过sleep(),wait()
    WAITING             等待,死死等待
    TIMED_WAITING,      超时等待状态
    TERMINATED;         线程死亡状态
}
​

多线程的实现方式Runnable

Java语言不能开启多线程,通过Thread实现Runnable接口,成为thread的子类,并且重写run方法
实现关系(Runnable)
​
步骤:
1)自定义一个类,实现Runnable接口,重写run方法;
2)在用户线程(main)创建"资源类"对象,然后创建Thread类对象,将"资源类"作为对象传递
3)分别启动线程
​
//Thread类的静态功能:
public static Thread currentThread():表示正在执行的线程对象的引用

案例1)使用继承关系

//创建三个线程
​
SellTicket st1 = new SellTicket() ;
SellTicket st2 = new SellTicket() ;
SellTicket st3 = new SellTicket() ;
​
//设置线程名称
st1.setName("窗口1") ;
st2.setName("窗口2") ;
st3.setName("窗口3") ;
​
//启动线程
st1.start() ;
st2.start() ;
st3.start();
   -----------------  
public class SellTicket  extends  Thread{
​
    //有100张票
    public static int tickets = 100 ;
    //创建一个把锁
    private Object obj = new Object() ;
​
    @Override
    public void run() {
        //模拟一直有票
        while(true){
            synchronized (obj){
                //加入网络延迟,睡眠100毫秒
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
​
                if(tickets>0){
                    System.out.println(getName()+"正在出售第"+tickets+"张票");
                    tickets -- ;
                }else{
                    break ;
                }
            }
​
​
        }
    }
}     

方式2,使用Runnable接口

//创建资源共享类对象
SellTicket st = new SellTicket() ;
//创建多个线程类对象,将资源共享类作为参数传递
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
​
//启动线程
t1.start();
t2.start();
t3.start();
​
public class SellTicket implements Runnable {
    public static int tickets = 100 ;//100张票
​
    //t1,t2,t3
    @Override
    public void run() {
​
        //为了模拟一直有票,使用死循环
        while(true){
            if(tickets>0){  //t1进来
                //睡眠100毫秒
​
                //为了模拟网络延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
​
                System.out.println(Thread.currentThread().getName()+
                        "正在第"+(tickets--)+"张票");
            }
            
//-------------------------
程序出现:
     1)一个张票可能被卖多次(出现同票)
              线程的执行具有随机性(原子性操作:最简单,最基本的操作语句:--,++...)
     2)出现了负票
             线程的延迟性导致(加入睡眠100毫秒)
      现在的程序存在 "多线程安全问题"
//----------------------     

校验多线程安全问题的标准

1)查看当前程序是否是多线程环境      
2)是否存在共享数据                   
3)是否有多条语句对共享数据进行操作   

关键字synchronized

synchronized:关键字---- 内置语言实现的(jvm来实现锁定操作: 锁的释放:自动释放)
可以是通过代码块(代码中),可以在方法上使用(同步方法)
synchronized同步锁---属于"悲观锁"
悲观锁:自己线程本身在执行的时候,其他线程不能进入同步代码块中,其他线程不能进入
修改数据,保证数据的安全性!  (针对频繁的写入操作)
​
乐观锁:针对频繁读取数据的锁
​
程序添加synchronized同步锁
//----------------------------------------
public class SellTicket implements Runnable {
    public static int tickets = 100 ;//100张票
​
    private Demo demo = new Demo();
   // private Object obj = new Object() ;
​
​
    //t1,t2,t3
    @Override
    public void run() {
        //为了模拟一直有票
        while(true){
       
           // synchronized(obj){ //一个锁对象
            //锁对象可以是任意的Java类对象
            synchronized(demo){ //一个锁对象
                if(tickets>0){  //t1进来,t2和t3无法进入
​
                    try {
                        Thread.sleep(100); //睡眠100毫秒,模拟网络延迟
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+
                            "正在第"+(tickets--)+"张票");
                }
            }
        }
    }
}
class Demo{//自定义类
}

代理模式

代理:让别人替自己本身完成一些事情!
代理角色:帮助真实角色对他本身的功能进行增强(完成代理完成不了的事情!)
真实角色:只专注于自己完成的事情
​
Java代理模式----结构型设计模式
​
静态代理
同一个接口
特点:代理角色和真实角色必须同一个接口
​
动态代理(后期框架底层使用的这个模式)
JDK动态代理:基于接口
CGLib动态代理:基于子类
public class StaticProxyDemo {
    public static void main(String[] args) {         
      //接口多态
        //真实角色
        Marry marry = new You() ;
        marry.marry() ;
​
        System.out.println("-----------------------");
​
        //加入婚庆代理角色
        You you = new You() ;
        //创建婚庆公司
        WeddingCompany wdc = new WeddingCompany(you) ;
        wdc.marry();
    }
}
​
//定义接口:Marry
interface  Marry{
    public abstract  void marry() ;
}
​
//定义一个子实现类:真实角色
class You implements Marry{
​
    @Override
    public void marry() {
        System.out.println("我很高兴,我要结婚了...");
    }
}
​
//代理角色weddingCompany:婚庆公司 要实现Marry接口
class WeddingCompany implements  Marry{
    private You you ;
    public WeddingCompany(You you){
        this.you = you ;
    }
​
    @Override
    public void marry() {
        System.out.println("结婚之前,婚庆公司布置婚礼现场...");
        you.marry();
        System.out.println("结婚完毕,很高兴,给婚庆付尾款...");
    }
}
//创建资源共享类对象
SellTicket st = new SellTicket() ;
//创建多个线程类对象,将资源共享类作为参数传递
Thread t1 = new Thread(st,"窗口1") ;
Thread t2 = new Thread(st,"窗口2") ;
Thread t3 = new Thread(st,"窗口3") ;
​
//启动线程
t1.start();
t2.start();
t3.start();
//-----------------------------
public class SellTicket implements  Runnable {
    //100张票
    public static int tickets = 100 ;
//    public  Object obj = new Object() ;
​
    //定义一个统计变量
    int x = 0  ;
​
    @Override
    public void run() {
        //模拟一直有票
        while(true){
            if(x % 2 == 0){
//                synchronized (this){
                synchronized (SellTicket.class){
                    if(tickets>0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
​
                        System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                    }
                }
            }else{
                //x%2!=0
                sellTicket();
            }
            x ++ ;
        }
    }
    
静态的同步方法 ---静态的东西都和类直接相关 :锁对象---就是 (反射相关)类名.class--->class 包名.类名{}  字节码文件对象
    private  static  synchronized  void sellTicket() {
​
        if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
        }
    }
}
​

JDK5以后Java提供了比syncrhonized(jvm来操作:自动释放锁)更广泛的锁定操作,程序员可以在某个位置自己去加锁,(弊端):手动释放锁
​
java.util.concurrent.locks.Lock  接口 不能实例化
  提供成员方法
   void lock() :获取锁
   void unlock():手动试图释放锁
 
ReentrantLock :子实现类         跟synchronized用于法相似
               可重入的互斥锁!
 
synchronized:  关键字---> 内置语言实现---通过jvm调用的
          由jvm自动释放锁
          它不仅仅可以应用在方法体中(同步代码块),也可以引用在方法上(同步方法)
 
Lock :是一个接口
      手动加锁和手动释放锁
       一般都是在方法中的语句中使用
       
----------------------
//创建资源类对象
        SellTicket st  = new SellTicket() ;
​
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;
​
        //启动线程
        t1.start();
        t2.start();
        t3.start();
​
public class SellTicket implements Runnable {
    public static int tickets = 100 ;//定义100张票
​
    private Lock lock = new ReentrantLock() ;    //声明一个锁:Lock
​
    @Override
    public void run() {
       
        while(true){ //死循环模拟一直有票
​
            //获取一个锁:某个线程执行到这块:必须持有锁
            lock.lock();
​
            //执行完毕,手动释放锁
            //在开发中 :try...catch...finally :捕获异常 ,不会使用throws
            //变形格式:try...catch...catch...
            //try...finally...
            try{
                if(tickets >0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
​
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                }
            }finally {
                //释放资源代码块
                //释放锁
                lock.unlock();
            }
​
        }
    }
}

死锁

虽然syncrhonized可以解决线程安全问题:同步代码块/同步方法,但是执行效率低,可能出现死锁
两个线程或者多个线程出现互相等待的情况!
​
解决死锁问题方案:"生产者消费者思想" 必须保证多个多线程必须使用的同一个资源对象!
public class DieLockDemo {
​
    public static void main(String[] args) {
​
        //创建资源类对象
        DieLock dl1 = new DieLock(true) ;
        DieLock dl2 = new DieLock(false) ;
​
        //创建线程类对象
        Thread t1 = new Thread(dl1) ;
        Thread t2 = new Thread(dl2) ;
​
        //启动线程
        t1.start();
        t2.start();
   }
}
​
------------------------
public class MyDieLock {
​
    //创建两把锁对象 (静态实例变量)
    public static final Object objA = new Object() ;
    public static final Object objB = new Object() ;
}
​
-------------------------
public class DieLock implements Runnable {
​
    //提供一个boolean类型的变量
    private boolean flag ;
    public DieLock(boolean flag){
        this.flag = flag ;
    }
​
    @Override
    public void run() {
        if(flag){
            synchronized (MyDieLock.objA){
                System.out.println("if objA");
                synchronized (MyDieLock.objB){
                    System.out.println("if objB");
                }
            }
        }else{
            synchronized (MyDieLock.objB){
                System.out.println("else objB");
                synchronized (MyDieLock.objA){
                    System.out.println("else objA");
                }
            }
        }
    }
}

Day4

等待唤醒机制(学生数据私有,提供同步方法)

public class Student {
  private   String name ;
  private  int age ;
  private   boolean flag ;
​
  //定义一个功能:给学生赋值(产生数据)
    public synchronized void set(String name,int age){ //同步方法  锁对象:this
  
            if(this.flag){//如果生产者有数据,等待消费者使用数据
                try {
                    this.wait(); //立即释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
​
        this.name = name ;
        this.age = age ;
​
            //如果存在数据
            this.flag = true ;
            //唤醒阻塞中的线程:消费者线程
            this.notify();
    }
​
​
    public synchronized void get(){    //获取学生的方法   
            if(!this.flag){ //判断如果当前没有数据了,等待生产者生产数据
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
​
            System.out.println(this.name+"---"+this.age);
            //判断如果当前没有数据类,唤醒生产者线程,产生数据
            this.flag = false ;
            this.notify();
    }
}
//----------------------------
public class SetThread implements  Runnable {
    private Student s ;
    public SetThread(Student s){
        this.s = s ;
    }
    int x  = 0 ;
​
    @Override
    public void run() {
        //模拟生产者不断产生数据
        while(true){
            if(x % 2 ==0){                
                s.set("张三",41);
            }else{             
                s.set("李四",26);
            }
            x ++;
        }
​
    }
}
//----------------
public class GetThread implements Runnable {
​
    private Student s ;
    public GetThread(Student s ){
        this.s  = s ;
    }
    @Override
    public void run() {
        
        while(true){//模拟消费者不断使用数据
            s.get();
        }
    }
}
//---------------------
public class ThreadDemo {
    public static void main(String[] args) {
        
        Student s = new Student() ;//创建学生对象
        
        SetThread st = new SetThread(s) ;//生产者资源类/消费者资源类对象
        GetThread gt = new GetThread(s) ;
       
        Thread t1 = new Thread(st) ;//创建线程了对象
        Thread t2 = new Thread(gt) ;
        t1.start();
        t2.start();
    }
}

线程组

线程组 ThreadGroup 线程组表示一个线程的集合
hread类中方法:
public final ThreadGroup getThreadGroup():获取当前所有线程的默认线程组
ThreadGroup
public final String getName() :获取默认的线程组名称: (默认就是main)
​
构造方法:
        ThreadGroup(String name):构造一个新的名称的线程组
 
        所有的线程默认的线程组就是main线程(用户线程)
public class ThreadGroupDemo {
    public static void main(String[] args) {
        //method() ;
        method2() ;
    }
​
    //设置线程组名称
    private static void method2() {
//        ThreadGroup(String name):构造一个新的名称的线程组
          ThreadGroup tg = new ThreadGroup("myMain") ;
          //创建线程类对象:可以将线程组对象作为参数传递
        //public Thread(ThreadGroup group,String name)
        Thread t1 = new Thread(tg,"线程1") ;
        Thread t2 = new Thread(tg,"线程2") ;
​
        System.out.println(t1.getThreadGroup().getName());//输出myMain
        System.out.println(t2.getThreadGroup().getName());//输出myMain
    }

线程池的使用Callable接口方式

1)接口:ExecutorService :跟踪一个或者多个异步任务
2)如何实例化---->Executors.newFixedThreadPool(int) 工厂方法:
​
Executors:工厂类
             提供创建线程池对象的方法
               public static ExecutorService newFixedThreadPool(int nThreads)
 
ExecutorService
          方法:
                   Future<?> submit(Runnable task) :通过线程池提交异步任务
                   <T> Future<T> submit(Callable<T> task):提交异步任务
 
                   Future:异步任务计算的结果!
 
第三种方式:线程池实现---->还是自定义一个类 实现Runnable接口
​
​
//Callable要比Runnable接口更好
//可以跟踪具体的异常错误(如果执行过程中,线程出现异常,可以跟踪异常信息!)
public class ThreadDemo {
    public static void main(String[] args) {
//创建一个线程池:静态工厂模式
        ExecutorService pool = Executors.newFixedThreadPool(2);//两个线程
        
       pool.submit(new MyCallable()) ;
       pool.submit(new MyCallable()) ;
​
        //使用完毕,关闭线程池--将底层产生的线程归还线程池中
        pool.shutdown();
        
//-------------------
public class MyCallable implements Callable<Object> {
    //MyCallabe:等待需要被线程池提交的异步任务
    
    //call方法:本身要计算的结果
    @Override
    public Object call() throws Exception {
        for(int x = 0 ; x <100 ; x ++ ){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
        return null;
    }
}
//------------------------
public class MyRunnable implements  Runnable{
    @Override
    public void run() {
​
        for(int x = 0 ; x < 100 ; x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}

两条线程分别求和

public class MyCallable implements Callable<Integer> {
​
    private int number ;
    public MyCallable(int number){
        this.number  = number ;
    }
​
    //call方法:异步结果结果:它的返回值需要和Callable泛型的数据类型一致
    //最终结果变量:
    int sum = 0 ;
    @Override
    public Integer call() throws Exception {  //就是线程执行的耗时操作 类似于 Runnable的run方法
        for(int x = 1 ; x <= number; x ++){
            sum+=x ;
        }
​
        return sum;
    }
}
//-------------------------
public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
​
        //创建存有2条线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
​
        //Future:接口:异步计算的结果
        Future<Integer> f1 = executorService.submit(new MyCallable(100));
        Future<Integer> f2 = executorService.submit(new MyCallable(200));
        //V get():获取结果值
        Integer i1 = f1.get();
        Integer i2 = f2.get();
        System.out.println(i1);
        System.out.println(i2);
​
    }
}

定时器

j ava.util.Timer:定时器  :有线程安排执行务执行一次,或者定期重复执行。
       构造方法:
               public Timer() 无参构造方法
 
成员方法
       public void cancel():取消定时器
       public void schedule(TimerTask task,Date time) :在指定日期时间内执行这个任务
      public void schedule(TimerTask task,long delay):在指定的延迟时间后执行task任务(时间:毫秒)
 
      public void schedule(TimerTask task,
             long delay,
             long period) :在指定的delay延迟时间后开始重复时间间隔period来执行task任务
public class TimerDemo {
​
    public static void main(String[] args) {
        //创建一个定时器
        Timer timer  = new Timer() ;
        //   public void cancel():取消定时器
​
        //参数1:定时任务:抽象类,定义子类继承自TimerTask
       // timer.schedule(new MyTask(timer),3000); :3秒后执行一次这个任务
​
      /*  public void schedule(TimerTask task,
                 long delay,
                 long period) :在指定的delay延迟时间后开始重复时间间隔period来执行task任务*/
      timer.schedule(new MyTask(timer),2000,3000);//2000指的是开始执行时间,3000指执行后再次执行时间,单位(毫秒)
    }
}
​
//定时任务
class MyTask extends TimerTask{ //TimerTask实现Runnable接口         ---会使用同步机制
    private Timer t ;
    public MyTask(Timer t){
        this.t = t ;
    }
int i = 0;
​
    @Override
    public void run() {
​
        System.out.println("bom...");
        //关闭定时器
        //t.cancel() ;
        i++;
        if (i == 10) {
            System.out.println("停止");
            t.cancel();// 增加判断,达到条件停止定时器
        }
    }
}
​

创建型设计模式之单例

单例: 在加载某个类的时候,内存中始终只有一个对象!(该类对象自动创建)
​
单例分两种:
    饿汉式:特点  永远不会出现问题的单例模式!
    在加载这个类的时候,就已经在内存中创建了一个对象!
    1)自定义一个类(具体类)
    2)成员位置:创建当前类的实例
    3)提供私有的构造方法:外界不能够创建它
    4)对外提供公共的访问方法:静态的,返回值当前类本身
 
懒汉式:可能出现问题的单例模式
    1)自定义一个类(具体类)
    2)成员位置:声明类型的变量
    3)构造方法私有化
    4)提供对外的公共访问方法:
    需要判断:当前如果没有对象,new 对象
    
    存在懒加载或者延迟加载!
    可能出现多线程 安全问题:

标准单例模式之饿汉式:Runtime

​
public class RuntTimeDemo {
​
    public static void main(String[] args) throws IOException {
​
        Runtime runtime = Runtime.getRuntime();
      //  Runtime runtime2 = Runtime.getRuntime();
        //System.out.println(runtime==runtime2);
        int cpuSize = runtime.availableProcessors();
        System.out.println(cpuSize);
        runtime.exec("notepad") ;
        runtime.exec("mspaint") ;
        runtime.exec("calc") ;
    }
}
public class Programmer {
​
    private static Programmer pro = null ;
​
    private Programmer(){}
​
    public synchronized static Programmer getPro(){//静态同步方法:锁对象:当前类名.class属性
            if(pro ==null){
                pro = new Programmer() ;
            }
            return pro ;
​
    }
​
​
}

懒汉

public class Tests {
​
    public static void main(String[] args) {
       
        Student s1 = Student.getStudent();
        Student s2 = Student.getStudent();
        System.out.println(s1==s2);
​
        System.out.println("-----------------");
        Programmer p1 = Programmer.getPro();//输出地址
        Programmer p2 = Programmer.getPro();
        Programmer p3 = Programmer.getPro();
​
        System.out.println(p1==p2);
        System.out.println(p1==p3);
​
    }
}
//------------------
public class Student {
​
    //创建该类实例---(类的实例变量)
    private static Student s = new Student() ;
    private Student(){} //外界不能创建对象
​
    //提供对外的公共访问方法:静态的
    public static Student getStudent(){
        return s ;
    }
}
​

创建型设计模式:对象的创建

Java提供:简单工厂模式 ---静态工厂方法模式
  优点:不需要具体类创建具体实例,通过工厂类创建
 
  弊端:一旦有一个新的类型增,修改工厂类!
 
  需要提供一个工厂类,负责具体的实例的创建
public class Test {
​
    public static void main(String[] args) {
​
        //创建猫
        Cat cat = new Cat() ;
        cat.eat();
        cat.sleep();
        //狗
        Dog dog = new Dog() ;
        dog.eat();
        dog.sleep();  
        
        //优化之后
        Animal animal = AnimalFactory.createAnimal("dog"); //父类引用指向子类对象
        animal.eat();
        animal.sleep();
        animal = AnimalFactory.createAnimal("cat") ;
        animal.eat();
        animal.sleep();
    }
​
}
​
//----------------------
public class Animal {//定义父类
​
    public void eat(){
        System.out.println("动物都需要吃");
    }
    public void sleep(){
        System.out.println("动物都需要休息");
    }
}
​
//------------------------
public class Cat extends  Animal {//猫继承动物类
        public void eat(){
            System.out.println("i can eat and eat mouse");
        }
        public void sleep(){
            System.out.println("i can sleep ...");
        }
}
//------------------------
public class Pig extends Animal {
    @Override
    public void eat() {
        System.out.println("eat");
    }
    @Override
    public void sleep() {
        System.out.println("sleep");
    }
}
​
//------------------------
public class AnimalFactory {
    //构造方法私有化
    private AnimalFactory(){} //外界不能创建当前类对象
    
/优化:利用多态:提供功能扩展
    public static Animal createAnimal(String type){
        if(type.equals("dog")){
            return new Dog() ;
        }else if(type.equals("cat")){
            return new Cat() ;
        }else if(type.equals("pig")){
            return new Pig() ;
        }else{
            System.out.println("对不起,工厂类没有提供者动物的实例创建!");
        }
        return null ;
    }
​
}
    

工厂方法模式:

对象创建的工作:有一个接口完成
接口的子实现类---->创建具体实例的工厂类
优点:面向接口编程:  结构非常清晰,维护起来容易
弊端:代码量增加了,需要编写额外的工厂类...
public class Test {
    public static void main(String[] args) {
        //没有使用工厂方法模式
        //抽象类多态
        Animal a = new Cat();
        a.eat();
        a = new Dog() ;
        a.eat();
        System.out.println("-----------------------------------");
        //猫的工厂类
        Factory f = new CatFactory() ;
        Animal animal = f.createAnimal(); //new Cat()
        animal.eat();
​
        f = new DogFactoy() ;
        Animal an = f.createAnimal();
        an.eat();
​
    }
}
//----------------
public  abstract  class Animal {
    public abstract  void eat() ;
}
//--------------------
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
//------------------
public class CatFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Cat() ;
    }
}
//----------------------
public class CatFactory implements Factory{//猫的工厂类 来实现 工厂接口
    @Override
    public Animal createAnimal() {
        return new Cat() ;
    }
}
//--------------------------
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }
}
//-----------------------------
public class DogFactoy implements Factory {
​
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
//---------------------------
public interface Factory { //工厂接口
    //创建动物的实例
    public abstract Animal  createAnimal() ;
}

Day5

什么是异常

异常就是程序出了问题
​
体系结构
      Throwable
         子类
         Error  Exception
​
 Error:严重问题: 无法直接使用代码方式解决(内存溢出...(加载大量图片的时候))
 Exception:程序出现的这种问题,是可以通过代码方式解决
          RuntimeException:运行时期异常
                   举例:
                           NullPointerException:都属于代码逻辑不严谨导致的!
           只要不是运行时期的出现的都是属于编译时期异常

解决异常的方案:

 try...catch...finally:标准格式
 变形格式
      try...catch
      try...catch...catch...
      try...finally
 
      捕获异常的执行流程
      1)首先执行try中的代码
      2)如果程序在try中出问题了,执行catch语句----jvm创建当前异常类对象:异常类名 e = new 异常类名() ;
        自动查看是否匹配catch语句中的异常对象,如果匹配,就执行处理的语句!
 
 
    throws:抛出异常

编译时期异常和运行时期异常的区别

编译时期异常:必须要进行处理,否则代码通过不了,运行不了!
如果编译时期异常的代码使用的捕获异常,调用者不需要在处理了!
           try...catch... (开发中:使用捕获)
 
          如果使用throws:抛出异常 在方法声明上使用
                          调用者必须要抛出,否则报错!
                          
 运行时期异常:
             调用者不需要显示处理,可以通过逻辑代码来优化
                                也可以显示处理
注意事项:
           不管什么编译和运行时期,尽量在代码中使用try...catch处理...

捕获异常的标准格式:

​
       try{
 
           可能出现问题的代码
 
       }catch(异常类名 变量名){
 
           处理语句;
       }finally{
 
           //一般情况
           释放相关的底层系统资源
           //io流中的流对象 (底层系统资源)
           //Statment:sql语句的执行对象
          //PreparedStatement:预编译的对象
           //Connection:数据库的链接对象
           //ResultSet:结果集对象
      }
 
       finally特点:
               就是释放相关的系统资源,而且finally语句一定会执行的!
               除非一种特例,在执行finally语句,jvm退出了! (System.exit(0))
 //--------------------------
  try{
            String s = "2021-5-28" ;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd ") ;
            Date date = sdf.parse(s) ;
            System.out.println(date);
        }catch (ParseException e){
            //String str = e.getMessage();//Unparseable date: "2021-5-28"
           // String str = e.toString() ;//java.text.ParseException: Unparseable date: "2021-5-28"
           // System.out.println(str);
            //public void printStackTrace():跟踪堆栈打印错误输出流
            e.printStackTrace() ;
            System.exit(0);
        }finally {
            System.out.println("这里的代码一定会执行...");
        }

面试题

final跟return的执行

当前try...catch...finally:捕获异常的时候,如果catch语句里面有return语句,finally还会执行吗?
   在前还是在后?
 
           finally一定会执行,在return 前 (将方法已经结束---catch语句中的return语句已经返回路径!)
 
           finally代码除非在执行前 jvm退出,----finally不会出现return,都是去释放资源...
           
           
public class FinallyDemo2 {
    public static void main(String[] args) {
        System.out.println(getNum(10));
    }
​
    private static int getNum(int i) {
        try{
            i = 20 ;
            int b = 0 ;
            System.out.println(i/b); //出现异常了
        }catch(Exception e){
            i = 30 ;  //i =30
            return i ; //当前位置 已经形成返回路径 i = 30
        }finally {
            i = 40 ;
            //return i ;
        }
        return i; // return 30
    }
}  

面试题throws和throw的区别?

这两个都是属于"抛出"
       throws:抛出
       1)抛出在方法声明上,而且方法声明上的异常类名可以跟多个,中间使用逗号隔开
       2)throws的异常处理交给:调用者进行处理
       3)throws表示抛出异常的一种可能性
       4)throws后面跟的异常类名
       
      throw:抛出
       1)是在方法体中使用,并非在方法声明上使用(位置不一样)
       2)throw的异常处理交给: 方法体中的逻辑语句判断
       3)throw表单抛出的异常的肯定性(执行某段代码,一定会执行这个异常)
       4)throw后面跟的异常对象: throw new XXXException() ;匿名对象

 

finally :
           一般使用在异常处理中:捕获异常 格式 try...catch...finally
           它里面的语句一定会执行(特例:在执行之前jvm退出)
           try...catch...finally---应用场景:
            业务层(service)代码中 使用捕获异
 
           在数据库访问层(dao)代码, 建议使用抛出throws

自定义一个异常类

异常体现的结构:
           Throwable
           error  exception
                       RuntimeException
                               很多运行时期异常
                       IOException,ParseException..编译时期异常
 
             自定义一个类:继承自RuntimeException
                           继承自 Exception
 
                   提供有参构造方法(String message)/无参构造方法
public class ExceptionDemo {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in) ;
        System.out.println("请输入学生成绩:");
        int socre = sc.nextInt() ;
        //创建Teacher类对象
        Teacher t = new Teacher();
        t.checkStudentSocre(socre);
    }
}
//-------------------
public class Teacher {
    //打分的功能
    public void checkStudentSocre(int socre){
        //分值:1-100
        if(socre<0 || socre>100){
            //非法数据
            throw  new MyException("学生成绩非法...") ;
        }else{
            System.out.println("学生数据合法...");
        }
    }
}
//--------------------
//自定义一个异常类 继承自RuntimeException
public class MyException  extends  RuntimeException{
   public MyException(){}
    public  MyException(String message){
        super(message) ;
    }
}

异常的使用注意事项:

 1)子类继承父类, 重写父类的方法的时候,如果父类的方法存在抛出异常,那么子类重写的方法的异常
      要么跟父类方法异常保持一致
    要么是父类方法异常的子类异常
​
 2)子类继承父类的时候,子类重写父类方法,如果父类的该方法没有抛出异常,那么子类只能去try...catch,不能throws,
        一旦子类抛出,那么父类的方法也必须抛出(不推荐更改父类的代码!)
public class ExceptionDemo2 {
    public static void main(String[] args) {
​
    }
}
​
class Father{
   public void show(){
       System.out.println("show father");
   }
}
//子类要重写method方法
class Son extends  Father{
   public void show() {
       //将日期文本--->日期格式
       //String--->Date
       try {
           String s = "2021-5-28" ;
           SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
           Date date = sdf.parse(s) ; //throws----> 父类的方法也必须throws
       } catch (ParseException e) {
           e.printStackTrace();
       }
   }
}
​

文件和目录(文件夹)路径名的抽象表示形式。

java.io.File:文件和目录(文件夹)路径名的抽象表示形式。
  构造方法
 
   File(String parent, String child)
   File(String pathname)
            通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
  File(File parent, String child)
           根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
 

File类的相关的文件夹的创建

 文件的创建
 文件夹以及文件的删除功能
 
  boolean mkdir() :创建文件夹:如果已经存在,创建不成功,返回false!
  public boolean mkdirs():创建多级目录的使用,如果父文件夹不存在,自动创建
​
  public boolean createNewFile()throws IOException:创建文件,可能出现IO异常(举例:文件找不到)
 
  public boolean delete():删除文件或者是文件夹
//创建一个demo文件夹  如果没有指定盘符:相对路径:默认在当前项目路径的下创建文件或者是文件
        File file = new File("demo") ;
        System.out.println(file.mkdir());
​
        File file2 = new File("demo\\a.txt") ;
        System.out.println(file2.createNewFile());

重命名功能

public boolean renameTo(File dest):对当前文件进行重命名
​
情况1:
     当前指定文件路径和重命名后的路径一致的,那么仅仅是改名字
 
    需要将D盘下的高圆圆.jpg改名个为杨桃.jpg
    D:\\高圆圆.jpg 
    D:\\杨桃.jpg
​
    情况2:如果路径不一致, ----改名并剪切
    
    
     File file  = new File("文件.jpg") ;//项目路径的文件
     File file2 = new File("d:\\文件1.jpg") ;//新文件地址
     System.out.println(file.renameTo(file2));//执行城后和将项目路径的文件转移至D盘下,改名位文件1

判断功能

public boolean canRead():判断这个文件是否是可读
public boolean canWrite():是否可写
public boolean exists():是否存在
public boolean isDirectory():是否是文件夹  (使用居多)
public boolean isFile():是否是文件         (使用居多)
public boolean isHidden():是否是隐藏文件

File类的高级获取功能:

public String[] list():当前目录下的所有的文件夹以及文件的字符串数组
public File[] listFiles():获取当前某个目录下的所有的File数组对象
​
​
需求:
    获取d盘下的所有的以.jpg结尾的文件
1)获取当前某个盘符下或者目录下的所有的文件以及文件夹的file数组
    public File[] listFiles():获取当前某个目录下的所有的File数组对象
​
2)防止空指针:判断如果当前File数组不为空的时候,遍历
    遍历,获取到每一个File对象
    2.1)File对象如果是文件 isFile()
    2.2)并且它还是以.jpg结尾的文件
    2.3)输出文件对象.getName()  获取到
 File file = new File("d:\\") ;`选择盘符
     
        File[] fileArray = file.listFiles();
        if(fileArray!=null){
            for(File f :fileArray){
                //获取名称 
                if(f.isFile()){
                    //再次判断
                    if(f.getName().endsWith(".jpg")){//判断D盘有无.jpg结尾的文件,并打印
                        System.out.println(f.getName());
                    }
                }
            }
        }

File类获取功能:

使用文件名称过滤器来帮助我们完成过滤!
优点:在获取的时候就已经通过文件名称过滤器筛选了
​
获取字符串列表
  public String[] list(FilenameFilter filter)
  获取文件列表
  public File[] listFiles(FilenameFilter filter) 形式参数接口:需要接口子实现类对象
              使用匿名内部类的方式
​
                     FilenameFilter:文件名称过滤器
                     boolean accept(File dir,String name)
                     返回值true或者false取决于:是否将当前name文件添加在文件列表中
//描述D盘
        File file = new File("d:\\") ;
​
        File[] fileArray = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
               
               File file = new File(dir,name);
             //一步走
                return file.isFile() && file.getName().endsWith(".jpg") ;
            }
        });
        for(File f :fileArray){
            System.out.println(f.getName());
        }

递归

方法调用方法本身的现象而不是方法嵌套方法!
​
使用递归的前提条件:
           1)必须有一个方法
           2)必须存在出口条件(结束条件):否则就是死递归
           3)有一定的规律
//需求:求出5的阶乘
​
 private static int getNum(int i) {
        //出口条件:如果i=1,永远是1
        if(i==1){
            return 1 ;
        }else{
            //i不等于1
            return i*getNum(i-1) ; //5 * getNum(4)
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值