《java8高级应用与开发》笔记(--类加载+反射+枚举+注解+国际化+格式化)

类加载:是指将类的class文件读入内存,并为之创建一个Java.lang.class对象。即当线程使用任何一个类时,系统都会为之创建一个java.lang.Class对象。可以在第一次使用某个类时加载该类,或者预加载机制。

Class类

java.lang.Class类封装一个对象和接口运行时的状态,当加载类时Class类型的对象将自动创建,Class没有公共构造方法,其对象是JVM在类加载时通过类加载器中的defineClass()方法自动构造的,不能显示的实例化一个class对象。

Class常用方法
static Class forName(String className) 返回指定类名的Class对象
T newInstance() 调用默认的构造方法,返回该Class对象的一个实例
String getName() 返回Class对象锁对应的类名
Constructor[] getConstructors()
ConstructorgetConstructors(Class…parameterType) 返回Class对象所对应的类的指定参数列表的public构造方法
Constructor[]getDeclaredConstructors() 返回Class对象所对应的所有构造方法,与访问权限无关
ConstructorgetDeclaredConstructors(Class…parameterTypes) 返回Class对象所对应类的所有构造方法,与访问权限无关
Method[] getMethod() 返回Class对象所对应类的所有public方法
Method getMethod(String name,Class…parameterType) 返回Class对象所对应的指定参数列表的public方法
Method[] getDeclaredMechods() 返回Class对象所对应的所有方法,与访问权限无关
Method getDeclaredMethod(String name,Class…parameterTypes) 返回Class对象对应类的指定参数列表的方法,与访问权限无关
Field[] getFields() 返回Class对象所对应类的所有public成员变量
Field getField(String name) 返回Class对象所对应的类的指定参数的public成员变量
Field[] getDeclaredFields() 返回Class对象所对应类的所有public成员变量
Field getDeclaredField() 返回Class对象所对应类所有的成员变量,与访问权限无关
ClassgetDeclaringClasses()) 返回Class对象所对应的外部类
Class[] getDeclaredClasses() 返回Class对象所对应的类里包含的所有内部类
ClassgetSuperclass() 返回Class对象所对应的类里的父类的Class对象
int getModifiers() 返回Class对象所对应类的修饰符,返回的整数是修饰符的对应常量,需要是使用Modified工具类解码
Package getPackage() 返回Class对象所对应的包
Class [] getInterfaces() 返回Class对象所对应类实现的所用接口
Class LoadergetClassLoader() 返回该类的类加载器
boolean isArray() 判断Class对象是否表示一个数组类
boolean isEnum() 判断Class对象是否表示一个枚举
boolean isInterface() 判断Class对象是否表示一个接口
boolean isInstance(Object obj) 判断obj对象是否是该Class对象的一个实例
boolean isAnnottation() 返回Class对象是否标识一个注解类型
Annotation [] getAnnotation() 返回Class对象所对应类上存在的所有注解
< A extends Annotation>A getAnnotation(Class annotationClass ) 返回Class对象所对应类上存在的指定类型的注解

每个类被加载之后,会生成一个Class对象,通过Class对象可以访问JVM中该类的信息,一旦类被载入JVM中,同一个类将不会被再次载入,被载入的类都有一个唯一的标识,是该类得到全限定类名(包括包名和类名)。

在Java中获取Class对象的三种方式:
1,使用Class类的forName(String classNmae)静态方法,参数class代表所需要类的全限定类名。
2,调用某个类的class属性来获取该类对应的Class对象,对象.class;
3,调用某个类的getclass()方法来获取该类对应的class对象,该方法是Object类中的一个方法.

通过
类的Class属性获得该类所对应的Class对象,会始代码更安全。程序性更好
string类型的字符串不能使用String.class方式。需要使用Class.forName(“java.lang.String”)
Class的forName()方法声明抛出ClassNotFoundException异常,调用必须捕获或抛出异常。

package com.liruilong.ClassDemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Date;



public class ClassDemo {

	public ClassDemo() {
		// TODO Auto-generated constructor stub
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("--------String 的Class类对象-----------");
		try {
			Class strClass = Class.forName("java.lang.String");
			System.out.println("Class对象:"+strClass);
		}catch(ClassNotFoundException e){
			e.printStackTrace();
			System.out.println("有错");
		}
		System.out.println("++++++++Float的Class类对象++++++++");
		Class fClass = Float.class;
		System.out.println(fClass);
		
		System.out.println("+++++++++Date类的Class类对象+++++++");
		Date nowTime = new Date();
		Class deteClass = nowTime.getClass();
		System.out.println(deteClass);
		System.out.println("--------Date类的父类:-----------");
		System.out.println(deteClass.getSuperclass());
		System.out.println("--------获取所有的Date类的构造方法:----------");
		Constructor[] ctors = deteClass.getDeclaredConstructors();
		for(Constructor c: ctors) {
			System.out.println(c);
		}
		System.out.println("------Date类的所有public方法--------");
		Method[] mtds = deteClass.getMethods();
		for(Method m:mtds) {
			System.out.println(m);
		}
		try {
			@SuppressWarnings("deprecation")
			Object obj = deteClass.newInstance();
			System.out.println(obj);
		}catch (Exception e) {
			// TODO: handle exception
		}
		
	}

}

类加载步骤:当程序使用某个未加载到内存中的类时,系统将通过加载,连接和初始化三个步骤对类进行初始化.

类的加载:由JVM提供的类加载器完成,程序运行的基础,由JVM提供的类加载器通常被称为系统类加载器,开发者可以通过继承ClassLoader类创建自己的类加载。

使用不同的类加载器,可以从不同来源加载类的二进制数据。类加载器通常无需在首次使用类时加载该类,JVM允许系统预先加载某些类

1,从本地文件系统或jar包中加载.class文件,大部分文件常用。
2,通过网络加载.class文件。
3,从java源代码文件动态编译成.class 文件,执行时加载。

类的连接:将二进制数据合并到JRE中,类连接分为三个阶段:
1,验证阶段:检验被加载的类是否有正确的内部结构,并和其它类协调一致;
2,准备阶段:负责为类的类变量分配内存,并设置默认初始值。
3,解析阶段:将类的二进制数据中的符合引用替换成直接引用。

类的初始化:是指针对类变量进行初始化,当程序使用任何一个类时,JVM会保证该类及其所有祖先类都被初始化,JVM初始化一个类包含以下几个步骤:
1,如果类没有被加载和连接,则程序先加载并连接该类。
2,如果类的直接父类未被初始化,则先初始化其直接父类。
3,如果类中有初始化语句,则直接执行初始化语句。

类加载器
类加载器负责将磁盘上或网络上的.class文件加载到内存中,并为之生成对应的java.lang.Class对象。
类加载器负责加载所有的类,系统为所有被载入内存的类生成相应的Class对象,一旦类被载入class中,同一个类将不会被重复载入,被载入的类拥有一个唯一标识(全限定类名)。

JVM启动时,会形成由三个类加载器组成的初始化类加载器层次结构:(用户可以定义自己的类加载器)

1,Bootstrap ClassLoader:根类加载器,负责加载java的核心类库,例如:rt.jar包;
2,Extension ClassLoader:扩展类加载器,负责加载JRE的扩展目录中的jar包即%JAVA_HOME%/jre/lib/ext目录或者java.ext.dirs系统属性指定的目录。
3,System ClassLoader:系统类加载器,负责在JVM启动时加载来自java命令的-classpath选项,java.class.path系统属性或CLASSPATH环境变量中所指的jar包和类路径。

类加载器机制三种;
1,全盘负责:当一个类加载器加载类时,该类所依赖的其他类也将有该类加载器负责,除非显示使用类加载器载入。
2,父类委托:先尝试使用父类加载器来加载,父类加载器无法加载时尝试使用自己类路径中的加载器。
3,缓存机制:保证所有加载过得类都被缓存,当程序使用某个类时,类加载器先存缓存区中搜索该类,Class对象不存在时,才会读取该类的二进制文件,将其转化为Class文件并存入缓存中去。
类加载器大致经过步骤:(背面)

ClassLoader类
java.lang.ClassLocader是一个抽象类,通过继承ClassLocader类来实现自定义的用户类加载器,以扩展JVM动态加载了类的方式,

方法 描述
public ClassloadClass(String name) 根据指定的名称加载类
protected Class loadClass (String name,boolean reslve) 根据指定的名称加载类,
protexted Class findClass(String name) 根据指定类名查找类
propected final Class findLoadedClass(String name) 该方法时java类加载缓存机制的体现,如果JVM已经加载指定的类,则直接返回该类对应的Class实例,否则返回null
protected final Class defineClass(String name,byte[] b,int off,int len) 将指定的来源于文件的或网络上的字节码文件(即.class文件)读入字节数组中,并转换为class对象。
protected final Class findSystemClass() 重本地系统文件中装入文件
public static ClassLoader getSystemClassLoader() 用于返回系统类加载器的静态方法
public final ClassLoader getParent() 获取当前类加载的父类加载器
public final void resolveClass(Classc) 链接指定的表

实现自定义类的加载器,可以通过重写ClassLoader类的LoadClass()或findClass()方法来实现,因为重写findClass()方法能够避免覆盖默认类加载器的父类委托和缓存机制两种策略,因此推存重载findClass方法。

package com.liruilong.ClassDemo;

import java.io.File;
import java.io.FileInputStream;

class Animal{
	public void say() {
		System.out.println("这是一个Animal类");
	}
}
public class MyClassLoader extends ClassLoader {

	public MyClassLoader() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public Class<?>findClass(String className){
		byte[] data = loadClassData(className);
		return this.defineClass(className,data,0,data.length);
	}

	private byte[] loadClassData(String className) {
		try{
			String path = this.getClass().getResource("/").getPath();//查找具有改定名称的资源,返回url对象。
			path = path.substring(1);
			className = className.replace(".", "/");
			File classFile = new File(path+className+".class");
			long len = className.length();
			byte[] rew = new byte[(int)len];
			FileInputStream fin = new FileInputStream(classFile);
			int r = fin.read(rew);
			if(r != len) {
				System.out.println("无法读取全部文件");
				return null;
			}else {
				return rew;
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		// TODO Auto-generated method stub
		MyClassLoader mcl = new MyClassLoader();
		Class<?>clazz = mcl.loadClass("com.liruilong.ClassDemo.Animal");
		Animal animal = (Animal)clazz.newInstance();
		animal.say();
	}

}

反射

java中对象在运行时会出现两种类型:编译时类型和运行时类型。
在程序运行时获取对象的真实信息有一下两种做法:
1,在知道对象类型的情况下,可以使用instanceof运算符进行判断,然后转型。
2,无法预知,必须通过反射来发现该对象和类的真实信息。
反射(Reflection)机制允许程序在运行时借助Reflection API取得任何类的内部信息,并不能直接操作对象的内部属性及方法。反射被视为动态语言的关键。
java反射机制主要提供了以下功能:
1,在运行时判断任意一个对象所属的类;
2,在运行时构造任意一个类的对象。
3,在运行时获取任意一个类所具有的成员变量和方法。
4,在运行时调用任意一个对象的方法。
5,生成动态代理。
Reflection API 提供了 Constructor,Field和Method类,这三个类定义在java.lang.reflect包中,分别用于描述类的构造方法,属性和方法。
Executable抽象类:java8在java.lang.reflect包下新增了一个Executable抽象类,代表可执行的类成员。Executable抽象类派生了Constructor和Method两个子类。Executable抽象类提供了大量方法来获取参数,修饰符或注解等信息。

方法 描述
parameter [] getparameters() 获取所有形参,返回一个parameter [] 数组
int getParameterCount() 获取形参个数
abstract int getModifiers() 获取修饰符,返回的整数是修饰符关键字对应的常量
boolean isVarArgs() 判断是否包含数量可变的形参

Constructor类:用于表示类的构造方法。通过Class的getConstructor()方法来获取构造方法的集合。

方法 描述
String getName() 返回构造器的名称
Class [] getParameterTypes() 返回当前构造方法的参数类型
int getModifiers() 返回修饰符的整型标识,返回的整数是修饰符是标识常量,需要使用Modified工具类方法解码Modified.toSting(int mod),可以通过Modified.PUBLIC 查看对应的值

Method类:用于封装方法的信息,调用Class对象的getMethods()方法或getMethod()可以获取当前类的所有方法或指定的方法。

常用方法 功能描述
String getName() 返回方法的名称
Class[] getparameterType() 返回方法的参数类型
int getModifieds() 返回修饰符的整型标识
Class getReturnType() 返回当前方法的返回类型

Field类:用于封装属性信息,调用Class对象的getFields()或getField()方法可以获取当前类的所有属性或指定属性。

常用方法 描述
String getName() 获取属性的名称
int getMOdifiers() 返回修饰符的整型标识
getXxx(Object obj) 获取属性的值,此处的Xxx对应的java8中的基本类型,如果属性是引用类型,直接使用get(Object obj)方法
setXxx(Object obj,Xxx val) 设置属性的值,此处的Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用set(Object obj,Object val)方法
Class [] getType() 返回当前属性的类型

文件对象.setAccessible(true):设置通过反射访问该成员变量时取消访问权限检查。
调用getDeclaredFields()方法可以获取包括私有和受保护的所有属性,但不包括父类的属性;调用getField方法可以获得所有的public属性。包括从父类继承的。

parameter类:是JAVA8中新增的API,每个paramtete 对象代表一个参数。Parameter类提供许多方法来获取参数信息

方法 功能
int getModifiers() 获取参数的修饰符
String getName() 获取参数的形参名
Type getparameterizedType() 获取带泛型的形参类型
ClassgetType() 获取形参类型
boolean isVarArgs() 判断该参数是否为可变参数
boolean isNamePreaent() 判断.class文件中是否包含方法的形参名信息
package com.liruilong.reflec;

import com.liruilong.algorithm.Solution;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Description : 创建对象的两种方法
 * @Author: Liruilong
 * @Date: 2019/9/21 21:42
 */
public class ClassDemo {


    public static void main(String[] args) {

        try {
            Class  aClass = Class.forName("com.liruilong.algorithm.Solution");
            Solution solution = (Solution) aClass.newInstance();
            Constructor constructor = aClass.getConstructor();
            // 获取所有方法信息
            Method[] methods = aClass.getDeclaredMethods();
            for (Method method : methods ){
                System.out.println(method.toString());
            }

            // 获取当前类的所有的成员变量
            Field[] field = aClass.getDeclaredFields();
            for (Field field1 : field){
                System.out.println(field1.toString());
            }
            System.out.println("获取构造方法"
            );
            // 获取当前类的所有的构造方法
            Constructor[] constructors = aClass.getDeclaredConstructors();
            for (Constructor constructor1 : constructors){
                System.out.println(constructor1.toString());
            }

        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }
}

Object类的.class文件默认是不包含参数信息的。

枚举

定义枚举的关键字为enum,枚举类是一种特殊的类。(不能继承其他类,不能被继承)
与普通类的区别:
1, 枚举类可以实现一个或多个接口,使用enum定义的类继承java.lang.Enum类,不是Objec类,因此枚举类不能显示继承其他父类。
2,使用enum定义的非抽象的枚举类时默认会使用final修饰,因此枚举类 不能派生子类。
3,枚举类的构造方法只能使用private访问修饰符,如果省略,默认使用private修饰,强制指定只能是private。
4,枚举类的所有实例必须在枚举类的类体的第一行显示列出,否则该枚举类永远不能产生实例。实例默认public static final修饰。
定义枚举类:

[修饰符]enum 枚举类名{
	//第一行列举枚举实例
}
public enum SeasonEnum{
	SPRING,SUMMER,SPRINGS("春")}

枚举类一旦被定义,就可以直接使用该类型的枚举实例,枚举实例的声明和使用方式类似于基本类型,但不能使用new关键字实例化一个枚举类型。枚举类型包含的预定义方法。

方法 功能描述
public static enumtype [] values() 返回一个枚举类型的数组,包含该枚举类的所有实例值
public static enumtype valueOf(Stirng str) 返回指定名称的枚举实例值。

使用枚举类的实例:枚举类.实例;
包含属性和方法的枚举类:可以定义枚举的属性和方法以及构造方法,在定义枚举类构方法时,不能定义public构造方法,枚举类的构造方法只能使用private或缺省。
Enum类:
所有的枚举类都继承自java.lang.Enum该类定义了枚举类公共的方法,java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口。Enum常用方法:

方法 描述
final int ordinal() 返回枚举类实例值在类中的序号,该序号与申明顺序有关,从0开始
final int compareTo (enumtype e) Enum实现了java.lang.Comparable接口,因此可以用于比较
boolean equals(Object other) 比较两个枚举引用的对象是否相等
public String toStirng() 返回枚举实例的名称,一般情况下不重写
public static >TvalueOf(Class< T>enumType,Stirng name) 返回指定枚举类型和指定名称的枚举实例值;

注解:

注解(Annotation):在程序中可以对任何元素进行注解,包括java包,类,构造器,域,方法参数以及局部变量。注解就像修饰符一样,使用时在其前面增加@符号,信息被存储在"name=value"键值对中。希望程序中的注解在运行时起到一定的作用,需要使用配套的工具对注解中的信息进行访问和处理,这种工具称为APT(Annotation Processing Tool注解处理工具)
注解元数据的作用:
编写文档:通过注解中标识的元数据可以生生doc文档。
代码分析:通过注解中标识元数据,使用反射对代码进行分析。
编译检查:通过注解中标识的元数据,让编译器能够实现基本的编译检查。
java.lang.annotation.Annotation是一个接口,该接口时所有注解类型都要扩展的公共接口,但该接口本身不能定义注解类型。不能手动扩展。
基本注解:
@Override:用于限定重写的父类方法,使用该注解修饰的父类方法必须重写父类中的方法,否则发生编译错误。
@Deprecated:用于标识某个元素是否已过时,当程序使用以过时的类方法时,编译器会出警告。
@SuppressWarnings:用于抑制编译警告的发布,允许开发人员取消显示指定的编译器警告。参数见151笔记,会一直作用域该元素的所有子元素。
@FunctionalInterface:java8中新增,用于指定某个接口必须是函数接口。java8规定,如果一个接口只有一个抽象方法,则该接口就是函数式接口。是为Lambda表达式准备的,java8允许使用lambda表达式来创建函数式接口。
@SafeVarags:在java7中新增,用于抑制“堆污染”警告。堆污染。将一个不带泛型的变量赋值给一个带泛型的变量将导致该变量污染。

List list = new ArrayList();
list.add(10);
list<Stirng>ls = list;//发生堆污染
System.out.printin(ls.get(0));

抑制堆污染的警告:
使用@Safevarags注解修饰引发该警告的方法。使用@SuppressWarnins(“unchecked”)修饰。编译时使用-Xlint:varargs选项。、
元注解
JDK提供元注解,负责注解其他注解,java8在java.lang.annotation包中提供6个元注解。

  • @Retention:指定其所修饰的注解的保留策略(保留多长时间,即指定JVM决策在什么时候删除当前注释,使用java.lang.annotation.RetentionPolicy来指定策略值,SOURCE(源文件保留),CLASS(编译期间),RUNTIME(运行时,最长))。
  • @Document:该注解是一个标记注解,用于指示一个注解将被文档化。即可以被javadoc工具提取成文档。
  • @Target:用于限制注解的使用范围。即可以用于那个程序单元(值为枚举值,ElementType.*)
  • @Inherited:该注解使父类的注解能被其子类继承。即子类被自动修饰。
  • @Repeatable:该注解使Java8新增的注解,用于开发重复注解。定义该注解可重复。
  • 类型注解(Type Annotation):该注解是java8新增的注解,在ElementType枚举增加了TYPE_PARAMTER和TYPE_USE两个人枚举值,允许在定义枚举时用@Target(ElementType.TYPE_USE)修饰。可以用在任何用到类型的地方使用类型注解。除了接口,类,方法,和成员变量外,还可以在创建对象时,类型转化,使用implements实现接口,使用throws声明抛出的异常序列。方法参数。
@Target(ElementType.TYPE_USE)
     @interface AnnotationDemoS{
    }
    public class  AnnotationDemo implements  @AnnotationDemoS  Serializable{
        public static  void main( @AnnotationDemoS String[] args){
            
        }
    }

定义注解。定义一个注解类型与定义一个接口相似,在interface前面加@,语法:

[访问符] @interface 注解名{ …………}
@Target(ElementType.TYPE_USE)
     @interface AnnotationDemoS{
        String commaa();
        int order() default 2;
    }

自定义注解的成员由未实现的的方法组成,在使用时实现,在定义注解时,可以使用default语句声明注解成员的默认值

使用注解:注解大多是为其他工具提供运行信息或决策依据而设计的,任何的java程序都可以通过反射机制来查询注解信息。在java的java.lang.reflect包中新增一个AnnotationElement接口。用于反射过程中获取注解信息。

Annotation getAnnotation (Class annotype) 返回调用的对象的注解
Annotation getAnnotations() 返回调用对象的所有注解
Annotation geyDeclareedAnnotations() 返回对象的所有非继承注解
Boolean isAnnotationPreset(Class annotype) 判断与调用对象关联的注解是由annoType指定的
import java.io.Serializable;
import java.lang.annotation.*;

    @Retention(RetentionPolicy.RUNTIME)//最长注解
    @Target(ElementType.TYPE_USE)
     @interface AnnotationDemoS{
        String commaa();
        int order() default 2;
    }
    @AnnotationDemoS(commaa = "as")
    public class  AnnotationDemo implements   Serializable{
        public static  void main( String[] args){
            AnnotationDemoS annotationDemo = AnnotationDemo.class.getAnnotation(AnnotationDemoS.class);
            System.out.println(annotationDemo);
输出:
            @AnnotationDemoS(order=2, commaa=as)

为使反射机制获取注解的相关信息,在定义注解时必须将注解的保留策略设置为RetentionPolicy.RUNTIME。否则获取不到注解对象。程序将会引发NullPointerException异常.

国际化

国际化: 简写为I18N ,源于Internationalization一词I和N中间有18个字符,国际化在设计阶段就应该使其具备多种语言功能,当需要在应用中添加对一种语言或国家的支持时,无需对已有的软件进行重构。
本地化:(loclization,L10N)是设计和编写能够处理特定区域的,国家或地区,语言,文化或政治环境的应用程序的过程。
国际化的思路抽取具备语言特性描述到资源文件。java语言本身采用Unicode编码,在java中,解决国际化问题大部分类位于java.util包,相关的类有:Locale,ResourceBundle,ListResourceBundle,PropertyResourceBundle等。
Locale类:主要包含对地理区域化特征的封装,其特定对象表示某一特定的地理,政治或文化区域。一个Locale实例代表一种特定的语言和地区,可以通过Locale对象中的信息来输出其对应语言和地区的时间,日期,数字等格式,
Locale常用方法

Locale(String language) 构造language指定语言的Locale对象
Locale(String language,String country) 构造language指定语言和country指定国家的Locale对象
String getCountry() 返回国家代码
String get DisplayCountry() 返回国家名称
String getLanguage() 返回语言代码
String getDisplayLanguage() 返回语言的名称
Static Locale getDefault 获取当前系统信息的对应的Locale对象
Static viod setDefault(new Locale) 从新设置默认的Locale对象
Locale[] locales = Locale.getAvailableLocales();
            Pattern pattern = Pattern.compile("zh");
            for (int i = 0; i < locales.length; i++) {
              Matcher matcher = pattern.matcher(locales[i].getLanguage());
                if (matcher.matches()){
                System.out.println("国家:" + locales[i].getDisplayCountry() + ":" + locales[i].getCountry());
                System.out.println("语言:" + locales[i].getDisplayLanguage() + ":" + locales[i].getLanguage());
            }else ;
            }

在使用Locale时。指定的语言及国家信息需要java支持才通过,调用Locale.getAvailableLocales()方法取得当前java 支持的所有国家和语言。
ResourceBundle类:用于加载国家和语言资源包。
资源文件的命名方式:baseName_language_countrry.properties,baseName_language.properties, baseName.properties
baseName是资源文件的基本名称,可以随意命名:language和country必须是java支持的。

public static final ResourceBundle getBundle(String baseName) 使用指定的基本名称,默认的语言环境和调用者的类加载器获取资源包
public Locale getLocale() 返回键的枚举
public final Object getObject(String key) 返回此资源包的语言环境
public final String[] getString(String key) 从此资源包或其某个妇包中获得给定的键的字符串
 ResourceBundle resourceBundle = ResourceBundle.getBundle("resourceName",Locale.getDefault());
                    System.out.println(resourceBundle.getString(""));

格式化处理:

依赖Locale类,java类提供格式器来完成对数字,货币,日期以及消息的格式化。

数字格式化,货币格式化。

不同的国家,数字的表示方式不一样。在java的java.text包中提供了一个NumberFormat类,用于完成对数字,百分比进行格式化和队对字符串对象进行解析。NumberFormat提供静态方法用于获取使用指定的Locale对象封装的NumberFormat实例,

static NumberFormate getNumberInstance() 返回当前系统信息相关的默认的数字格式器
static NumberFormat getNumberInstance(Locale l) 返回指定Locale为l 的数字格式器对象
static NumberFormat getPercentInstance() 返回当前系统信息相关的默认百分比格式器
static NumberFormat getPercentInstance(Locale l) 返回指定Locale为I 的百分比格式器对象
static NumberFormat getCurrencyInstance() 返回当前系统信息相关的默认货币格式器
String format(double number) 将数字number格式化为字符串返回
Number parse() 将指定的字符串解析为Number对象
 double value = 324234234.334543;
            Locale locale = new Locale("zh","CN");
            Locale locale1 = new Locale("en","US");
            Locale locale2 = new Locale("de","DE");
            NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
            NumberFormat numberFormat4 = NumberFormat.getPercentInstance();
            NumberFormat numberFormat1 = NumberFormat.getNumberInstance(locale1);
            NumberFormat numberFormat2 = NumberFormat.getNumberInstance(locale2);
            System.out.println(numberFormat.format(value));
            System.out.println(numberFormat1.format(value));
            System.out.println(numberFormat4.format(value));

日期格式化

java中日期和时间的格式化是通过DateFormat类来完成,该类的使用方与NumberForamat相似。
常用方法

static DateFormat getDateInstance() 返回默认样式的日期格式器
static DateFormat getDateInstance(int style) 返回默认指定样式的日期格式器
static DateFormat getDateInstance(int style,Locale alocale) 返回默认指定样式和Locale信息的日期格式器
static DateForm getTimeInstance() 返回默认样式的时间格式器(后两个一样)
static DateFormat getDateTimeInstance() 返回默认日期时间的格式器(后两个一样)

常用样式控制:DateFormat,FULL DateFormat.LONG DateFormat.DEFAULT DateFormat.SHORT;

DateFormat dateFormat  = DateFormat.getDateTimeInstance();
            Date date = new Date();
            System.out.println(dateFormat.format(date));

除了DateFormat类,java还提供日期格式器SimpleDateFormat类,通过预定义的模式字符串构造特定的模式串,然后根据模式串来创建SimpleDateFormat格式器对象。

 DateFormat dateFormat  = DateFormat.getDateTimeInstance();
            Date date = new Date();
            System.out.println(dateFormat.format(date));
             Date date1 = new Date(System.currentTimeMillis());
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
            System.out.println(simpleDateFormat.format(date));
            SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("今年是:YYYY 年");
            System.out.println(simpleDateFormat1.format(date));
模式字符 功能描述 模式字符 功能描述 模式字符 功能描述
D 一年中的第几天 y H(h) 小时(0-11)
d 一月中的第几天 s S 毫秒
E 星期中的第几天 m 分钟 M 月份

如果需要的模式串中使用的字符串(字符)不被SimpleDateformat 解释,可以在模式串中将其用单引号括起来。
SimpleDateformat 一般不用于国际化处理,而是为了以特定模式输出日期和时间。本地化使用。

消息格式化

国际化软件需要根据用户的本地化消息输出不同的格式,即动态实现消息的格式化,有java.text.MessageFormat类可以实现消息的动态处理。方法

方法 功能呢描述
public MessageFormat(String pattern) 构造方法,根据指定的模式字符串,构造默认语言环境下的MessageFormat对象
public Messageformat(Stringpattern,Locale locale) 构造方法,根据指定的模式字符串和语言环境,构造该语言环境下的MessageFormat对象
public void applyPattern(String pattern) 设置模式字符串
public String toPattern() 返回消息格式当前状态的模式字符串
public setLocale(Locale locale) 用于设置创建或比较子格式时所使用的语言环境,
public final String format(Object obj) 格式化一个对象以生成一个字符串,该方法是其父类Foramt的方法
public String formt(String pattern,Object…arguments) 创建具有给定模式的MessageFormat对象,并使用该对象来格式化改定的参数

参数pattern为一个带占位符的模式字符串,可以根据实际情况使用实际的值来替换字符串的占位符,在模式字符串中,占位符用{}括起来。

{ n [,formatType][,formatStyle]}
//其中n代表占位符的索引,formatType代表格式类型,标识数字,日期,货时间,代表格式样式,用于具体的样式,如货币,完整日期等。
分类 格式类型 格式样式 功能描述
数字 number integer currency percent #.## 整型,货币,百分比,小数
日期 date full long medium short 完整, 长,中等,短
时间 time full long medium short 完整, 长,中等,短

通常使用MessageFormat进行消息格式化的步骤如下:
1,创建模式字符串,其动态变化的部分使用占位符代替,每个占位符可以重复出现多次。
2,根据模式字符串构造MessageFormat(pattern)对象。
3,创建Locale对象,并调用setLocale()方法设置MessageFormat对象的语言环境。
4,创建一个对象数组,并按照占位符的索引来组织数据。
5,调用forma()方法实现消息的格式化,将对象数组作为参数。

public static void main(String[] args) {
		String pattern = "{0},开学快乐,欢迎你在{1,date,long}访问本系统,现在是{1,time,long}";
				MessageFormat format = new MessageFormat(pattern);
				Locale locale = Locale.getDefault();
				format.setLocale(locale);
				Object [] msgParams = {"lrl",new Date()};
				System.out.print(format.format(msgParams));
	}

java8新特性

DateTimeFormatter

在java8中新增一个DateTimeFormatter格式器类,相当于DateFormat和SimpleDateFormat的综合体,可以将时间日期对象格式化为字符串,还可以将特定的字符串解析为时间日期对象。
使用DateTimeFormatter进行格式化和解析,必须获取DateTimeFormatter对象,有三种方法:

  • 直接使用静态常量创建,静态常量本身就是DateTimeFormatter实例,IOS_LOCAL_DATE/TIME/DATE_TIME;
  • 使用不同风格的枚举值来创建DateTimeFromat对象,在FormatStyle枚举类中,定义FULL,LONG,MEDIUM,SHORT四个枚举值,代表不同风格。
    java.time.format.DateTimeFormatter.ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle)
  • 根据模式字符串创建DateTimeFormat对象; java.time.format.DateTimeFormatter.ofPattern(String pattern)
    DateTimeFormatter类提供了format()方法用于对于日期时间进行格式化,parse()方法对字符串进行解析。
		LocalDateTime date = LocalDateTime.now();
		//LocalDateTime是一个不可变的日期时间对象,代表日期时间,这个类是不可变的和线程安全的。
		//static LocalDateTime now()//从默认时区的系统时钟获取当前的日期时间。  
		DateTimeFormatter[] da = new DateTimeFormatter[] {
				DateTimeFormatter.ISO_DATE_TIME,
				DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG,FormatStyle.MEDIUM),
				DateTimeFormatter.ofPattern("yyyy-MM-dd ")};
		for(DateTimeFormatter d:da) 
			System.out.println(d.format(date));

接口的默认方法和静态方法

允许在接口中定义默认方法和静态方法,默认方法又称扩展方法,需要在方法前使用default关键字修饰。静态方法就是类方法,需要在方法前使用static关键字修饰。都必须有方法体。
默认方法需要通过接口实现类访问。静态方法可以直接接口访问。

Lambda表达式

:支持将代码做为方法参数,允许使用更加方便的代码创建一个抽象方法的接口实例。实际上为一种匿名方法,由参数列表,箭头,方法体组成。

(参数列表)->{方法体}
//参数列表中的参数do都是匿名方法等待形参,允许省略形参的类型,即可以为明确类型或者推断类型,当参数是推断类型时,参数的数据类型将由jvm根据上下文自动推断。
//->为Lambda运算符
//方法体可以为单一的表达式或多条语句组成的语句块,如果只有一条语句,则允许省略方法体{},如果只有一条return语句,可以省略return,Lambda表达式需要返回值,如果方法体中仅有一条省略了return关键字的语句,则Lambda表达式会自动返回该语句的结果值。
(int i ,int j)->{
	System.out.printin(x);
	System.out.printin(y);
	return x+y;
}
//如果参数类型只包含一个推断类型的参数时,可以省略小括号即
参数名->{方法体}
//只有一个参数和一条语句的Lambda表达式
参数名->表达式
//没有参数的Lambda表达式
()->{方法体}

Lambda的应用:
使用Lambda表达式输出集合内容,

String []string =  {"sdf","sdf","sdfsdf"};
		List<String> name = Arrays.asList(string);
		name.forEach((names)->System.out.println(names));//Lambda表达式方式
		name.forEach(System.out::println);//双冒号表达式,用于方法的引用

使用Lambda表达式实现排序:

List<String> arrNames = Arrays.asList("liruilong","shanhewuyang","qingchong");
            Collections.sort(arrNames, new Comparator<String>() {//调用容器工具类排序方法。
                        @Override
                        public int compare(String o1, String o2) {
                            return o1.compareTo(o2);
                        }
                    }
            );
            arrNames.forEach((x)-> System.out.println(x));
            System.out.println("______________________________");
            List<String> arrNamess = Arrays.asList("liruilong","shanhewuyang","qingchong");
            Collections.sort(arrNamess,(a,b)->b.compareTo(a));
            arrNamess.forEach(System.out::println);
            //比较器:public interface Comparator强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
            //int compare(T o1, T o2)比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
            

函数式接口

:本质上是只有一个抽象方法的普通接口,可以被隐式的转换为Lambda表达式,需要用注解定义。默认方法和静态方法可以不属于抽象方法,可以在函数式接口中定义。

@FunctionalInterface
public interface 接口名{
      //只有一个抽象方法;
}

函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object的public方法一样接口最终有确定的类实现, 而类的最终父类是Object。 因此函数式接口可以定义Object的public方法。
如以下的接口依然是函数式接口:

@FunctionalInterfacepublic
interface ObjectMethodFunctionalInterface {
void count(int i);
String toString(); //same to Object.toString
int hashCode(); //same to Object.hashCode
boolean equals(Object obj); //same to Object.equals
} 

为什么限定public类型的方法呢?因为接口中定义的方法都是public类型的。 举个例子,下面的接口就不是函数式接口:

interface WrongObjectMethodFunctionalInterface {
void count(int i);
Object clone(); //Object.clone is protected
} 

因为Object.clone方法是protected类型。
Lambda表达式只能为函数接口创建对像,即Lambda表达式只能实现具有一个抽象方法的接口,且给接口必须是有@FunctionlInterface 注释修饰。

::方法引用

:可以使用“::”来简化lambda表达式,由三部分组成,左边是容器,可以是类名或实例名,右边为方法名,可用于静态方法,实例方法,以及构造方法 ,语法:

容器::方法名
静态:  类名::静态方法名。
实例:  对象::实例方法名
构造:  类名:: new 

@FunctionalInterface
public interface LrlDemo <F,T>{
    T convert(F form);
}
 LrlDemo<String,Integer> con = new LrlDemo<String, Integer>() {
                @Override
                public Integer convert(String form) {
                    return Integer.valueOf(form);
                }
            };
            System.out.println(con.convert("34"));
            LrlDemo<String,Integer> cos = form -> Integer.valueOf(form);
            //LrlDemo cos = form -> Integer::valueOf;
            LrlDemo<String,Integer> coss = Objects::hashCode;
            System.out.println( cos.convert("45"));
            System.out.println(con.convert("34")+cos.convert("45"));
        }

无论是方法引用还是Lambda表达式,其最终原理和所实现的就是当某一个类中,或接口中某一个方法,其入口参数为一个接口类型时,使用方法引用或Lambda表达式可以快速而简洁地实现这个接口,不必繁琐的通过创建一个这个接口的实例对象。

java8新增类库:

Optional类:
空指针异常是导致程序运行失败的常见原因,goodle公司引入Optional类,通过使用检查空值的方式来防止代码污染。Option类实际为一个容器,额可以保存类型T得到值吗,或仅保存null,Option提供许多方法。

你可能感兴趣的:(Java)