java复习笔记day15

本文深入解析Java反射机制,包括类加载器的工作原理、Class实例的获取方法及反射的使用技巧。同时,详细阐述Lambda表达式的基础概念、语法格式及函数式接口的运用,辅以Stream API的介绍,帮助读者全面掌握Java高级特性。

1.类加载器-ClassLoader:

启动类加载器(bootstrap)、用户自定义加载类(user-defined-classLoader)

package reflectionTest;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

import org.junit.Test;

public class ReflectionTest {
	/**
	 * 需要掌握的
	 * @throws Exception 
	 */
	@Test
	public void test5() throws Exception{
		Properties pros = new Properties();
		//配置文件默认存储在当前工程目录下
		FileInputStream is = new FileInputStream("jdbc.properties");
//		FileInputStream is = new FileInputStream("src\\jdbc.properties");
		pros.load(is);
		String name = pros.getProperty("name"); 
		String pwd = pros.getProperty("pwd");
		System.out.println(name +"::::"+pwd);
//		方式二:此时的配置文件默认在src下
		InputStream inputStream = ReflectionTest.class.getClassLoader().getResourceAsStream("jdbc1.properties");
		pros.load(inputStream);
		String name1 = pros.getProperty("name");
		String pwd1 = pros.getProperty("pwd");
		System.out.println(name1 +"::::"+pwd1);
		
	}
	/**
	 * 类加载器的理解
	 */
	@Test
	public void test4(){
		ClassLoader loader1 = ClassLoader.getSystemClassLoader();
		System.out.println(loader1);//系统类加载器
		ClassLoader loader2 = loader1.getParent();
		System.out.println(loader2);//扩展类加载器
		ClassLoader loader3 = loader2.getParent();
		System.out.println(loader3);//引导类加载器 获取不到
		
		//java的核心类库  使用   引导类加载器加载
		ClassLoader classLoader = String.class.getClassLoader();
		System.out.println(classLoader);
		
		//自定义类  使用  系统类加载器加载
		ClassLoader classLoader1 = Person.class.getClassLoader();//Person.class是自定义的
		System.out.println(classLoader1);
	}
	/**
	 * 获取Class的实例
	 * @throws Exception 
	 */
	 @Test
	 public void test3() throws Exception{
		 //方法一:调用当前类的静态属性:class
		 Class clazz1 = Person.class;
		 System.out.println(clazz1);
		 //方法二:调用对象的getClass()
		 Person p1 =new Person();
		 Class clazz2 = p1.getClass();
		 System.out.println(clazz2);
		 //方法三:调用Class的静态方法forName(String className)
		 Class clazz3 = Class.forName("reflectionTest.Person");
		 System.out.println(clazz3);
		 //方式四:通过类的加载器获取(了解)
		 Class clazz4 = ReflectionTest.class.getClassLoader().loadClass("reflectionTest.Person");//找到当前类的加载器并用它加载Person类
		 System.out.println(clazz4);
		 
		 //验证四种方式加载的是否是同一个类,并没有创建新的类。
		 System.out.println((clazz1==clazz2)&&(clazz2==clazz3)&&(clazz3==clazz4));
	 }
	
	//反射的使用
	//1.获取Class的实例。
	//2.实例化Class对应的运行时类。
	//3.调用类中的结构:属性、方法、构造器。
	@Test
	public void test2() throws Exception{
		//1.获取Class的实例。
		Class clazz = Person.class;//clazz指向运行时类Person.class
		//2.实例化Class对应的运行时类。
		Person p1 = (Person) clazz.newInstance();
		System.out.println(p1);
		//3.1.调用运行类Person类中的公共的结构:属性、方法。
		Field f1 = clazz.getDeclaredField("name");
		f1.set(p1, "Tom");
		System.out.println(p1);
		Method m1 = clazz.getDeclaredMethod("setAge",int.class);
		m1.invoke(p1, 20);
		System.out.println(p1);
		//3.2.调用私有的属性、方法、构造器
		//3.2.1.属性
		Field f2 = clazz.getDeclaredField("age");
		f2.setAccessible(true);//设置可修改。
		f2.set(p1, 30);
		System.out.println(p1);
		//3.2.2.方法
		Method m2 = clazz.getDeclaredMethod("info");
		m2.setAccessible(true);
		m2.invoke(p1);
		//3.2.3.构造器
		Constructor con = clazz.getDeclaredConstructor(String.class);
		con.setAccessible(true);
		Person p2 = (Person)con.newInstance("Jerry");
		System.out.println(p2);
	}
	
	//反射之前:
	@Test
	public void test1(){
		//创建Person类的对象
		Person p1 = new Person();
		//调用指定的属性
		p1.name = "Tom";
		System.out.println(p1);
		//调用指定的方法。
		p1.setAge(10);
		p1.setId(1001);
		System.out.println(p1);
		
		p1.show();
		//不能调用私有的方法
//		p1.info();
		//不能调用私有的构造器
//		Person p2 = new Person("Jerry");
	}
}

package reflectionTest1;

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

import org.junit.Test;

import reflectionTest.Person;

/**
 * 反射运用三:调用运行时类中的指定的结构:属性、方法、构造器
 */
public class ReflectionTest {
	
	@Test
	public void test3() throws InstantiationException, IllegalAccessException{
		Class clazz = Person.class;
		Person p = (Person) clazz.newInstance();
		System.out.println(p);
		
		
	}
	
	/**
	 * 调用运行时类中的指定结构:方法
	 * 1.获取运行类中的指定的方法:getDeclaredMethod(String methodName,Class...params)
	 * 2.保证此属性是可访问的:method.setAccessable(true)
	 * 3.调用此方法:method.invoke(Object obj,Object...paramValues)
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * 
	 */
	@Test
	public void test2() throws Exception{
 		Class clazz = Person.class;
		Method m1 = clazz.getDeclaredMethod("info", String.class);
		m1.setAccessible(true);
		Person p = (Person)clazz.newInstance();
		//invoke() 此方法的返回值即为调用此方法的m1对象对应的info()方法的返回值。
		//如果invoke()方法对应的方法没有返回值,则返回null。
		Object returnValue = m1.invoke(p, "zhongguo");
		System.out.println(returnValue);
		
		//*********如下是静态方法的调用****************
		Method m2 = clazz.getDeclaredMethod("show");
		m2.setAccessible(true);
		Object objValue = m2.invoke(Person.class);//Person.class写不写都可以,因为show()已经在内存中。
		System.out.println(objValue);
		
	}
	//调用运行时类中的指定的结构:属性
	/**
	 * 1.获取运行类中的指定的属性:getDeclaredField(String fieldName)
	 * 2.保证此属性时可访问的:field.setAccessable(true)
	 * 3.修改此属性值:field.set(Object obj,Object fieldValue)
	 * 	 获取此属性值:field.get(Object obj)
	 */
	@Test
	public void test() throws Exception{
		Class clazz = Class.forName("reflectionTest.Person");
		//动态地创建运行时类
		Person p1 = (Person) clazz.newInstance();
		//获取指定的属性
		Field f1 = clazz.getDeclaredField("name");
		//设置指定属性的值
		f1.set(p1, "Tom");
		String name = (String) f1.get(p1);
		System.out.println(name);
		
		System.out.println("-----------------");
		Field f2 = clazz.getDeclaredField("id");
		f2.setAccessible(true);
		f2.set(p1, 1001);
		int id = (int)f2.getInt(p1);
		System.out.println(id);
		
		
	}
}

2.Lambda表达式:

lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

3.Lambda的使用:

3.1.格式:

举例:(o1,o2)->{…};
->:lambda操作符或箭头操作符
->左边:lambda参数列表
->右边:lambda要执行的操作,称为lambda体。
总结:
Lambda参数列表:一定可以省略数据类型,如果只有一个参数,还可以省略一对()
Lambda体:正常情况需要使用一对{}将lambda体包起来。如果lambda体只有一条执行语句,可以省略一对{}。如果此唯一的一条执行语句是return语句,还可以省略return。

3.2.函数式接口:

1.定义:接口中只声明了唯一的一个抽象方法。
2.我们可以在接口的声明上使用@FunctionalInterface,校验一个接口是否是函数式接口。
3.lambda表达式在java中充当了函数式接口的对象。
4.lambda表达式虽然形式简单,格式简单,但是使用起来有局限性:只使用于函数式接口。
5.java.util.function包下定义了java8的丰富的函数式接口。

3.3.方法引用的使用

在lambda表达式可以使用的基础上,进一步迭代,可以使用方法引用。
格式:类(或对象)::方法名
具体分类:
对象::实例方法名
适用场景:在重写的抽象方法中调用了另一个方法a,且函数式接口中的抽象方法的形参列表和返回值类型与另一个方法的形参列表和返回值类型相同,则可以使用方法引用。
类::静态方法名
类::实例方法名(有难度)

3.4.构造器引用

构造器::new

3.5.数组引用

数组声明::new(如:String[]::new)

package lambdaTest;


import java.util.Comparator;
import java.util.function.Consumer;

import org.junit.Test;
/**
 * lambda 表达式,仍然作为对象出现。
 * 只有一个抽象方法的接口才能用lambda表达式,称其为函数式接口。
 * 举例:(o1,o2)->{...};
 *		->:lambda操作符或箭头操作符
 *		->左边:lambda参数列表
 *		->右边:lambda要执行的操作,称为lambda体。
 *		
 */ 
public class LambdaTest {
	//语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略。
	@Test
	public void test8(){
		Runnable r2 = ()->System.out.println("jlksdjflkjsdl");
		r2.run();
	}
	//语法格式五:Lambda需要两个或两个以上的参数,多条执行语句,并且可以有返回值
	@Test
	public void test7(){ 
		 Comparator<Integer> com = new Comparator<Integer>(){

			@Override
			public int compare(Integer o1, Integer o2) {
				System.out.println(o1);
				System.out.println(o2);
				return Integer.compare(o1, o2);
			}
		 };
		 System.out.println(com.compare(21,43));
		 System.out.println("*************");
		 Comparator<Integer> com1 = (o1,o2) ->{
				System.out.println(o1);
				System.out.println(o2);
				return Integer.compare(o1, o2);
		 };
		 System.out.println(com1.compare(12,21));
	}
	//语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
	@Test
	public void test6(){
		Consumer<String> con1 = (String t)->{
			System.out.println(t);
			};
			con1.accept("我爱湖南!");
		System.out.println("************************");	
			Consumer<String> con2 = t->{
				System.out.println(t);
				};
				con2.accept("我爱湖南!");
	}
	
	//int[] arr = {1,2,3};
	//ArrayList<Integer> list = new ArrayList<>();
	//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
	@Test
	public void test5(){
		Consumer<String> con1 = (String t)->{
			System.out.println(t);
			};
			con1.accept("我爱湖南!");
		System.out.println("************************");	
			Consumer<String> con2 = (t)->{
				System.out.println(t);
				};
				con2.accept("我爱湖南!");
	}
	//语法格式二:Lambda需要一个参数,但是没有返回值。
	@Test
	public void test4(){
		Consumer<String> con= new Consumer<String>(){
			@Override
			public void accept(String t) {
				System.out.println(t);
			}
		};
		con.accept("我爱北京");
		System.out.println("***************");
		Consumer<String> con1 = (String t)->{
			System.out.println(t);
			};
			con1.accept("我爱湖南!");
		
		
	}
	//语法格式一:无参,无返回值
	@Test
	public void test3(){
		Runnable r1 = new Runnable(){
			@Override
			public void run() {
				System.out.println("冬天来了!");
			}
		};
		r1.run();
		System.out.println("******************");
		
		Runnable r2 = ()->{System.out.println("冬天来了!");}; 
		r2.run();
	}
	
	@Test
	public void test2(){
		Comparator<Integer> com = new Comparator<Integer>(){
			@Override
			public int compare(Integer o1, Integer o2) {
				return Integer.compare(o1, o2);
			}
		};
		int value = com.compare(12, 21);
		System.out.println(value);
		System.out.println("*********************");
		Comparator<Integer> com1 = (o1,o2)->Integer.compare(o1,o2);//labmda表达式的写法
//		Comparator<Integer> com1 = Integer::compare ;//方法引用。
		
		int value1 = com1.compare(12, 21);
		System.out.println(value1);
	}
	@Test
	public void test1(){
		Runnable r1 = new Runnable(){
			@Override
			public void run() {
				System.out.println("输出成功!");
			}
		};
		r1.run();
		System.out.println("**************************");
		Runnable r2 = ()->System.out.println("jlksdjflkjsdl");
		r2.run();
	}
}

package lambdaTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.junit.Test;

/**
 * 消费型接口:Consumer<T>	void accept(T t)
 * 供给型接口:Supplier<T> T get()
 * 函数型接口:Function<T,R> boolean test(T t)
 * 断定型接口:Predicate<T> boolean test(T t)
 */
public class LambdaTest2 {
	@Test
	public void testGetNames(){
		List<String> list = Arrays.asList("北京","南京","东京","西京","深圳","广州");
		List<String> nameList = getNames(list,t->t.contains("京"));
		nameList.forEach(System.out::println);
	}
	//4 断定型接口:Predicate<T> boolean test(T t)
	public List<String> getNames(List<String> list,Predicate<String> p){
		ArrayList<String> arrayList = new ArrayList<>();
		for(int i = 0 ;i<list.size();i++){
			if(p.test(list.get(i))){
				arrayList.add(list.get(i));
			}
		}
		return arrayList;
	}
	@Test
	public void test3(){
		String s1 = handleString("世界那么大,我想去看看。",s ->s.substring(2,5));
		System.out.println(s1);
	}
	//3 函数型接口:Function<T,R> R apply(T t)
	public String handleString(String str,Function<String,String> func){
		return func.apply(str);
	}
	@Test
	public void test2(){
		List<Double> list= getRandomNumber(10,()->Math.random()*100);
		list.forEach(System.out::println);
	}
	//2 供给型接口:Supplier<T> T get()
	public List<Double> getRandomNumber(int num,Supplier<Double> s){
		ArrayList<Double> list = new ArrayList<>();
		for(int i = 0; i< num ;i++){
			list.add(s.get());
		}
		return list;
	}
	
	@Test
	public void test1(){
		happyTime(500.00,m ->System.out.println("上午、下午"+m) );
		
	}
	//1 消费型接口:Consumer<T>	void accept(T t)
	public void happyTime(Double money,Consumer<Double> con){
		con.accept(money);
	}
}

4.Stream API

1.java提供的一套API,使用它可以实现对内存中的数组、集合进行过滤、映射、归约等操作。

2.注意:

Stream自己不会存储元素。
Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

3.Stream API使用上的三个步骤。

步骤一:实例化Stream。(4种)
方式一:调用集合的stream()
方式二:调用Arrays的stream()
方式三:调用Stream的静态方法:of(T … t)
步骤二:一系列的中间操作。
1.筛选与切片:
filter(Predicate p) -接收Lambda,从流中排除某些元素。
limit(n) -截断流,使其元素不超过给定数量。
skip(n) -跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回空流。与limit(n)互补
distinct() -筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
说明:1.中间操作可以以方法链的方式书写多个。
2.如果没有终止操作的话,中间操作是延迟执行的。
3.一旦Stream执行了终止操作,就不可以再被调用中间操作或终止操作。
2.映射:
map(Funciton f)
3.排序:
sorted() -自然排序。
sorted(Comparator com) -定制排序。
步骤三:一个终止操作。
1.匹配与查找。
allMatch(Predicate p) -检查是否匹配所有元素。
anyMatch(Predicate p) -检查是否至少匹配一个元素。
noneMatch(Predicate p) -检查是否没有匹配所有元素。
findFirst() -返回第一个元素。
findAny() -返回当前流中的任意元素。
count -返回流中元素的总个数。
max(Comparator c) -返回流中最大值
min(Comparator c) -返回流中最小值
forEach(Consumer c) -内部迭代
2.规约
reduce(T identity,BinaryOperator) -可以将流中元素反复结合起来,得到一个值,返回T。
reduce(BinaryOperator) -可以将流中元素反复结合起来,得到一个值,返回Optional。
3.收集
collect(Collector c) -将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import org.junit.Test;


public class StreamAPI {
	@Test
	public void test(){
		List<Employee> list = EmployeeData.getEmployees();
		//方式一:调用集合的stream()
		Stream<Employee> stream = list.stream();
		System.out.println(stream);
		//方式二:调用Arrays的stream()
		String[] str = new String[]{"AA","BB","CC"};
		Stream<String> stream1 = Arrays.stream(str);
		//方式三:调用Stream的静态方法:of(T ... t)
		Stream<Integer> stream2 = Stream.of(12,32,5,232,3);
	}
	
	@Test
	public void test1(){
		//迭代
		//public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
		Stream<Integer> stream = Stream.iterate(0,x->x+2);
		stream.limit(10).forEach(System.out::println);
		//生成
		//public static<T> Stream<T> generate(Supplier<T> s )
		Stream<Double> stream1 = Stream.generate(Math::random);
		stream1.limit(10).forEach(System.out::println);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值