boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开头。
list.stream().filter(s->s.startsWith("zhang")).filter(s->s.length()==3).forEach(s-> System.out.println(s));
Stream流的使用
生成流
通过数据源(集合,数组等)list.stream
中间操作
一个流后面可以跟随零个或多个中间操作,其目的主要是打开流 。做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用filter()
终结操作
一个流只能由一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流最后一个操作forEach()
Stream流的常见生成方式
Collection体系的集合可以使用默认方法Stream()生成流 default Stream<E>stream()
Map体系的集合间接的生成流
数组可以通过Stream接口的静态方法of(T...values)生成流
public static void main(String[] args) {
//Map体系
Map<String,Integer> map = new HashMap<String,Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valuesStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
//数组
String[] st = {"java","world"};
Stream<String> str = Stream.of(st);
Stream<String> h1 = Stream.of("hello", "world");
Stream<Integer> h2 = Stream.of(100, 900);
}
Stream流的常见中间操作方法
1.Stream<T>filter(Predicate predicate):对于流中的数据进行过滤
Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
2.Stream<T>limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据
(取集合中前maxsize个数据)
3.Stream<T>skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流
4.static<T>Stream<T>concat(Stream a,Stream b):合并a和b两个流为一个流
5.Stream<T>distinct():返回由该流的不同元素(根据Object.equals(Object))组成的流
(去除重复元素)
6.Stream<T>sorted():返回由此流的元素组成的流,根据自然顺序排序
7.Stream<T>sorted(Comparator comparator):返回有该流的元素组成的流,根据提供的Compartor进行排序(int compareTo(T o) 将此对象与指定的对象进行比较以进行排序。)
8.<R>Stream<R>map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流 (类型转换)
Function 接口中的方法 Rapply(T t)
9.IntStream mapToInt(ToIntFunction mapper):返回一个IntStream其中包含将给定函数应用于此流的结果(IntStream 含有Stream没有的方法,例如sum求和)
IntStream:表示原始int流
ToIntFunction接口中的方法 int applyAsInt(T value)
Stream流常见的终结操作方法
void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
long count():返回此流中的元素数
Stream练习
public static void main(String[] args) {
ArrayList<String> manar = new ArrayList<String>();
ArrayList<String> womanar = new ArrayList<String>();
manar.add("林俊杰");
manar.add("周杰伦");
manar.add("周润发");
manar.add("许嵩");
manar.add("汪苏泷");
manar.add("李连杰");
womanar.add("林心如");
womanar.add("张曼玉");
womanar.add("柳岩");
womanar.add("林志玲");
womanar.add("林青霞");
womanar.add("张晓丽");
Stream<String> s1 = manar.stream().filter(s->s.length()==3).limit(3);
Stream<String> s2 = womanar.stream().filter(s->s.startsWith("林")).skip(1);
//static<T>Stream<T>concat(Stream a,Stream b):合并a和b两个流为一个流
//Object[] toArray() 返回一个包含此流的元素的数组。
//方法1
// Object[] ss = Stream.concat(s1,s2).toArray();
// for ( Object s : ss){
// Actor a = new Actor(String.valueOf(s));
// System.out.println("演员:"+a.getName());
// }
//方法2
Stream<String> s3 = Stream.concat(s1,s2);
s3.map(Actor::new).forEach(s-> System.out.println("演员:"+s.getName()));
}
Stream流的收集操作
Stream流的手机方法
R collect(Collector collector)这个收集方法的参数是一个Collector接口
工具类Collectors提供了具体的收集方式
public static<T> Collector toList():把元素收集到List集合中
public static<T> Collector toSet():把元素收集到Set集合中
public static<T> Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
Stream<String> s1 = manar.stream().filter(s->s.length()==3).limit(3);
Stream<String> s2 = womanar.stream().filter(s->s.startsWith("林")).skip(1);
List<String> stringList = s1.collect(Collectors.toList());
for (String s : stringList){
System.out.println(s);
}
数组转换
String[] ss = {"xiaohuang,30","xiaolan,25","xiaobai,27","xiaocai,22"};
//数组通过of(values T)
Stream<String> maps = Stream.of(ss).filter(s->Integer.parseInt(s.split(",")[1])>25);
//收集到Map
Map<String,Integer> map1 = maps.collect(Collectors.toMap(s->s.split(",")[0],s->Integer.parseInt(s.split(",")[1])));
Set<String> keyset = map1.keySet();
for (String key : keyset){
Integer value = map1.get(key);
System.out.println(key+","+value);
}
反射
1.类加载
就是指将Class文件读入内存,并为之创建一个Java.lang.Class对象 任何类被使用时,系统都会位置建立一个Java.lang.Class对象
2.类的连接
验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
准备阶段:负责为类的类变量分配内存,并设置默认初始化值
解析阶段:将类的二进制数据中的符号引用替换为直接引用
3.类的初始化
在该阶段,主要就是对类变量进行初始化
类的初始化步骤:1.假如类还未被加载和连接,则程序先加载并连接该类 2.加入该类的直接父类还未被初始化,则先初始化其直接父类 3.假如类中有初始化语句,则系统依次执行这些初始化语句(在执行第2步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1~3)
类的初始化时机:创建类的实例 调用类的类方法 访问类或者接口的类变量,或者为该类变量赋值 使用反射方式来强制创建某个类或者接口对应的Java.lang.Class对象 初始化某个类的子类 直接使用Java.exe命令来运行某个主类
类加载器
作用:负责将.class文件加载到内存中,并为之生成对应的Java,lang.Class对象
JVM的类加载机制
全盘负责:即使当一个类加载器负责加在某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显式使用另外一个类加载器来载入
父类委托:就是将一个类加载器负责加在某个Class时,先让父类加载器试图加载该Claa,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象储存到缓存区
ClassLoader:是负责加载类的对象
Bootstrap class loader:类加载器。 它是虚拟机的内置类加载器,通常表示为null ,并且没有父null
Platform class loader :平台类加载器可以看到所有平台类 ,可以将其用作ClassLoader实例的父ClassLoader 。 平台类包括由平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
System class loader : 它也被称为应用程序类加载器 ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类。 平台类加载器是所有平台类对其可见的系统类加载器的父级或祖先。
加载器的继承关系:System 的父类加载器为Platform 的父类加载器为Bootstrap
ClassLoader中的两个方法:
static ClassLoader getSystemClassLoader() 返回用于委派的系统类加载器。
ClassLoader getParent() 返回父类加载器进行委派。
ClassLoader c = ClassLoader.getSystemClassLoader();
System.out.println(c);
ClassLoader c1 = c.getParent();
System.out.println(c1);
ClassLoader c2= c1.getParent();
System.out.println(c2);
反射概述:Java反射机制,是指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息来创建对象、调用方法的一种机制。由于这种动态性,可以极大地增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
三种方式获取Class对象
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象。
1.使用类的Class属性来获取该类对应的Class对象
2.调用对象的getClass()方法,返回该对象所属类对应的Class对象
该方法是Object类中的方法,所有Java对象都可以调用该方法
3.使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符参数的值是某个类的全路径
public static void main(String[] args) throws ClassNotFoundException {
//使用类的Class属性来获取该类对应的Class对象
Class<Student> c1 = Student.class;
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c1==c2);
//调用对象的getClass()方法,返回该对象所属类对应的Class对象
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1==c3);
//使用Class类中的静态方法forName(String className)
Class<?> c4 = Class.forName("test5.Student");
System.out.println(c1==c4);
}
反射获取构造方法
Class类中用于获取构造方法的方法
Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象个数组
Constructor<T> getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回单个构造方法对象
Constructor类中用于创建对象的方法
T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。(根据指定的构造方法创建对象)
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//使用Class类中的静态方法forName(String className)
Class<?> c = Class.forName("test5.Student");
System.out.println();
//Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。
// Constructor<?>[] cs = c.getConstructors();
// for (Constructor cc :cs){
// System.out.println(cc);
// }
//Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组。
Constructor<?>[] cs = c.getDeclaredConstructors();
for (Constructor cc :cs){
System.out.println(cc);
}
//Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数
//Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。
//参数:你要获取的构造方法的参数的个数和数据类型对应的字节码文件对象
Constructor<?> c1 = c.getConstructor();
//Constructor提供了一个类的单个构造函数的信息和访问权限。
//T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
Object obj = c1.newInstance();
System.out.println(obj);
}
练习1
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//使用Class类中的静态方法forName(String className)
Class<?> c = Class.forName("test5.Student");
//公共方法
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//基本数据类型也可通过.class得到对应的Class类型
Object o = con.newInstance("xiaohuang", 30, "西安");
System.out.println(o);
}
练习2
void setAccessible(boolean flag) 值为true取消访问检查
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//使用Class类中的静态方法forName(String className)
Class<?> c = Class.forName("test5.Student");
Constructor<?> con = c.getDeclaredConstructor(String.class);
//暴力反射
//void setAccessible(boolean flag) 值为true取消访问检查
con.setAccessible(true);
Object o = con.newInstance("xiaohuang");
System.out.println(o);
}
反射获取成员变量
Field[] getDeclaredFields(): 返回所有成员变量对象的数组
Field[] getFields():返回所有公共成员变量对象的数组
Field getDeclaredField(String name) :返回单个成员变量对象
Field getField(String name) :返回单个成员变量对象
Field类中用于给成员变量赋值的方法
void set(Object obj, Object value):给obj对象的成员变量赋值为value
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//使用Class类中的静态方法forName(String className)
Class<?> c = Class.forName("test5.Student");
//Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段。
//Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段。
// Field[] fls = c.getDeclaredFields();
// for (Field fl : fls){
// System.out.println(fl);
// }
//Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段。
//Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段。
Field ad = c.getDeclaredField("address");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
//创建对象
Object obj = con.newInstance();
//void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值。
ad.set(obj,"西安");//给obj的成员变量 ad赋值为西安
System.out.println(obj);
}
练习
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> c = Class.forName("test5.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Field name = c.getDeclaredField("name");
//取消访问检查
name.setAccessible(true);
name.set(obj,"xiaohuang");
System.out.println(obj);
Field age = c.getDeclaredField("age");
Field address = c.getDeclaredField("address");
age.setAccessible(true);
address.setAccessible(true);
age.set(obj,30);
address.set(obj,"西安");
System.out.println(obj);
}
反射获取成员方法
Class类中用于获取成员方法的方法
Method[] getDeclaredMethods() :返回所有成员方法对象的数组,不包括继承的
Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的
Method getDeclaredMethod(String name, Class<?>... parameterTypes) :返回单个成员方法对象
Method getMethod(String name, Class<?>... parameterTypes) :返回单个公共成员方法对象
Method类中用于调用成员方法的方法
Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
//Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。
//Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。
//Method getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法。
Class<?> c = Class.forName("test5.Student");
Method method1 = c.getDeclaredMethod("method1");
//创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
//Object 方法返回值类型
//obj 调用方法的对象
//args 方法需要的参数
method1.invoke(obj);
}
反射练习(ArrayList<Intrger>集合,添加一个字符串数据)
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> ar = new ArrayList<Integer>();
Class<? extends ArrayList> ac = ar.getClass();
Method ma = ac.getMethod("add", Object.class);
ma.invoke(ar,"hello");
ma.invoke(ar,"java");
System.out.println(ar);
}
练习二(通过配置文件运行类中程序)
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("untitled\\class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c = Class.forName(className);
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method mt = c.getMethod(methodName);
mt.invoke(obj);
}
className = test5.Student
methodName = study
模块化
模块的基本使用步骤
1.在src目录下创建一个名为module-info.java的描述性文件,该文件专门定义模块名,访问权限模块依赖等信息,描述性文件中使用模块导出和模块依赖来进行配置并使用
2.模块中所有为导出的包都是模块私有的,他们是不能在模块之外被访问的
模块导出格式:exports 包名;
3.一个模块要访问其他模块,必须明确指定依赖哪些模块,为明确指定依赖的模块不能访问
模块依赖格式:requires 模块名;
注意:写模块名报错,需要按下ALT+Enter提示,然后选择模块依赖
模块服务的使用
1.创建一个包,在该包下提供一个接口,接口中i当以一个抽象方法
public interface MyService{
void service();
}
2.在该包下再建一个包impl,在impl下提供接口的两个实现类show1和show2
3.在myOne这个模块下的描述性文件中添加
模块导出:exports com.test2;
模块服务:provides MyService with show1 指定MyService的服务实现类是show1
4.在myTwo这个模块下的描述性文件中添加如下配置
生命服务接口:uses MyService;
5.在myTwo这个模块的类中使用MyService接口提供的服务
SercviceLoader:一种加载服务实现的工具