• JDK5新特性


     JDK5新特性目录导航:

    • 自动拆装箱
    • Foreach
    • 静态导入
    • 可变参数 Var args
    • 枚举
    • 格式化输出
    • 泛型
    • ProcessBuilder
    • 内省
    • 线程并发库(JUC)
    • 监控和管理虚拟机
    • 元数据

    自动拆装箱

    Java数据类型分两种:基本数据类型 和  引用数据类型(对象)

    有时候我们需要将基本数据类型包装为对象进行处理

    在JKD5以前我们的处理方式:

    //int 转换为 Integer
    int i = 10;
    Integer integer = new Integer(i);
    
    //Integer 转换为 int
    Integer integer1 = new Integer(100);
    int i1 = integer1.intValue();
    自动拆装箱处理方式:
    //int 转换为 Integer
    Integer integer = 10;
    
    //Integer 转换为 int
    int i = integer;

    将class反编译可以看出自动拆装箱的代码如下:

    Integer integer = Integer.valueOf(10);
    int i = integer.intValue();

    以上就是自动拆装箱的效果,同理其余基本类型也可以自动裁装箱对应的对象。详细对应关系如下表:

    基本数据类型 封装类
    int Integer
    byte Byte
    short Short
    long Long
    char Character
    double Double
    float Float
    boolean Boolean

     

    Foreach

    增强for循环,新增一种循环语法,格式:for( : ) 

    普通for与增强for循环对比如下:

    List<String> list = new ArrayList<String>();
    list.add("111");
    list.add("222");
    list.add("333");
    
    //JDK5 以前循环需要定义下标“index”并初始化,判断是否小于集合长度并自增,循环体还需要赋值
    for (int index = 0; index < list.size(); index++ ) {
        String str = list.get(index);
        System.out.println("str: " + str);
    }
    
    //foreach 增强for循环只需要下面代码即可完成上面的操作。
    for (String str : list){
        System.out.println("str:" + str);
    }

    反编译class文件可以看到增强for循环会被编译器自动处理如下代码:

    Iterator var4 = list.iterator();
    
    while(var4.hasNext()) {
        str = (String)var4.next();
        System.out.println("str:" + str);
    }

    具体编译成什么类型还的根据循环数据实际的数据类型,例如:

    //int数组 foreach 
    int[] ints = new int[]{1, 2, 3, 4, 5};
    for(int i : ints){
        System.out.println("i: " + i);
    }
    
    //class反编译结果
    int[] ints = new int[]{1, 2, 3, 4, 5};
    int[] var9 = ints;
    int var4 = ints.length;
    
    for(int var5 = 0; var5 < var4; ++var5) {
        int i = var9[var5];
        System.out.println("i: " + i);
    }

    从上面代码可以大致了解foreach,它基本可以替换掉你所有用普通for循环的代码

    静态导入

    静态导入可以将静态方法和静态变量通过 import static 和导包一样的方式直接导入,使用的时候无需使用类名即可直接访问。

     1 import static java.lang.System.out;
     2 import static java.lang.Math.*;
     3 
     4 public class ImportStaticTest {
     5 
     6     public static void main(String[] args) {
     7         /*
     8          *  使用静态导入 import static java.lang.System.out;
     9          *  out.println 可以直接使用调用 而不再需要类System对象去调用
    10          *  同时也支持*通配符
    11          */
    12         out.println("max(3,5): " + max(3,5));
    13         out.println("random(): " + random());
    14     }
    15 }

    输出结果:

    max(3,5): 5
    random(): 0.7808341266194762

    可变参数 Var args

    当传入到方法的参数不固定时,就可以使用可变参数 格式:数据类型... 参数名

     

     1 public class VarArgsTest {
     2 
     3     // Tips: 和以往main方式不一样,一般这样写 public static void main(String[] args)
     4     public static void main(String... args) {
     5         varArgs(1);
     6         varArgs(2,3);
     7 
     8         // ...
     9 
    10         varArgs(7,8,9,10,11);
    11     }
    12 
    13     // 可变参数的格式: 数据类型... 参数名
    14     public static void varArgs(int... ints) {
    15         for (int i : ints){
    16             System.out.println(i);
    17         }
    18     }
    19 }

    输出结果:

    1
    2
    3
    7
    8
    9
    10
    11

      

    枚举

    关键字enum表示枚举类型,它的作用相当于类声明中的class关键字,

    注意事项:

    1.不能含有public修饰的构造器,即构造器只能是private修饰,如果没有构造器编译器同样也会自动生成一个带private修饰无参默认构造器。;

    2.所有的枚举值默认都是public static final 修饰的;

    3.枚举值与值之间用逗号分割,最后一个用分号,如果枚举值后面没有任何东西该分号可以省略;

    4.每一个枚举值就是一个枚举类型的实例;

    5.枚举类型中可以定义带任意修饰符的非枚举值变量;

    6.枚举值必须位于枚举类型的第一位置,即非枚举值必须位于枚举值之后;

    7.枚举类型自带两个方法,values() 和 value(String name) 两个方法。

    枚举代码示例:

    //定义枚举类型
    public enum SexEnum {
        MAN,WOMAN
    }

    class反编译结果:

    public enum SexEnum {
        MAN,
        WOMAN;
    
        private SexEnum() {
        }
    }

    枚举类型方法默认方法示例:

     1 public class Test {
     2     public static void main(String[] args) {
     3 
     4         SexEnum man = SexEnum.valueOf("MAN");
     5         System.out.println("man: " + man);
     6         SexEnum woman = SexEnum.valueOf("WOMAN");
     7         System.out.println("woman: " + woman);
     8 
     9         SexEnum[] sexEnums = SexEnum.values();
    10         for (SexEnum sex : sexEnums) {
    11             System.out.println("SexEnum: " + sex);
    12         }
    13     }
    14 }

    输出结果:

    man: MAN
    woman: WOMAN
    SexEnum: MAN
    SexEnum: WOMAN

      

    格式化输出

    JDK5推出了printf-style格式字符串的解释器 java.util.Formatter 工具类,和C语言的printf()有些类似。

    简单示例:

    //创建对象时指定将结果输出到控制台
    Formatter formatter = new Formatter(System.out);
    formatter.format("x = %d , y = %s
    ",1 , "test");
    formatter.close();

    输出结果:

    x = 1 , y = test

    Formatter类可以将一些特定风格的字符转换为另一种格式进行输出,给出一下常用格式转换。

    d 整数型
    s String
    f 浮点数
    c Unicode字符
    b 布尔值
    e 科学计数
    x 整数(16进制)
    h 散列码(16进制)

     

    System.out.printf 和 System.out.foramt 方法的格式化输出就是调用了Formatter工具类。其中System.out.printf 的源码实际就是调用用了System.out.foramt方法。

    System.out.printf 源码如下:

    public PrintStream printf(String format, Object ... args) {
          return format(format, args);
    }

    泛型

    泛型格式:<>

    JDK5引入泛型是一个很大的功能增强,使用也比较广泛。使用多态进行数据传输时,JDK5之前使用Object传输,然后进行向下转型,这里可能在运行期强转失败抛ClassCastException异常,导致程序异常终止。引入泛型可以将此运行期异常转移到编译异常,在编写代码时就可以检测出问题。

    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
    
            //此处只能在运行期报ClassCastException异常。
            Object obj = new String();
            Integer i = (Integer) obj;
    
            //泛型
            List<String> list = new ArrayList<String>();
            list.add("abc");
            list.add("efg");
            //此处编译不通过,类型检测不能通过,在编译期就能解决错误。
    //        list.add(1);
    //        list.add(false);
    //        list.add(0.5);
    
        }
    }

    泛型关键技术:

    1.通配符问号(?)表示任意类型.如"List<?>"表示可以存放任意对象类型的List,和List<Object>一样。

    2.通配符可以连接限制符:extends 和 super

    如:上边界List<? extends Parent> 申明的List只能存放Parent及其子类,而下边界 List<? super Child> 申明的List只能存放Child及其父类。

    3.通用类型,通常使用一个大写字母表示如:T(这里可以使用任意符合命名规则的字符都可以,不过我通常喜欢使用一个大写字母表示),它能代表任何类型。

    如果使用通用类型申明一个变量,那么必须在类申明后面加上<T>,尖括号里面的符号必须是前面申明的通用类型变量,如果有多个可以使用逗号分割如:<T,D>;

    如果使用通用类型申明一个方法返回值或者方法参数,要么如上在类申明后加使用<>申明通用类型,要么在方法前申明通用类型。

     1 //在类申明后申明通用类型T,则可以在变量、方法返回值和方法参数使用
     2 public class Test<T> {
     3 
     4     //在变量处使用通用类型,且并需在类申明后申明通用类型
     5     T t;
     6     //此处报错因为,变量通用类型必须在类申明后申明
     7 //  E e;
     8 
     9     //在方法返回值处使用通用类型
    10     public T getT() {
    11         return t;
    12     }
    13 
    14     //在方法参数使用通用类型
    15     public String getType(T t) {
    16         return t.getClass().getSimpleName();
    17     }
    18 
    19     //方法返回值通用类型 和 方法参数通用类型 可以在方法前申明
    20     public <E> E getE(E e) {
    21         return e;
    22     }
    23 }

    ProcessBuilder

     ProcessBuilder可以用来创建操作系统进程,它的每一个实例管理着Process集合,start()方法可以创建一个新的Process实例

    主要方法:

    1.ProcessBuilder的start()方法:执行命令并返回一个Process对象;

    2.ProcessBuilder的environment()方法:返回运行进程的环境变量Map<String,String>集合;

    3.ProcessBuilder的directory()方法:返回工作目录;

    4.Process的getInputStream()方法:获得进程的标准输出流;

    5.Process的getErrorStream()方法:获得进程的错误输出流。

    演示代码

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            //创建进程
            ProcessBuilder processBuilder = new ProcessBuilder("ipconfig","/all");
            //获取当前进程的环境变量
            Map<String, String> map = processBuilder.environment();
            Process process = null;
            try {
                //执行 ipconfig/all 命令并返回Process对象
                process = processBuilder.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //获取进程标准输出流
            InputStream in = process.getInputStream();
            StringBuffer sb = new StringBuffer();
            int readbytes = -1;
            byte[] b = new byte[1024];
            try{
                while((readbytes = in.read(b)) != -1){
                    sb.append(new String(b,0,readbytes));
                }
            }catch(IOException e1){
            }finally {
                try{
                    in.close();
                }catch (IOException e2){
                }
            }
            System.out.println(sb.toString());
    
        }
    }

    内省

    内省(Introspector) 是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”,这些信息储存在类的私有变量中,通过set()、get()获得,如下所示:

    Person类示例:

    public class Person {
    
        private String name;
        private int age;
        private String address;
    
        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;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }

    在类Person中有属性name、age和address。通过 getName/setName来访问name属性,getAge/setAge来访问age属性,getAddress/setAddress来访问address属性,这是我们默认遵循的规则。Java JDK中提供了一套 API用来访问某个属性的 getter/setter 方法,这就是内省。

    内省类库:PropertyDescriptor类库:

    PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:

    1.getPropertyType():获得属性的class对象;

    2.getReadMeth():获得读取属性值的方法,返回Method对象;

    3.getWriteMethod():获得写入属性值的方法,返回Method对象;

    4.hashCode():获得对象的哈希值;

    5.setReadMethod(Method readMethod):设置读取属性值;

    6.setWriteMethod(Method writeMethod):设置写入属性值。

    //创建Person对象,并赋初始值
    Person person = new Person();
    person.setName("niannianjiuwang");
    PropertyDescriptor propertyDescriptor = new PropertyDescriptor("name",Person.class);
    //获得属性的Class对象
    System.out.println("Class: " + propertyDescriptor.getPropertyType().getSimpleName());
    Method method = propertyDescriptor.getReadMethod();
    System.out.println("Value: " + method.invoke(person));
    System.out.println("HashCode: " + propertyDescriptor.hashCode());

    线程并发库(JUC)

    JDK5提供了线程处理的高级功能,在(java.util.concurrent)包下。包括:

    1.线程护斥:Lock 类、ReadWriteLock接口

    Lock的方法:

    ReadWriteLock的方法:

     2.线程通信:Condition接口

     Condition的方法:

    3.线程池:ExecutorService接口

    ExecutorService的方法:

    4.同步队列:ArrayBlockingQueue类

     ArrayBlockingQueue的方法:

    5.同步集合:ConcurrentHashMap类、CopyOnWriteArrayList类

    ConcurrentHashMap相当于一个HashMap集合,但前者是线程安全的,所以性能上比后者略低。

    CopyOnWriteArrayList相当于一个ArrayList集合,前者其所有可变操作(add和set等)都是通过对底层的数组进行一次复制来实现,所以代价非常昂贵。

    6.线程同步工具:Semaphore类

    Semaphore的方法:

     关于JUC的并发库类容非常的多,这里将不一一列举。

     

    监控和管理虚拟机

    在JDK5中使用Bean监控和管理Java虚拟机,java.lang.management.ManagementFactory是管理Bean的工厂类,通过它的get系列方法能够获得不同的管理Bean的实例。

    ManagementFactory的方法:

    详细讲解以下几个对象:

    1.MemoryMXBean:该Bean用于管理Java虚拟机的内存系统,一个Java虚拟机具有一个实例。

    2.ClassLoadingMXBean:该Bean用于管理Java虚拟机的类加载系统,一个Java虚拟机具有一个实例。

    3.TreadMXBean:该Bean用于管理Java虚拟机的线程系统,一个Java虚拟机具有一个实例。

    4.RuntimeMXBean:该Bean用于管理Java虚拟机的线程系统,一个Java虚拟机具有一个实例。

    5.OperatingSystemMXBean:该Bean用于管理操作系统,一个Java虚拟机具有一个实例。

    6.CompilationMXBean:该Bean用于管理Java虚拟机的编译系统,一个Java虚拟机具有一个实例。

    7.GarbageCollectorMXBean:该Bean用于管理Java虚拟机的垃圾回收系统,一个Java虚拟机具有一个或者多个实例。

    演示代码:

     1 import java.lang.management.*;
     2 import java.util.List;
     3 
     4 public class Test {
     5     public static void main(String[] args){
     6         //Java虚拟机的内存系统
     7         MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
     8         System.out.println("虚拟机的堆内存使用量: " + memoryMXBean.getHeapMemoryUsage());
     9         System.out.println("虚拟机的非堆内存使用量: " + memoryMXBean.getNonHeapMemoryUsage());
    10         //Java虚拟机的类加载系统
    11         ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
    12         System.out.println("当前加载到Java虚拟机中的类的数量: " + classLoadingMXBean.getLoadedClassCount());
    13         System.out.println("自Java虚拟机开始执行到目前已经加载的类的总数: " + classLoadingMXBean.getTotalLoadedClassCount());
    14         //Java虚拟机的线程系统
    15         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    16         System.out.println("当前线程的总CPU时间: " + threadMXBean.getCurrentThreadCpuTime());
    17         System.out.println("当前活动线程的数目,包括守护线程和非守护线程: " + threadMXBean.getThreadCount());
    18         //Java虚拟机的线程系统
    19         RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    20         System.out.println("当前Java库路径: " + runtimeMXBean.getLibraryPath());
    21         System.out.println("当前Java虚拟机实现提供商: " + runtimeMXBean.getVmVendor());
    22         //操作系统
    23         OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
    24         System.out.println("当前Java虚拟机可以使用的处理器数目: " + operatingSystemMXBean.getAvailableProcessors());
    25         System.out.println("当前操作系统名称: " + operatingSystemMXBean.getName());
    26         //Java虚拟机的编译系统
    27         CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
    28         System.out.println("当前(JIT)编译器的名称: " + compilationMXBean.getName());
    29         System.out.println("当前即时(JIT)编译器的名称: " + compilationMXBean.getTotalCompilationTime());
    30         //Java虚拟机的垃圾回收系统
    31         List<GarbageCollectorMXBean> garbageCollectorMXBeanList = ManagementFactory.getGarbageCollectorMXBeans();
    32         for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeanList) {
    33             System.out.println("当前垃圾收集器的名字: " + garbageCollectorMXBean.getName());
    34             System.out.println("当前垃圾收集器累计回收总次数: " + garbageCollectorMXBean.getCollectionCount());
    35             System.out.println("当前垃圾收集器累计回收总时间: " + garbageCollectorMXBean.getCollectionTime());
    36         }
    37     }
    38 }

    输出结果:

    虚拟机的堆内存使用量: init = 134217728(131072K) used = 4094288(3998K) committed = 128974848(125952K) max = 1900019712(1855488K)
    虚拟机的非堆内存使用量: init = 2555904(2496K) used = 5223536(5101K) committed = 8060928(7872K) max = -1(-1K)
    当前加载到Java虚拟机中的类的数量: 586
    自Java虚拟机开始执行到目前已经加载的类的总数: 586
    当前线程的总CPU时间: 546875000
    当前活动线程的数目,包括守护线程和非守护线程: 6
    当前Java库路径: D:Program FilesJavajdk1.8.0_121in;C:WindowsSunJavain;C:Windowssystem32;C:Windows;C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;D:Program Files (x86)IDM Computer SolutionsUltraEdit;D:developmentmavenapache-maven-3.5.2in;D:Program Files (x86)ClockworkModUniversal Adb Driver;C:Program Files (x86)NVIDIA CorporationPhysXCommon;D:Program FilesGitin;.
    当前Java虚拟机实现提供商: Oracle Corporation
    当前Java虚拟机可以使用的处理器数目: 8
    当前操作系统名称: Windows 10
    当前(JIT)编译器的名称: HotSpot 64-Bit Tiered Compilers
    当前即时(JIT)编译器的名称: 99
    当前垃圾收集器的名字: PS Scavenge
    当前垃圾收集器累计回收总次数: 0
    当前垃圾收集器累计回收总时间: 0
    当前垃圾收集器的名字: PS MarkSweep
    当前垃圾收集器累计回收总次数: 0
    当前垃圾收集器累计回收总时间: 0

    元数据

    元数据也可以叫注解,这个名字估计容易理解,格式:@注解名

    注解的作用范围,可以通过java.lang.annotation.ElementType查看:

    1.TYPE:类、接口(包括注释类型)或enum声明

    2.FIELD:字段声明(包括enum常量)

    3.METHOD:方法申明

    4.PARAMETER:参数申明

    5.CONSTRUCTOR:构造器申明

    6.LOCAL_VARIABLE:局部变量申明

    7.ANNOTATION_TYPE:注解类型申明

    8.PACKAGE:包申明

    JDK内置三种标准注解: 

    @Override: 注解只能使用在方法上,表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误,或者方法签名对不上被覆盖的方法,编译器就会发出错误的提示

    @Deprecated: 注解可使用在构造器、字段、局部变量、方法、包、类接口以及枚举上,表示被弃用,不鼓励使用,编译器会发出警告信息。通常是因为它是危险的,或则因为有更好的选择。

    @SuppressWarnings:注解可以使用在构造器、字段、局部变量、方法、类接口以及枚举上,必须指定value值,关闭不当的编译器警告信息。告诉编译器不提示某某警告信息。

    注意的几个问题:

    1.  当注解的元素没有默认值的时候,在使用的时候必须为其指定初始值

    2.  如果注解元素有了初始值,那么在使用的时候可以为其赋新的值,否则将使用默认值

    3.  一个较为特殊的情况:注解元素当且仅当其只有一个元素且名称为value时,在使用该注解的时候为其赋值时可以不用写属性(元素)名称

    元注解:

    java内置了4种元注解,元注解负责注解其它的注解,可以理解成java中用来注解Annotation的Annotation

    @Retention: 保留策略,表示注解有多长保留,先了解JAVA文件的三个时期:SOURCE 源文件期(*.java文件) -> CLASS 编译器编译期(*.class文件) -> RUNTIME jvm运行时期。

    @Target: 表示注解使用的上下文,TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNOTATION_TYPE和PACKAGE。详细说明返回看注解的作用范围。

    @Documented: 表示将被javadoc记录。

    @Inherited: 表明注释类型是自动继承的。如果一个继承的元注释出现在注释类型上声明,用户在一个类上查询注释类型声明,类声明没有这种类型的注释,然后该类的超类将自动被查询注释类型。这个过程将会重复直到这个注释类型被找到,或者类层次结构的顶部(对象)是达到了。如果没有超类有这种类型的注释,那么查询将表明的类没有这样的注释。

     

  • 相关阅读:
    MySQL 数据恢复
    由 go orm 引发的探索
    beego 优雅重启
    2020年8月20日
    Linux 递归获取目录下所有满足条件的文件
    NET Core Kestrel部署HTTPS 一个服务器绑一个证书 一个服务器绑多个证书
    Flutter环境配置-windows
    Vue获取钉钉免登陆授权码(vue中的回调函数实践)
    【C#上位机必看】你们要的Iot物联网项目来了
    Windows Server系统部署MySQL数据库
  • 原文地址:https://www.cnblogs.com/lufeiludaima/p/pz20190212.html
Copyright © 2020-2023  润新知