Java总结(进阶)

10.JavaSE新特性概述
多例设计模式
构造方法私有化,类内部需要提供若干个实例化对象,然后通过static方法返回这些实例化对象

枚举(JDK1.5)
    枚举并不是一种新的结构,使用enum关键字定义的枚举本质上是继承于 java.ang.Enum 父类的枚举类
    JDK 1.5之后的枚举比起多例设计模式,简单且代码少,可以说枚举是一种高级的多例设计模式
    三个方法
        public String name();           // 取得当前枚举变量名字,对象方法
        public int ordinal();           // 取得当前枚举变量编号,对象方法
        public static Enum values();    // 以数组的形式返回所有的枚举变量名字,类方法
    
    枚举中也可以定义方法属性以及实现接口,这时,枚举对象必须放在首行,并且枚举对象要添加构造
    switch支持 int/char/enum/String

注解(Annotation,JDK1.5依赖使用最广的特性之一)
    @Override(准确覆写)
        用于子类覆写父类方法时,检测是否正确覆写,即如果该方法是覆写方法,并且覆写成功,则不会有语法错误,如果没有成功覆写,就会发生语法错误
    @Deprecated(声明过期处理)
        新版本程序里不建议使用这个类,但是旧版本使用没有问题,即在新版本里不推荐使用,但是使用也不会报错
    @SuppressWarnings(压制警告)
        不想出现警告信息(黄波浪线),使用压制警告,将警告信息进行压制

分工
    开发 DEV,测试 QA,产品 PM,运维 Sup

接口定义加强(JDK1.8开始)
    可以使用 default 定义普通方法,这时的 default 不能缺省,通过接口的实现类来调用接口的普通方法
    也已使用 static 来定义静态方法,通过接口名来调用

    加强之后的接口更像抽象类了,但是比起抽象类,接口的子类可以实现多继承,这是接口不可及的

Lambda表达式(JDK1.8开始)
    Java函数式编程典型代表

    接口的匿名内部类
        可以使用接口的匿名对象类进行接口的实现
            interface IMessage {
                public void print();
            }
            IMessage message = new IMessage() {
                // 匿名内部类
                // 进行接口方法的覆写
                public void print() {
                    // statment
                }
            };
            // 通经过口的匿名内部对方法类实现之后,可正常使用接口中的方法
            message.print();
    面向对象语法的最大局限就是结构必须完整,为了解决这个问题,Java推出了Lambda表达式来进行函数式编程
        // 效果与上例中的接口匿名内部类一致
        IMessage message2 = () -> System.out.println("hello");
	    message2.print();
    
    函数式编程的前提:接口必须只有一个方法,否则无法使用函数式编程
    语法
        -> 之后表示覆写接口中唯一的方法,,单行覆写如例子,多行的话使用 {}
        ( )内为该方法的参数,没有参数不写,可以不写类型,或者不写形参,但二者必须有一个
            IMessage message = (int a, int b) -> {
                int add = a+b;
                System.out.println(add);
                return add;
            };
        如果覆写的方法只有一行输出语句,比如 add(int a, int b) 方法只返回 a+b,可以如下表示
            (int a, int b) -> a+b;  // 形参只是一个符号,没有实际意义
        

    如果某个接口就是为了函数式编程而生,可以使用此注解
        @Functionallnterface
        此注解限定接口只能有一个方法,但是该接口不一定只能用做函数式编程

方法引用
    引用的本质就是别名,所以方法引用也就是别名的使用
    方法引用有以下四种类型
        1. 引用静态方法
            类名称::static方法名称;
        2. 引用某个对象(包括匿名对象)的方法
            实例化对象名::普通方法;
            例如引用字符串匿名对象的 toUpperCase() 方法
                IUtil<String> iUtil = "hello"::toUpperCase;
        3. 引用某个特定类的方法
            类名称::普通方法;
        4. 引用构造方法
            类名称::new;

内建函数式接口
    函数式编程的核心在于函数式接口函数式接口的核心在于只有一个方法
    Java内部提供了四个函数式接口,存放在 java.util.function 包内
        1. 功能型函数式接口
            public interface Function<T,R> R apply(T t);
                接口为 Function<T,R>
                方法为 R apply(T t);
                包为 import java.util.function.Function;
        2. 供给型函数式接口
            public interface Supplier T get();
            包为 import java.util.function.Supplier;
        3. 消费型函数式接口
            public interface Consumer void accept(T t);
            包为 import java.util.function.Consumer;
        4. 断言型函数式接口
            public interface Predicate boolean test(T t);
            包为 import java.util.function.Predicate;

11.JavaSE泛型
Eclipse简介

JDK1.5特性
    可变参数
        public [static] [final] 返回值 方法名称([参数类型 参数名称] [参数类型 ...参数名称]) {
            // statment
        }
        // ... 代表可变参数

        可变参数本质就是数组,可以传入数组,基本数据类型等
        要传入多种数据时,可变参数列表要放在最后一个
    
    foreach循环
        增强型的for循环,无需数组下标即可取得数据
        只支持打印取数据等不对数组进行修改的操作
    
    静态导入
        如果一个包中的类全都是 static 方法,则可以直接把这个类静态导入,不用定义该类就可以直接使用这些静态方法
            静态导入 inport static 包路径;
        不建议使用,了解概念即可
    
泛型
    泛型是 JDK1.5 之后引入的三的常用新特性之一,另外两个是枚举与注解
    泛型就是Java中的守门员,能解决参数转换的问题,可以避免向下转型使出现的 ClassCastException 异常
    泛型指的是在类定义时并不会设置类中属性或方法参数的具体类型,而是在类使用时再进行定义
    泛型基本语法
        class MyClass<T> {
            T value;
        }
        
        <> 里的 T 代表占位符,为类型参数,指代任意类型,在类使用时才会得到具体类型
        即声明时不定义任何具体类型,使用时才定义具体类型
        <> 里可以定义多个类型参数

    类型参数标识符
        一般来说, <> 里的类型参数标识符可以定义为任意符号,但是建议使用单个大写字母来定义
            T 代表一般的类
            E element 的意思,或者代表 Exception
            K key
            V value,通常与 K 搭配一起使用
            S Subtype
    泛型只能接受类,所以泛型为基本类型时要使用包装类

    实例化泛型类
        MyClass<T> myclass = new MyClass<t>();
        // JDK1.7 之后可以简写为
        MyClass<T> myclass = new MyClas<>();

    泛型方法
        方法也可以定义为泛型方法
        泛型类中也可以定义泛型方法
            泛型类传入的类型参数与其中泛型方法的类型参数不同,泛型方法始终以自己定义的类型参数为准
            为了避免混淆,泛型类的类型参数标识符与其中的泛型方法的类型参数标识符不要同名
    通配符(解决参数统一问题)
        通配符 "?" 可以代表任意参数类型,通过单独的通配符 "?" 传入方法的泛型类参数,不能进行修改
        "?" 不能作为泛型类定义时的参数类型
        子通配符
            ? extends 类:设置泛型上限
                作为传入方法的泛型类参数,不能进行修改
            ? super 类:设置泛型下限
                可以进行修改
                只能用在泛型方法里,不能用在泛型类里
            上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容
    泛型接口
        泛型也可以用在接口上,这种接口成为泛型接口
        实现接口的子类要么明确泛型类型,要么继续保留泛型
            明确了泛型类型的子类不再是泛型类,而继续保留泛型的类则是泛型类
    
    泛型擦除
        泛型是 Java1.5 才引进的概念,为了更好的和之前版本的代码兼容,所以又提出了泛型擦除
            泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息都会被擦出,这就叫做泛型擦除
            即,泛型类泛型方法和普通类普通方法在Java虚拟机内没有什么区别
        在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 <T> 则会被转译成普通的
            Object 类型,如果指定了上限如 <T extends String> 则类型参数就被替换成类型上限

12.JavaSE多线程
进程与线程
进程:操作系统中一个程序的执行周期成为进程
线程:一个程序同时执行多个任务,通常,每一个任务就称为一个线程
与进程相比较,线程更轻量级,创建撤销一个线程比启动停止一个新进程的开销要小很多
进程与线程的本质区别:每个进程拥有自己的一整套变量,而同一个进程的多个线程之间共享数据。共享数据是的线程之间的通信比进程之间的通信更有效,更方便
Java一大特色就是支持多线程编程
线程状态
就绪
通过系统调度与运行状态相互切换
阻塞
阻塞解除切换到就绪状态
运行
遇到导致阻塞的事件,切换到阻塞状态
进程中多个线程之间的执行顺序是随机的,没有任何顺序可言
多线程的实现
有三种实现多线程的方法
1.继承 Thread类 实现多线程
java.lang.Thread 是一个线程操作的核心类

            创建进程
                新建一个线程最简单的方法就是直接继承 Thread类,然后再覆写该类中的 run()方法,run方法 相当于主方法的 main,线程中的所有操作均在 run 中实现
            
            启动进程    
                直接在主方法中调用覆写的 run 方法是不能启动线程的,其效果相当于把 run 当作普通方法进行调用
                正确启动多线程的方法:调用 public synchronized void start() 方法。即调用 Therad类 的 start 方法
            
            为什么用通过 start 调用 run方法 来启动线程,而不是直接调用 run方法
                    分析 start 源码
                    ... start方法中调用本地方法Native方法start0方法,调用操作系统启动一个线程
            
            当重复启动同一个线程时 ,start 会抛出一个 IllegalThreadStateException异常 ,这是一个 RunTimeException(这是一个非受查异常,不进行异常处理也不会报错)。
            
            启动线程流程
                start方法 中调用了 start0() 方法,这个方法是一个只声明而未实现的方法,同时使用了 native 进行了修饰
                    private native void start0();
                    该方法调用了本地方法(native ,调用本地方法,C语言实现本地方法,一般为底层方法)
                        Thread类 中有一个 registrNative 本地方法,该方法主要作用是注册一些本地方法供 Thread类 使用,如 start0(),stop0() 等,可以说,所有操作本地线程的本地方法都由它注册
                        这个方法存放在一个 static块 中,当该类被加载到 JVM 中时,他就会被调用,注册相应的本地方法
                        所以 start0 实际调用的是本地方法 registrNative
                            registrNative方法 又调用了其中的 JVM_StartThread方法
                                而该方法又调用了 run方法      
                所以,总流程是 start -> start0 -> registrNative -> JVM_StartThread -> run
        2.Runnable()接口的实现
            其实 Thread类 的核心功能是启动线程,虽然创建线程的方法有三种,但启动线程的方法就只有 Thread类 start方法 一种
            如果一个类为了实现多线程直接去继承 Thread类 就会有单继承局限,因为子类继承了 Thread类 就不能再继承其他的父类了
            所以可以通过 实现 Runnable接口 来创建新的进程
                @Functionallnterface
                public interface Runnable {
                    // 只有一个 run 方法,所以可以使用 Lambda表达式
                    public void run();
                }
            创建线程
                创建一个类来实现 Runnable 接口,覆写其中的 run 方法
                
            启动线程
                Thread类 中有一个重载构造方法,可以接受一个 Runnable 对象
                    public Thread(Runnable target);
                然后调用 Thread 类的 start方法 就可以启动线程了
                也可以给 Thread类 构造传入 Runnable接口 的匿名内部类或 Lambda表达式 来启动线程
            
            继承 Therad类 和实现 Runnable接口 的区别
                从使用形式上来说, Runnable 实现要比 Thread 好,因为 Runnable 可以避免单继承限制,一个子类可以实现多个接口
                另外,Thread 是一个实现 Runnable接口 的子类,并且 Thread 覆写了 Runnable接口的run方法
                    public class Thread implments Runnable 
                    所以 实现Runnable接口 创建线程的方式其实上一个代理设计模式
                        实现子类为 真正业务类
                        Thread类 为代理类
                        两个类都实现 Runnable接口,组成代理设计模式
                实现 Runnable接口 创建线程的方式可以更好的描述线程之间的程序概念(Thread 不好描述)
        3.Callable实现多线程
            从 JDK1.5 追加了新的开发包:java.uti.concurrent,这个包只要用来进行高并发编程使用,在这个包中有一个新的接口 Callable
                public interface Callable<V> {
                    V call() throws Exception;
                }
                Callable接口 是一个泛型接口,它的 run方法 有一个返回值
            创建线程
                覆写 Callable接口 的 call方法,记得要传入具体类型参数
            启动线程
                // 将 Callable接口 接口的子类的实例化传入 FutureTask 的构造方法,来创建 FutureTask 的一个对象
                FutureTask<T> task = new FutureTask<>(new  MyThread());
                // 将 FutureTask 的对象传入 Thread 构造,然后使用 start 启动线程
                new Thread(task).start();

多线程的常用操作方法
    线程命名与取得
        // 创建线程的时候设定名称
        public Therad(Runnable target, String name);            
        // 获得线程名称
        public final synchronized void setName(String name);
        // 设置线程名称
        public final String getName();
        
        获得当前线程对象
            public static native Thread currentThread();
        如果没有设置线程名称,就会自动分配一个线程名称
        线程运行中不能进行修改
        主方法本身也是一个线程,所有的线程都是通过主线程创建并启动的
            String mainThreadName = Thread.currentThread().getName();
    
    线程休眠(sleep方法)
        让线程暂缓执行,等到了预计时间之后再恢复执行。线程休眠会交出CPU,让CPU去执行其他的任务。sleep不会释放锁,也就是说如果当前线程池有对某个对象的锁,即使调用sleep方法,其他线程也我要发访问这个对象
            public static native void sleep(long millis) throws InterruptedException
            时间以毫秒为单位
        sleep使线程进入阻塞状态
    线程让步(Thread 的 yield方法)
        暂停当前正在执行的线程对象,并执行其他线程
            public static native void yield();
        即调用 yield方法 会让当前线程较出CPU权限,让CPU去执行其他的线程。它跟 sleep方法 类似,同样不会释放锁
            但是 yield 不能控制具体交出CPU的时间,另外, yield方法 只能让拥有相同优先级的线程有获取COU执行时间的机会
        调用 yield方法 不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间
    join方法
        等待线程终止。如果在主线程中调用该方法就会让主线程休眠,调用该方法的线程的 run方法 先执行完毕之后再开始执行主线程
        join会抛出一个 InterruptedException 受查异常
    线程停止
        有三种停止线程的方式
            1.设置标记为使线程停止
            2.使用 Thread 的 stop方法 使线程退出
                使用 stop方法 强制退出,但是因为该方法不安全(可能会造成数据的丢失),所以已经被废除了
                    因为 stop 会解除由线程获取的所有锁定,当在一个线程对象上调用 stop 时,这个线程对象所运行的线程就会立即停止,这样可能会发生数据丢失
            3.使用 Thread.Interrupt()
                Interrupt方法 只是改变中断状态,它不会中断一个正在运行的进程。这一方法实际完成的是,给受阻塞的线程发出一个中断信号,这样时线程得以退出阻塞的状态
                然而 Interrupt方法 并不会立即执行终端操作,具体而言,这个方法只会给线程设置一个为 true 的中断标志
                    设置之后,则根据线程当前的状态进行不同的后续操作。如果线程当前的状态处于非阻塞状态,那么仅仅是线程的中断标志被修改为 true 而已,如果线程的当前状态处于阻塞状态,那么就在中断标志被设置为 true 后,还会有如下三种操作
                        1.如果是 wait,sleep,jion 三种方法引起的阻塞,那么会将中断标志重新设置为false,并抛出一个 InterruptedException
                        2.如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞
                            状态的情况来进行处理;例如,一个线程在运行状态中,其中断标志被设置为true之后,一旦线程调用了wait、
                            jion、sleep方法中的一种,立马抛出一个InterruptedException,且中断标志被程序会自动清除,重新设置为
                            false。
                调用线程类的 Interrupte 方法,其本质只是设置了该线程的中断标志,将中断标志设置为 true,并根据线程状态抛出异常。因此,通过 Interrupte 方法实现线程中断的原理使开发人员根据中断标志的具体值,来决定如何退出线程

    线程优先级
        设置优先级
            public final void setPriority(int newPriority)
        取得优先级
            public final int getPriority()
        对于优先级设置的内容可以通过 Thread类 的几个常量来决定
            // 最高优先级
            public final static int MAX_PRIORITY = 10;
            // 中等优先级
            public final static int NORM_PRIORITY = 5;
            // 最低优先级
            public final static int MIN_PRIORITY = 1;
        主方法也是一个线程,主线程的优先级为5
            int priority = Therad.currentThread().getPriority();
        线程具有继承性
            线程之间是具有继承关系的,比如在A线程中启动B线程,那么此时启动的B线程的优先级与A优先级一样
    守护线程
        守护线程是一种特殊的线程,是一个陪伴线程
        Java中有两种线程:用户线程和守护线程。可以通过 isDaemon()方法 来区别他们,用户线程返回 false,守护线程返回 true。典型的守护线程就是垃圾回收线程
        只要当前 JVM 进程中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才会随着 JVM 一起停止工作
        主线程main是用户线程
            
线程的同步与死锁
    同步处理指的是所有线程不是一起进入到方法种执行,而是按照顺序一个一个进入。效率较低,但是线程安全,不会产生不正确数据
    使用 synchronized 关键字处理同步问题
        1. 同步代码块
            使用同步代码块必须设置一个要锁定的对象,一般是锁定当前对象:this
                synchronized(this) {
                    // 同步代码块
                }
        2. 同步方法
            同步方法有且只有一个线程可以进入到同步方法中
        
        实际上,synchronized(this) 以及非 static 的 synchronized 方法,只能防止多个线程同时执行同一个对象的同步代码块。即 synchronized 锁住的是括号里的对象,而不是代码块
        即 synchronized 是一个对象锁
        当 synchronized 锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才能达到线程同步的目的。
        即使两个不同的代码块都要锁住同一个对象,那么这两个代码段也不能在多线程环境下同时运行

        当一个线程A 进入到同步方法所在的类中,其他线程不能进入该类中的其他类中,因为锁住的是对象

        锁住一段代码的方法
            1. 锁住同一个对象
                class Sync {
                    public void test() {
                        synchronized(this) {
                            // statement
                        }
                    }
                }

                class MyThread extends Thread {
                    private Sync sync;
                    public MyThread(Sync sync) {
                        this.sync = sync;
                    }
                    public void run() {
                        this.sync.test();
                    }
                }

                public class Test {
                    public static void mian(String[] args) {
                        Sync sync = new Sync();
                        for(int i = 0; i < 3; i++) {
                            MyThread myThread = new MyThread(sync);
                            myThread.start();
                        }
                    }
                }

            2. 全局锁
                设置同步代码块的对象为当前类,同一时刻有且只有一个对象能够进入当前类
                    synchronized(Sync.class) {

                    }
                或者使用静态同步方法
                    public static synchronized void test() {

                    }
    JDK1.5 提供的 Lock锁
        Lock锁 也是一个对象锁
        private Lock lock = new ReentrantLock();

        public void run() {
            // 打开锁
            lock.lock();
            // 一般与 try..finally 搭配使用,因为锁必须关闭
            try {
                // 业务代码
            } finally {
                lock.unlock();
            }
        }    
    
    死锁
        死锁的本质在于:一个线程等待另外一个线程执行完毕后才可以继续执行,但是如果如果相关的几个线程之间都在等待着,那么就会造成死锁。即死锁的出现一定是因为环
        过多的同步会造成死锁,所以对资源的上锁一定不能成环

生产者消费者模型
    设计模式的主要突破口是寻找到第三方
    生产者消费者模型是通过一个容器来解决生产者和消费者之间的强耦合问题。生产者和消费者比起之间不直接通讯,而通过阻塞队列进行通讯。生产者生产完数据不用等待消费者处理,而是直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列中取。阻塞队列在这里就相当于一个缓冲区,轻哼了生产者和消费者的处理能力
    这个阻塞队列就是用来给生产者和消费者解耦的。
        wait方法(使线程暂停运行)
            1. 使当前执行代码的线程进行等待。wait 是 Object类 的方法,该方法是用来将当前线程置入 预执行队列种,并且在 wait 所在的代码处停止执行,直到街道通知或被中断为止
            2. wait 只能在同步方法或同步代码块中被调用。如果调用 wait 时,没有持有适当的锁,会抛出异常
            3. wait 执行后,当前线程释放锁,线程与其他线程竞争重新获取锁
        notify方法(使停止的进程继续运行) 
            1. 方法 notify 也要在同步方法或同步块中调用,该方法是用来通知那些可能等待对象的对象锁的其他线程,对其发出通知 notify,并使他们重新获得该对象的对象锁。
                如果多个线程等待,则线程规化器随机挑选出一个呈 wait 状态的线程
            2. notify方法唤醒之后,当前线程不会马上释放对象锁,而是要等到当前 notify方法 的同步块/方法将程序执行完,即退出同步代码块之后才会释放对象锁,再执行还行的wait进程
        notifyAll方法(唤醒所有等待的进程)
            唤醒多个进程的顺序不定
        出现阻塞的情况:
            1. 线程调用 sleep 方法,主动放弃占用的CPU资源
            2. 线程调用了阻塞式IO方法,在该方法返回前,该线程被阻塞
            3. 线程企图获得一个同步监视器,但是该同步监视器正被其他线程所持有(join)
            4. 线程正在等待某个通知(wait)
            5. 程序调用了 suspend方法 将该线程挂起。此方法容易导致死锁,应避免使用

13.JavaSE反射
反射指的是对象的反向处理操作。所谓的反指的是根据对象来获得对象的来源信息(对象类的来源信息 包名.类名)
public final native Class<?> getClass(); // Object类的方法
返回一个 Class类 对象,这个Class描述的就是 对象的来源信息

反射研究的不再是一个对象,而是对象身后的组成(类,构造,成员等)

Class类是由JVM产生的,描述类的信息,由 JVM 产生,当类装载时,JVM对每个类会产生唯一对应的一个Class对象(每个类不论装载多少次,只会产生一个该类的Class对象)

Class类对象的三种实例化方式
    1. 调用 object类 的 getClass()方法 获取当前对象的 Class 实例
        Date date = new Date();
        System.out.println(date.getClass());

    2. 直接 类名.class
        Date.class();

    3. 调用 Class类 的静态方法 forName(类的全名称(包名.类名)) 取得满足条件的对象
        Class 类提供的 :public static Class<?> forName(String className) throws ClassNotFoundException() 方法
            Class<?> cls = Class.forName("***");
        最常用
    
    除了第一种方法会产生 Date类 的实例化对象之外,其他两种都不会产生 Date 的实例化对象
        所以取得Class对象的一个最直接的好处就是可以通过反射来实例化对象
            public T newInstance() throws InstantiationException, IllegalAccessException


创建对象的方式
    1. 正向处理:通过 类 new
    2. 反向操作:通过 Class对象的newInstance()
        Class<?> cls = Class.forName(类完整名称);
        // 通过Class对象实例化对象,等价于 new 类完整名();
        Object obj = cls.newInstance();
        // 使用该实例化对象时必须进行向下转型
        ((Demo)obj).method();
    通过方法2取得了Class对象就意味着取得了一个制定类的操作权

反射与工厂类结合
    传统的工厂模式在增加了新的类之后,就必须在 getInstance 中再增加返回该新增类实例化对象的语句,比较麻烦,使用反射可以不用如此
    Class 类可以使用 newInstance() 实例化对象,同时使用 Class.forName() 来接收类的名称
        class Factory {
            // 私有构造方法
            private Factory() {
                
            }
            
            // 静态方法
            @SuppressWarnings("deprecation")
            public static IFruit getInstance(String className) {
                IFruit fruit = null;
                try {
                    // 传入的是要生产的类的完整名称,使用 forName 获得对象,然后 newInstance 实例化对象
                    fruit = (IFruit) Class.forName(className).newInstance();
                } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return fruit;
            }
            
        }


反射与类操作
    利用反射可以做出一个对象具备的所有操作行为,这一切的操作核心是基于 Object 进行
    1. 取得父类信息
        a. 取得类的包名称
            Class类的getPackage()方法
                "package 包名"
            getPackage().getName()
                "包名"
            ==> getPackageName()
                "包名"
        b. 取得父类信息
            Class的 getSuperClass()方法
                "class 父类名"
            getSuperClass().getName()
                "父类名"
        c. 取得所有父接口(不止一个父接口应该用一个对象数组来接收)
            Class<?> cls = Demo.class;
            Class<?>[] class = cls.getInterfaces();

    2. 反射调用构造
        一个类中可以存在多个构造方法,如果要想取得类中构造的调用
            Constructor :描述类中构造方法的类,用来拿到构造方法

        a. Constructor getConstructor(Class<?>...parameterTypes):找到指定参数类型的构造方法
            // 只能拿到权限为 public 的构造方法
        Constructor getDeclaredConstructor(Class<?>...parameterTypes):可以拿到 private 的构造方法

        b. Constructor[] getConstructors():取得类中的所有构造方法

            Class<?> cls = Demo.class;
            Constructor<?>[] constructor = cls.getConstructors();
            for(Constructor<?> tmp:constructor) {
                // 直接打印调用了 Constructor类 的 toString方法,取得了构造方法的完整信息(权限,参数列表等)
                // 如果再使用了 getName() 方法,只会返回构造方法的 包名.类名
                System.out.println(tmp);
            }
                
        Constructor[] getDeclaredConstructors():可以拿到 private 的构造方法

        c. newInstance(Object...initargs):根据参数取得类的实例化对象
            Constructor.getInstance(...)
            Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。如果类中没有无参构造则无法使用Class类调用,只能通过明确的构造构造方法实例化

        int.class int这个基本类型的类信息

background

ClassLoader 类加载器

JDK自带六大命令行工具
1. jps:显示系统内所有的Hotspot虚拟机进程(最常用),并且显示执行主类名称并且返回PID(进程ID)
jps [options]
-q:只输出PID,省略主类名称
-m:输出JVM启动时传递给mian函数的参数(String[] args)
-l: 输出主类全名

2. jstat:用于收集HotSpot运行时数据,可以显示本地或远程JVM中类装载,内存,GC等信息
	命令行下运行期间定位JVM性能问题的首选工具
	jstat [option pid [interval count]]
		interval:查询间隔
		count:次数
		
		option:
			-gcutil:监视Java堆状况,并且输出已使用空间占总空间的百分比(主要使用该命令)
			-gcnew:监视新生代GC状况
			-gcold:监视老年代GC状况
			-class:监视类装载,卸载数量,总空间以及装载类所费时间

3. jinfo:显示虚拟机配置信息,即制定进程的JVM参数
	jinfo -flags pid
	
4. jmap:生成虚拟机JVM的内存转储快照,生成heapdump文件。jmap不仅可以获取dump文件,还可查询finalize执行队列,Java堆,永久代(元空间)等详细信息,例如空间利用率,当前使用的垃圾回收器等
	jmap [option] [pid]
		-heap:显示JVM堆详细信息
		-histo:显示heap中对象统计信息,包含类,实例信息,合计容量等
			-histo:live:显示当前存活的
		-dump:生成堆转储快照
			-dump:format=b,file=heap.bin // 固定格式
		
5. jhat:堆存储快照分析工具
	jhat dump文件
	JDK1.9没了!!!
	浏览器输入:localhost:7000,查看快照分析
6. jstack:Java堆栈跟踪工具,生成JVM当前时刻的线程快照。可用于定位线程出现长时间停顿的原因,入线程死锁,等待,死循环等问题。当出现线程停顿的时候,可使用jstack查看各个线程调用堆栈的情况
	jstack [option] pid
		-l:输出线程堆栈,显示有关锁的信息
		-m:可以显示本地调用的C/C++堆栈
	
	

	
	
	
hexo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值