小白学习Java第二十天

复习

1.线程方法

优先级:
优先级高的线程被cpu调度的可能性增强
级别:1-10
默认线程的优先级是:5
setPriority() getPriority()

守护线程:
叫做:用户线程,后台线程
作用:为非守护线程提供服务的
特点:依赖于非守护线程而存在
setDaemon(true) isDaemon()

注意:当多线程并发启动,某个线程出现异常,对其他线程是没有影响的。

2.线程的安全问题

产生:
多线程并发启动,操作同一个共享资源数据,操作该资源数据的代码行数有点多,某个线程还没有将这些代码都执行完,
另一个线程参与进来执行,导致错误的数据产生。
例子:多窗口售票

解决方式:
根本:那些不可分割的代码,即多行操作共享资源的代码,在被一个线程执行时,另一个线程不能进来执行,即使他有执行权
同步代码块

   synchronized(任意锁对象){
        共享资源代码
   }

同步方法

   synchronized修饰的方法
       非静态同步方法:this
       静态同步方法:类名.class

lock锁
jdk5.0,显示加锁

   Lock  lock = new ReentrantLock();
   lock(): 加锁
   unlock():释放锁

注意:1.多线程必须是同一个锁对象 2.操作共享资源的代码

3.死锁

两个线程启动,各自持有资源,对方想要持有的资源,双方都不释放持有的资源。
同步嵌套。

4.枚举类型

格式:

 修饰符  enum  枚举类名{
    枚举值名,枚举值名,...;
    属性、方法、构造方法(私有化)、抽象方法(重写)
 }

枚举值名:实际该类的实例对象,并且是静态的,意味着是类名直接访问。
获取所有的枚举值: static values()
某个类型的创建的对象的个数是有限制的,此时用枚举。

课程

一:多线程

(一) 线程状态

  1. 概述: 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。线程对象在不同的时期有不同的状态。

  2. 线程状态如下图:在这里插入图片描述

  3. 线程状态(线程的生命周期)如下图:

在这里插入图片描述

  1. 获取线程状态的方法:
    Thread.State getState() : 返回该线程的状态,Thread.State返回状态的类型就是枚举类型

(六) 线程池

6.1线程池概述

提到池,大家应该能想到的就是水池。水池就是一个容器,在该容器中存储了很多的水。那么什么是线程池呢?线程池也是可以看做成一个池子,在该池子中存储很多个线程。

线程池存在的意义:
系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务本身资源的消耗,这样就有点"舍本逐末"了。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中成为空闲状态。等待下一次任务的执行。

6.2 Executors创建线程池
  1. 概述 : JDK对线程池也进行了相关的实现,在真实企业开发中我们也很少去自定义线程池,而是使用JDK中自带的线程池。

  2. 使用Executors中所提供的静态方法来创建线程池
    (1) static ExecutorService newCachedThreadPool() 创建一个默认的线程池
    (2) static ExecutorService newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池

  3. 提交线程任务:

     1.Future<?> submit(Runnable task):提交一个Runnable任务,返回一个Future对象,可以通过get方法获得线程运行的结果
     2.Future<?> submit(Callable<T> task):提交一个Callable任务,返回一个Future对象,可以通过get方法获得线程运行的结果 
    
  4. 关闭线程池的方法:
    (1) void shutdown() : 关闭之后,已经提交的任务,执行完毕,后续不让提交任务了
    (2) List shutdownNow() :立即关闭线程池,已经正在运行的任务,运行完毕,在队列中,正在等待运行的任务,放到 list集合当中返回回来

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo2 {
    public static void main(String[] args) {
        //创建线程池,并指定最多的线程个数2
        ExecutorService service = Executors.newFixedThreadPool(2);
        //提交线程任务
        service.submit(new MyRun1());
        service.submit(new MyRun1());
        service.submit(new MyRun1());

        //关闭线程池
        //service.shutdown(); //执行完已提交的线程任务,然后关闭,不再接受新的任务
        List<Runnable> list =  service.shutdownNow(); //执行完正在执行的任务,等待的任务不执行,
        // 等待的任务作为返回值存储到集合中,不再接受新任务
        System.out.println(list);//java.util.concurrent.FutureTask@135fbaa4
        /*
        * FutureTask实现了Runnable接口,实现类中有方法,可以获取线程的状态、判断线程的状态、获取线程执行的后的结果。
        * */
    }
}

class MyRun1 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }
    }
}

/*
* 线程池:
*   池:指的就是容器
*   线程池:容器中存放已经创建好的线程对象。
*   作用:当有任务来,从池中取出一个线程对象来执行任务,当任务执行完后,线程对象不销毁,回到池中,继续等到下一个任务的来临。
*   频繁的创建和销毁线程是很耗费性能,所以出现了线程池的思想。
* */

二. 反射

(一) 虚拟机类加载机制

1.1 虚拟机类加载机制概述

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制.

1.2 类加载过程

当程序要使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始化三步来实现对这个类的加载.

  1. 加载
    (1) 就是指将class文件读入内存,并为之创建一个Class对象.
    任何类被使用时系统都会建立一个Class对象
  2. 连接
    (1) 验证是否有正确的内部结构,并和其他类协调一致
    (2) 准备负责为类的静态成员分配内存,并设置默认初始化值
    (3) 解析将类的二进制数据中的符号引用替换为直接引用
  3. 初始化
    主要对类变量进行初始化
    a: 类还未被加载, 程序先加载并连接该类
    b: 如该类还有直接父类, 则先初始化其直接父类
    c: 有初始化语句,按顺序执行
1.3 类的初始化时机

什么时候这个类的字节码文件被加载?【什么时候创建出该类的字节码对象 Class对象】
1.创建类的实例
2.类的静态成员使用
3.类的静态方法调用
4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
5.初始化某个类的子类
6.直接使用java.exe命令来运行某个主类

(二) 类加载器

概述: 类加载器是负责加载类的对象,将class文件加载到内存中,并为之生成对应的java.lang.Class对象.

2.1 类加载器的分类
  1. Bootstrap ClassLoader 引导类加载器,通常表示为null
    也被称为根类加载器,负责Java核心类的加载,比如System,String等.
  2. Extension ClassLoader 扩展类加载器
    负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录.
  3. Application ClassLoader 系统类加载器
    负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径.
  4. 自定义类加载器
    开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求.

类加载器之间的继承关系
-Bootstrap ClassLoader
-Extension ClassLoader
-Application ClassLoader

2.2 双亲委派机制
  1. 双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器.每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载.
  2. 双亲委派模型工作过程:
    1)当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成.
    2)当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成.
    3)如果Bootstrap ClassLoader加载失败,就会让Extension ClassLoader尝试加载.
    4)如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载.
    5)如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载.
    6)如果均加载失败,就会抛出ClassNotFoundException异常.

3.例子:
  当一个Hello.class这样的文件要被加载时.不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了.如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法.父类中同理会先检查自己是否已经加载过,如果没有再往上.注意这个过程,直到到达Bootstrap classLoader之前,都是没有哪个加载器自己选择加载的.如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException.

2.3 CLassLoader类
  1. ClassLoader 叫做类加载器.虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流” 也就是.class字节码文件,这个动作放到java虚拟机外部去实现,以便让应用程序自己决定去如何获取所需要的类,实现这个动作的代模块称之为“类加载器”.把【.class】文件加载到jvm虚拟机当中,转换为一个Class的对象【类的字节码对象 类的类对象】

2.ClassLoader的方法:
static ClassLoader getSystemClassLoader()
返回用于委派的系统类加载器

ClassLoader getParent()
    	返回父类加载器进行委派
public class Demo3 {
    public static void main(String[] args) {
        //获取系统类加载器
        ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
        System.out.println(sysLoader);  //AppClassLoader

        //获取父类加载器
        ClassLoader extLoder = sysLoader.getParent();
        System.out.println(extLoder); //ExtClassLoader

        System.out.println(extLoder.getParent());  //null

    }
}
/*
* 某个类型加载器到内存中,会自动创建一个Class对象。
*   Class对象是用于描述.class文件这类事物的对象类
*
*    类加载器(继承关系):
*         引导类加载器
*            --扩展类加载器
*               --系统类加载器
*
*    加载类采用的是双亲委派机制,从最子的加载器逐级向上委派,从顶层父类逐级进行加载,谁能加载就加载,都不能加载抛出异常。
* */

(三) 反射应用

3.1 反射机制的概述

反射是指在运行时去获取一个类的变量和方法信息.然后通过获取到的信息来创建对象,调用方法的一种机制.由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展.

举例说明 :

  1. 例如项目工程中, 有两个类,Student, Teacher, 需要使用这两个类
  2. 因为要使用上述两类, 这个两个类对应的.class字节码文件就会被类加载器从磁盘路径上加载进入到内存中
  3. 一个类型一旦进入到内存,证明需要使用,证明代码需要运行, 这种状态就是动态的效果
  4. 类加载器为这个正在运行的.class字节码文件, 创建出一个对应的Class对象, 对象中包含了class文件中所有代码内容(可以包含类中所有成员变量, 构造方法,方法…)
  5. 使用Class对象, 获取出类型中所有的需要的成员, 这种使用方式称为反射

在这里插入图片描述

3.2 获取Class类对象三种方式

1.Class类: Class类型的实例表示正在运行的java应用程序的类或者接口.
2.Class类的对象: 想获取和操作类中的内容,首先要获取类的字节码对象(Class类对象),每一个正在运行的类,都有对应的字节码对象,获取了类的字节码对象,就可以使用这个对象的所有方法,这些方法都定义在Class类型中.

3.三种获取Class类对象的方式:
1)类名.class属性
2)对象名.getClass()方法
3)Class.forName(全类名)方法
全类名 : com.ujiuye.demos.Demo01 包名 + 类名

public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class对象 ---com.day21.Person

        //第一种方式: 已知类型名
        Class<Person>  c1 = Person.class;
        System.out.println(c1);

        //第二种方式: 对象已存在
        Class<? extends Person> c2 = new Person().getClass();
        System.out.println(c2);

        //第三种方式: 已知类名(包名.类名)
        Class<?> c3 = Class.forName("com.day21.Person");
        System.out.println(c3);
    }
}

/*
* 之前方式:
*    1.先编写类
*    2.编译类
*    3.运行类
*    类如何编写的逻辑,就怎样去运行,结果不会变
*
*  反射技术:
*   在运行阶段,获取某个类型的中的成员信息(变量、方法、构造方法、父类、父接口、注解...),
*   根据这些信息,执行对应的操作。
*
*   源头:Class对象
*
* */
3.3反射获取构造方法并使用
  1. Class类获取构造方法对象:
    方法分类:

     Constructor<?>[] getConstructors()
      返回所有public公共构造方法对象的数组
    
     Constructor<?>[] getDeclaredConstructors()
     返回所有构造方法对象的数组
    
     Constructor getConstructor(Class<?>... parameterTypes)
     返回单个公共构造方法对象
     
     Constructor getDeclaredConstructor(Class<?>...parameterTypes)
     返回单个构造方法对象
    
  2. 注意:
    getConstructor(Class<?>... parameterTypes) getDeclaredConstructor(Class<?>…parameterTypes)
    两方法的参数列表为可变参数,可变参数即参数的个数可以是任意个,0个,1个或者多个均可,任意的数据类型都有对应Class对象, 连基本数据数据类型也不例外 : int.class

  3. Constructor类型:
    1)Constructor类表达的含义就是一个类当中的构造方法,一个对象就表达了一个构造方法
    2)构造方法对象应该具有的功能: 获取构造方法各种信息(构造方法修饰符、构造方法名称、构造方法的参数列表、构造方法的注解),最基本的一个功能就是,创建对象.

  4. Constructor类用于创建对象的方法:
    T newInstance(Object…initargs) 根据指定的构造方法创建对象,参数为所运行构造方法需要的实际参数.

package com.day21;

public class Person {
    private  String name;
    private  int age;

    public Person() throws  RuntimeException{
        System.out.println("无参数构造方法");
    }

    public Person(String name, int age) {
        System.out.println("有参数构造方法");
        this.name = name;
        this.age = age;
    }

    private  Person(String  name){
        System.out.println("私有构造方法");
        this.name = name;
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "com.day21.Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import com.day21.Person;

public class Demo5 {
    public static void main(String[] args) {
        //使用反射技术实现Person对象的创建
        /*
        * Class 类中提供的
        *       newInstance()
        *     注意:Class所表示的字节码文件中必须有无参数构造方法。
        *           即newInstance()方法创建对象时调用的无参数构造方法
        * */
        try {
            //1.获取Class对象
            Class<?> aClass = Class.forName("com.day21.Person");
            //2.创建对象,Class所表示的类型的对象
            Person p = (Person) aClass.newInstance();
            //3.通过对象调用类中的成员
            p.setName("小明");
            p.setAge(18);
            System.out.println(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

import com.day21.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Demo6 {
    public static void main(String[] args) {
        try {
            //1.获取Class对象
            Class<?> aClass = Class.forName("com.day21.Person");
            //2.获取类中的构造方法
//            Constructor<?>[] constructors = aClass.getConstructors();//获取所有的公共构造方法
            Constructor<?>[] constructors = aClass.getDeclaredConstructors();//获取所有的构造方法
            //3.根据constructor 所表示的构造方法,构造该Class所表示的类的对象
            Person p1 = (Person) constructors[1].newInstance("小红",18);
            System.out.println(p1.toString());

            Person p2 = (Person) constructors[2].newInstance();
            System.out.println(p2.toString());

            //暴力反射,将私有权限去掉
            constructors[0].setAccessible(true);
            Person p3 = (Person) constructors[0].newInstance("小刚");
            System.out.println(p3.toString());


            //遍历数组,查看构造方法的声明格式
            //修饰符    方法名  参数列表
            for (int i = 0; i < constructors.length; i++){
                //获取修饰符
                String mod = Modifier.toString(constructors[i].getModifiers());
                //获取方法名
                String name = constructors[i].getName();
                System.out.print(mod +"  "+ name +"(");
                //参数列表
                Class<?>[] params = constructors[i].getParameterTypes();
                if(params.length == 0) {
                    System.out.print(")");
                }else {
                    for (int j = 0; j < params.length; j++){
                        if(j != params.length-1){
                             System.out.print(params[j].getName() +" args"+j+",");
                        }else{
                            System.out.print(params[j].getName() +" args"+j+")");
                        }
                    }
                }

                //获取异常类型
                //Class<?>[] exceptionTypes = constructors[i].getExceptionTypes();


                System.out.print("{}\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/*
* java 是面向对象思想,任何事物都可以通过对象来描述。
*    因此它认为 构造方法 也是一类事物,可以通过对象来描述,因此有Constructor类。
*    Constructor 类的实例对象表示一个构造方法
*    newInstance(...) : 用于创建对象
* */

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo7 {
    public static void main(String[] args) throws Exception {
        //获取Class对象
        Class<?> aClass = Class.forName("com.day21.Person");
        //简单理解:aClass代表的是Person的类文件
        //类中文件中: 属性  方法 构造方法...
        //通过aClass可以获取文件中的内容。

        //获取构造方法 --Constructor

        //已近知道构造方法的参数列表类型,直接获取指定的构造方法对象即可。
        Constructor<?> constructor = aClass.getConstructor(String.class, int.class); //获取指定的公共构造方法
        // System.out.println(constructor);

        Object obj = constructor.newInstance("张三", 19);
        System.out.println(obj);

        //获取指定的构造方法(权限修饰符可以是任意的)
        Constructor<?> con = aClass.getDeclaredConstructor(String.class);
        //System.out.println(con);

        //暴力反射
        con.setAccessible(true);
        Object obj1 = con.newInstance("lisi");
        System.out.println(obj1);

    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值