《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对象所对应类所有的成员变量,与访问权限无关
Class<?>getDeclaringClasses())返回Class对象所对应的外部类
Class<?>[] getDeclaredClasses()返回Class对象所对应的类里包含的所有内部类
Class<? super T>getSuperclass()返回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 Class<?>loadClass(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(Class<?>c)链接指定的表

·实现自定义类的加载器
可以通过重写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提供了ConstructorFieldMethod类,这三个类定义在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()获取带泛型的形参类型
Class<?>getType()获取形参类型
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 <T extends Enum< T >>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一年中的第几天yH(h)小时(0-11)
d一月中的第几天sS毫秒
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代表格式类型,标识数字,日期,货时间,代表格式样式,用于具体的样式,如货币,完整日期等。
分类格式类型格式样式功能描述
数字numberinteger currency percent #.##整型,货币,百分比,小数
日期datefull long medium short完整, 长,中等,短
时间timefull 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<T>强行对某个对象 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<String,Integer> 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提供许多方法。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河已无恙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值