.net做的网站,vi设计百科,中建集团的重要事件,微信小程序搭建平台有哪些函数式接口#xff1a;
在java中有且仅有一个抽象方法的接口称为函数式接口#xff0c;但是可以包含其它的默认的或静态的方法。
格式#xff1a;
修饰符 interface 接口名称 {public abstract 返回值类型 方法名称(可选参数);// 其他非抽象方法
}函数式接口#xff1a;…函数式接口
在java中有且仅有一个抽象方法的接口称为函数式接口但是可以包含其它的默认的或静态的方法。
格式
修饰符 interface 接口名称 {public abstract 返回值类型 方法名称(可选参数);// 其他非抽象方法
}函数式接口
// 1.函数式接口有且仅有一个抽象方法的接口当然接口中可以包含其他默认、静态、私有方法
// 2.为了确保接口是函数式接口可以写注解Functional Interface,它可以自动检测是否为函数式接口,当有多个抽象方法时就会报错。
FunctionalInterface
public interface MethodsInterFace {public abstract void sayHi();// void eat();
}接口实现类
public class MethodsInterFaceTest implements MethodsInterFace {Overridepublic void sayHi(){System.out.println(重写了抽象方法sayHi);};
}测试使用函数式接口函数式接口作为参数使用
public class Demo {// 1.函数式接口的使用一般可以作为方法的参数和返回值类型public static void testMethodsInterFace(MethodsInterFace mi){mi.sayHi();};public static void main(String[] args){// 创建一个接口实现类对象传给testMethodsInterFace方法使用MethodsInterFaceTest mit new MethodsInterFaceTest();testMethodsInterFace(mit);// 2.可以在方法调用时直接传递接口的匿名内部类testMethodsInterFace(new MethodsInterFace(){Overridepublic void sayHi(){System.out.println(匿名内部类重写了抽象方法sayHi);};});// 3.方法的参数是一个函数式接口时可以使用Lambda表达式Lambda表达式可以较匿名内部类节省内存但是原理是不太一样的Lambda有延迟testMethodsInterFace(()-{System.out.println(使用Lambda表达式重写了接口的抽象方法);});// 简化Lambda表达式testMethodsInterFace(()-System.out.println(使用简化Lambda表达式重写了接口的抽象方法));};
}函数式接口做饭返回值使用 如果一个方法的返回值类型是一个函数式表达式那么就可以直接返回一个Lambda表达式
import java.util.Arrays;
import java.util.Comparator;public class ComparatorDemo {// 1.实现一个方法该方法返回java.util.Comparator接口类型作为字符串排序时使用Comparator不仅仅可以用来做排序它是一个比较器比较灵活public static ComparatorString getSortResult(){//return new ComparatorString(){// Override// public int compare(String s1,String s2){// // 按照字符串长度降序排序// return s1.length() - s2.length();// };//};// 方法返回一个函数式接口可以使用Lambda简化return (s1,s2)- s1.length() - s2.length();};public static void main(String[] args){String[] arr {123,0000,0};System.out.println(1排序前的顺序 Arrays.toString(arr)); // 1排序前的顺序[123, 0000, 0]Arrays.sort(arr,getSortResult());System.out.println(2排序后的顺序 Arrays.toString(arr)); // 2排序后的顺序[0, 123, 0000]};
}常用函数式接口简介 JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景它们主要在java.util.function包中被提供。
Supplier接口 该接口包含一个无参数方法get,get返回一个前面泛型指定类型的数据 被称为生产型接口前面泛型指定什么数据类型就会返回什么类型数据。
import java.util.function.Supplier;public class SupplierDemo {// 1.定义一个方法方法参数传递一个SupplierT接口泛型执行String,get方法就会返回一个Stringpublic static String getString(SupplierString sp){return sp.get();};// 2.练习使用Supplier求数组元素中最大值public static int getMaxNum(SupplierInteger sp){return sp.get();};public static void main(String[] args){// 1-1:方法的参数是一个函数式接口可以使用lambda表达式String str getString(()- 一个字符串);System.out.println(str); // 一个字符串// 2-1:定义一个int类型的数组int[] arr {1,5,2,3};int maxValue getMaxNum(() - {int maxTemp arr[0];for (int i : arr) {if (maxTempi){maxTemp i;};}return maxTemp;});System.out.println(数组中最大值 maxValue); // 数组中最大值5};
}Consumer接口 Consumer接口刚好与Supplier接口相反Supplier接口接口用于生产一个数据而Consumer用于消费一个数据给一个指定类型的数据将这个数据使用掉。
import java.util.Locale;
import java.util.function.Consumer;public class ConsumerDemo {// 1.Consumer接口用于消费一个指定类型的数据泛型指定什么类型accept方法就消费什么类型的数据具体怎么消费需要自定义打印输出计算等// 定义一个方法方法的参数1传递一个字符串的姓名方法的参数2传递Consumer接口消费字符串的姓名public static void useName(String names, ConsumerString cn){cn.accept(names);};// 2.Consumer接口的默认方法andThen,andThen将多个Consumer组合起来再对数据进行消费// 定义一个方法方法传递自个字符串和两个Consumer接口接口泛型使用字符串public static void useAndThen(String names, ConsumerString cn1, ConsumerString cn2){// cn1.accept(names);// cn2.accept(names);// 使用andThen代替上面方法cn1.andThen(cn2).accept(names);};public static void main(String[] args){// 1.测试useNameuseName(kuhai123,cn - {System.out.println(cn); // kuhai123// 翻转字符串链式编程多次调用String reNames new StringBuffer(cn).reverse().toString();System.out.println(reNames); // 321iahuk});// 2.测试useAndThenuseAndThen(kuHai,cn1 - System.out.println(cn1.toUpperCase()), cn2 - System.out.println(cn2.toLowerCase()));};
}Predicate接口有时候需要对某种数据类型进行判断从而得到一个boolean值结果这时候可以使用Predicate接口。
import java.util.function.Predicate;public class PredicateDemo {// 1.Predicate接口用于判断数据是否满足某个条件返回布尔值其中包含一个方法test做判断// 定义一个方法参数传递一个字符串和一个Predicate接口接口的泛型使用String,使用接口中的方法test对字符串进行判断并返回判断结果public static boolean isString(String str, PredicateString ps){return ps.test(str);};// 2.Predicate接口中有一个and方法表示并且的意思// 定义一个方法接收两个Predicate接口和一个字符串接口泛型指定为字符串对字符串使用两个接口做判断并返回判断结果public static boolean isAllSatisfy(String s, PredicateString p1, PredicateString p2){// return p1.test(s) p2.test(s);return p1.and(p2).test(s);};// 3.Predicate接口中有一个or方法表示或者的意思// 定义一个方法接收两个Predicate接口和一个字符串接口泛型指定为字符串对字符串使用两个接口做判断并返回判断结果public static boolean isSomeSatisfy(String s, PredicateString p1, PredicateString p2){// return p1.test(s) || p2.test(s);return p1.or(p2).test(s);};// 4.Predicate接口中有一个negate方法表示取反的意思// 定义一个方法参数传递一个字符串和一个Predicate接口接口的泛型使用String,使用接口中的方法test对字符串进行判断并返回判断结果public static boolean isEmptyStr(String s, PredicateString p1){// return !p1.test(s);return p1.negate().test(s);};public static void main(String[] args){// 1.测试1判断字符串长度是否大于0String tempStr abcde;// 调用方法做校验boolean rs isString(tempStr,(s)-s.length() 0);System.out.println(rs); // true// 2.测试2: 判断字符串长度是否大于2并且小于5String str2 123456;boolean s2 isAllSatisfy(str2,(s)-s.length() 2,(s)-s.length() 5);System.out.println(s2); // false// 3.测试3: 判断字符串长度是否小于5或大于8String str3 1234;boolean s3 isSomeSatisfy(str3,(s)-s.length() 5,(s)-s.length() 8);System.out.println(s3); // true// 4.测试4: 判断字符串长是否为空字符串String str4 ;boolean s4 isEmptyStr(str4,(s)-s ! );System.out.println(s4); // true};
}Function接口用来根据一个类型的数据得到另一个类型的数据前者称为前置条件后者称为后置条件。
import java.util.function.Function;public class FunctionDemo {// 1.Function接口用来根据一个类型的数据得到另一个类型的数据其中主要方法apply:// 定义一个方法将字符串转换为Integer类型public static void toNumber(String s, FunctionString,Integer f){// Integer n f.apply(s);int n f.apply(s); // 自动拆箱System.out.println(n); // 123};// 2.andThen方法用来进行组和操作// 定义一个方法将字符串转换为数字类型后加10后再转换为字符串public static void addTen(String str, FunctionString,Integer f1, FunctionInteger,String f2){String st f1.andThen(f2).apply(str);System.out.println(st); // 20};public static void main(String[] args){// 1.测试:将字符串转换为数字类型String str 123;toNumber(str,(String strs)-Integer.parseInt(strs));// 2.测试将字符串加10后再返回String s2 10;addTen(s2, st - Integer.parseInt(st) 10, n - n );};
}Stream流
Strema流和io流是完全不一样的两种概念。Stream流用于对数组和集合做简化操作。
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;// Stream流式模型当对一个数组或集合的多个元素进行操作时可以先拼一个模型filter过滤 - 映射map - 跳过skip - 统计count
public class StreamDemo {// 1.对集合中的元素进行过滤处理常用的方法就是遍历处理有的时候可能需要多个条件此时有可能需要遍历多次这样就会有点麻烦此时可以使用Stream简化处理public static void main(String[] args){ListString list new ArrayList();list.add(张无忌);list.add(张一);list.add(张二二);list.add(李四);list.add(王五);// 2.集合中有一个方法stream,可以将集合转换为Stream流Stream流有个filter方法找到满足提交的数据可以接收一个Lambda表达式支持链式调用list.stream().filter(s - s.startsWith(张)).filter(s - s.length() 2).forEach(s - System.out.println(s)); // 张一// 3.获取流的方式1.所有的Collection集合都可以通过stream默认方法获取 2.Stream接口的静态方法of获取,of方法中接收一个数组StreamInteger ist Stream.of(1,2,3,4);// 4.流模型的操作很丰富常用api可分两类1.延迟方法返回值类型仍然是Stream接口自身类型的api支持链式调用2.终结方法返回值类型不再是Stream接口类型的api,调用终结方法后不再支持链式调用终结方法常用的有count/forEach// 5.Stream流中forEach方法该方法接收一个Consumer接口函数会将每一个流元素交给该函数进行处理Consumer接口是一个消费型的函数式接口可以传递Lambda表达式进行消费数据简单记忆forEach遍历流中的每一个元素对每个元素进行处理调用了forEach方法后就不能在调用Stream的其他方法了StreamString slist Stream.of(赵丽颖,迪丽热巴,霍元甲);slist.forEach(item - System.out.println(item));// 6.Stream流中filter方法filter方法将一个流转换为另一个子集流该方法接收一个Predicate函数式接口做为筛选条件可对元素进行筛选StreamInteger ilist Stream.of(1,2,3,4);StreamInteger list2 ilist.filter(item - item 3);list2.forEach(item - System.out.println(item)); // 4// 7.Stream流的特点Stream流属于管道流只能被消费一次使用一次就不能被使用了第一个Stream流调用完毕后就会流到下一个Stream上而此时第一个Stream流已经使用完毕了就会被关闭再使用就会报错// list2.forEach(item - System.out.println(item)); // 抛出了异常// 8.Stream流中map方法map将一个流中的元素映射到另一个流中该方法接收一个Function接口使用Function接口可将某个类型转换为另一个类型做依依映射StreamInteger isst Stream.of(1,2,3,4);StreamString isst2 isst.map(item - item.toString());isst2.forEach(item - System.out.println(item));// 9.Stream流中提供了count方法count用于统计流中元素的个数类似Collection当中的size返回值类型为long类型该方法是一个终结方法StreamInteger listl Stream.of(1,2,3,4);System.out.println(listl.count()); // 4// listl.forEach(item - System.out.println(item)); // 使用过了再使用会抛异常// 10.Stream流中的limit方法limit方法用于截取前n个元素n类型是long,返回的是新的流支持链式调用String[] arrs {元素1,元素2,元素3,元素4,元素5,};StreamString streamlist Stream.of(arrs);StreamString streamlist2 streamlist.limit(2);streamlist2.forEach(item - System.out.println(item)); // 元素1 元素2System.out.println(-------------------);// 11.Stream流中的skip方法skip方法用于跳过前n个元素返回剩下的元素n类型是long,返回的是新的流支持链式调用当传入的参数大于元素的个数时会得到一个长度为0的空流String[] arrs2 {元素1,元素2,元素3,元素4,元素5,};StreamString ster Stream.of(arrs2);StreamString ster2 ster.skip(2);ster2.forEach(item - System.out.println(item)); // 元素3 元素4 元素5// 12.Stream流中的concat静态方法concat方法用于将两个流合并成一个流StreamString l1 Stream.of(1,2);StreamString l2 Stream.of(3,4);StreamString l3 Stream.concat(l1,l2);l3.forEach(item - System.out.println(item)); // 1 2 3 4};
}方法引用
方法引用实际是对Lambda的优化如
Printable接口
// 1.定义一个打印的函数式接口
FunctionalInterface
public interface Printable {// 打印字符串的抽象方法void print(String s);
}
public class PrintDemo {// 2.定义一个方法传递Printable接口对字符串进行打印public static void printString(Printable p){p.print(打印内容);};public static void main(String[] args){// 3.调用printString方法printString(s - System.out.println(s)); // 打印内容// 3-1方法引入调用方法Lambda表达式的目的打印参数传递的字符串把参数s传递给了System.out对象调用out对象中的方法println对字符串输出注意1.System.out对象已经存在 2.println方法也已经存在所以可以使用方法引入优化Lambda表达式可以使用System.out直接引入方法println,如printString(System.out::println); // 打印内容// ::被称为引用运算符而它所在的表达式被称为方法引用如果Lambda要表达的函数方案已经存在于某个方法的实现中那么可以使用双冒号来引用该方法作为Lambda的代替};
}
通过对象名引用成员方法
定义一个包含成员方法的类
public class MethodsRerObject {// 1.定义一个成员方法传递字符串把字符串按照大写输出public void printUpperCaseString(String str){System.out.println(str.toUpperCase());};
}
通过对象名引用方法测试
public class MethodsReferenceDemo {// 2.通过对象名引用成员方法使用前提对象名是已经存在的成员方法也是已经存在的就可以是使用对象名来引用成员方法// 定义一个方法方法的参数传递Printable接口public static void printString(Printable p){p.print(asda);};public static void main(String[] args){printString((s) - {// 3.创建一个MethodsRerObject对象MethodsRerObject obj new MethodsRerObject();// 4.调用对象中成员方法按照大写输出obj.printUpperCaseString(s); // ASDA});// 方法引用优化MethodsRerObject obj new MethodsRerObject();printString(obj::printUpperCaseString); // ASDA};
}
通过类名称引用静态方法
FunctionalInterface
public interface Calcable {// 1.定义一个抽象方法传递一个整数对整数进行绝对值计算int calsAbs(int n);
}
public class StaticClassMethodsReferenceDemo {// 2.通过类名称引用静态成员方法前提类已存在静态方法已经存在// 定义一个方法方法的参数传递要计算绝对值的整数和Calcable接口public static int methodsabs(int num, Calcable c){return c.calsAbs(num);};public static void main(String[] args){// 3.调用methodsabs方法int rs methodsabs(-5,cn - Math.abs(cn));System.out.println(rs); // 5// 优化通过类引用静态方法int rs2 methodsabs(-5,Math::abs);System.out.println(rs2); // 5};
}
通过super引用成员方法: 如果在继承关系中当Lambda中需要出现super调用时也可以使用方法引用进行代替如
FunctionalInterface
public interface Geetable {void greet();
}// 定义一个父类
public class Human {// 定义一个方法public void sayHai(){System.out.println(hi,我是human);};
}// 定义子类继承Human:
public class Man extends Human {// 子类重写sayHai方法Overridepublic void sayHai(){System.out.println(hi,我是Man);};// 定义一个方法参数是Greetable接口public void method(Geetable g){g.greet();};// 定义一个show方法在show方法中调用method接口public void show(){// method(() - {// // 创建父类对象// Human hm new Human();// // 调用父类的syaHi方法// hm.sayHai(); // hi,我是human// });// 优化因为有子父类关系所以存在一个关键字super,代表父类所以我们可以直接使用super调用父类的成员方法// method(() - super.sayHai());method(super::sayHai);};public static void main(String[] args){// 创建Man对象并调用show方法new Man().show();};
}通过this引用成员方法 this代表当前对象如果需要引用的方法
// 定义一个富有的函数接口
public interface Richable {// 购买的方法void buy();
}
public class Husband {// 定义一个买房子的方法public void buyHouse(){System.out.println(买房);};// 定义一个买车的方法参数传递Richable接口public void buyCar(Richable r){r.buy();// System.out.println(买车);};// 定义一个非常高兴的方法public void soHappy(){// 调用买车的方法// buyCar(() - {// this.buyHouse();// });// 优化buyCar(this::buyHouse);};public static void main(String[] args) {new Husband().soHappy();}
}
类的构造器引用 由于构造器的名称和类名称完全一样并不固定所以构造器引用使用类名称::new 的格式表示如
// 定义一个类
public class Person {private String name;public String getName() {return name;}public Person() {}public Person(String name) {this.name name;}public void setName(String name) {this.name name;}
}
// 定义一创建Person对象的函数式接口
FunctionalInterface
public interface PersonBuilder {// 定义一个方法根据传递的姓名创建Person对象Person builderPerson(String name);
}
// 定义一个测试demo
public class Demo {// 定义一个方法传递姓名和PersonBuilder接口方法中通过姓名创建对象public static void printName(String name,PersonBuilder p){Person ps p.builderPerson(name);System.out.println(ps);};public static void main(String[] args) {// 调用printName方法// printName(苦海123, (String name) - {// return new Person(name);// });// 优化使用方法引用printName(苦海123, Person::new);}
}数组构造器引用
数组也是Object的子类对象所以同样具有构造器只是语法对应到Lambda的使用场景中时需要一个函数式接口
// 定义一个创建数组的函数式接口
FunctionalInterface
public interface ArrayBuilder {// 定义创建int类型的数组的方法参数传递数组的长度返回创建好int类型的数组int[] builderArray(int length);
}
public class ArrayBuildDemo {// 定义一个方法方法的参数传递创建数组长度和ArrayBuilder接口方法内部根据传递的长度使用ArrayBuild中的方法创建数组并返回public static int[] createArray(int length,ArrayBuilder ab){return ab.builderArray(length);};public static void main(String[] args) {// 调用createArray方法// int[] arr1 createArray(5,(len) - {// return new int[len];// });// 优化使用数组构造器引用int[] arr1 createArray(5,int[]::new);System.out.println(arr1.length);}
}
junit单元测试
测试大概可以分为两类
黑盒测试不需要写代码给输入值看程序最终能否输出想要的结果。
白盒测试需要写代码关注程序的具体执行流程。
junit使用步骤1.定义一个测试类测试用例类名推荐XXXTest,放在XXX.XXX.test包2.定义测试方法可独立运行方法名推荐testXXX 3.给方法加Test注解
import org.junit.After;
import org.junit.Before;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;public class CalculateTest {// 1.加测试注解Testpublic void testAddnum(){// 2.创建需要测试累的对象Calculate cs new Calculate();// 3.调用对象的方法int result cs.addNum(5,3);System.out.println(result);// 点击编辑器左侧箭头即可执行此方法无需写main函数点哪个箭头对应的函数会执行如果方法有异常抛出那么控制台会有爆红警告报红表示测试失败// 4.断言上面爆红只是语法上的错误真要测试一个结果是否正确那么需要借助Assert下的相关方法对输出的结果和想要的结果进行比较Assert.assertEquals(8,result); // 当输出的结果和想要的结果不一样时这里也会报红};// 2.初始化方法用于申请资源等加Befoure注解,执行于test前Beforepublic void init(){System.out.println(Before注解方法执行);};// 3.释放资源方法所有测试方法都执行完后会自动执行的方法在前面加After注解即可执行于test后Afterpublic void destory(){System.out.println(After注解方法执行);};
}反射
将类的各个组成部分封装为其他对象这就是反射机制反射的好处可以在程序运行过程中操作这些对象可以解耦降低程序的耦合性提高程序的可扩展性。
Person类文件
public class Person {private String name;private int age;public String grad;public Person(String name, int age, String grad) {this.name name;this.age age;this.grad grad;}public Person() {}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 getGrad() {return grad;}public void setGrad(String grad) {this.grad grad;}Overridepublic String toString() {return Person{ name name \ , age age , grad grad \ };}public void eat(){System.out.println(吃...);};public void eat(String foot){System.out.println(吃... foot);};
}pro.properties配置文件
# 1.配置文件
# 定义一个类名这里的类是项目中存在的Class文件
classNamePerson
# 定义一个方法名这里的方法也是Class类文件中对应出现的方法
methodNameeat测试反射技术
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class ReflectDemo1 {// 获取class对象的方式1.Class.forName(全类名)将字节码文件加载进内存返回class对象 2.类名.class,通过类名的属性class获取 3.对象.getClass(),通过Object类中定义的方法getClass获取public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, IOException {// 1.Class.forName(全类名)将字节码文件加载进内存返回class对象多用于配置文件Class cls1 Class.forName(Person);System.out.println(cls1); // class Person// 2.类名.class,通过类名的属性class获取多用于参数传递Class cls2 Person.class;System.out.println(cls2); // class Person// 3.对象.getClass(),通过Object类中定义的方法getClass获取多用于对象获取字节码的方式Person p1 new Person();Class cls3 p1.getClass();System.out.println(cls3); // class PersonSystem.out.println(cls1 cls2 cls2 cls3); // true,同一个.class字节码文件在一次程序运行过程中只被加载进内存一次。System.out.println(-----------------------);// class对象功能1.获取所有的成员变量 2.获取所有的构造方法 3.获取所有成员方法 4.获取类名// 获取Person的class对象Class classObj Class.forName(Person);// 1-1.获取所有被public修饰的成员变量: getFields用于获取public修饰的成员变量Field[] flist classObj.getFields();for (Field item : flist) {System.out.println(item); // 这里获取到的结果public java.lang.String Person.grad}// 1-2.获取指定被public修饰的成员变量: getField用于获取指定名称的被public修饰的成员变量Field fie classObj.getField(grad);System.out.println(fie); // 这里获取到的结果public java.lang.String Person.grad// 1-3.获取成员变量的作用可以获取和设置成员变量对应的值get用于获取成员变量的值get方法接收一个对象实例 set用于设置成员对象的值,接收两个变量一是对象实例二是成员变量对应要设置的值Person p2 new Person();fie.set(p2,10班);Object p fie.get(p2);System.out.println(p); // null,初识化为null值前面加了set,所以加set后的值为10班// 1.4获取所有的成员变量getDeclaredFields()获取所有的成员变量不被修饰符限制Field[] flists classObj.getDeclaredFields();for (Field item : flists) {System.out.println(item); // 这里获取到的结果private java.lang.String Person.name 、 private int Person.age 、 public java.lang.String Person.grad}// 1-5.获取指定的成员变量getDeclaredField()获取指定名称的成员变量不被修饰符锁限制即使是私有的也是可以被操作的但是会抛异常只要使用setAccessible忽略异常就可以正常运行Field fits classObj.getDeclaredField(name);fits.setAccessible(true); // 获取访问权限修饰符的安全检查true为忽略false为不忽略Person p3 new Person(苦海,18,11班);fits.set(p3,kuhai123);System.out.println(fits.get(p3)); // 原本是苦海但是前面重新设置了kuhai123所以这里打印kuhai123// 2-1.获取对象构造器getConstructor用来获取构造器函数,根据可变参数获取对应的构造器Constructor cn classObj.getConstructor(String.class, int.class,String.class);System.out.println(cn);// 构造方法的作用用来创建对象Object p4 cn.newInstance(苦海123,16,6班);System.out.println(p4.toString()); // Person{name苦海123, age16, grad6班}// 3-1.获取方法getMethod用来获取指定名称的方法Method eats classObj.getMethod(eat,String.class); // 第一个参数为方法名后面可接收对应类型重载方法// 获取方法的作用使用invoke调用方法Person p5 new Person();eats.invoke(p5,苹果); // 吃...被打印了如果获取方法时传递了对应参数的重载方法则第二个参数开始为重载方法所需的参数传递了参数的值吃...苹果// 3-2.获取所有public修饰的方法Method[] methods classObj.getMethods();for (Method item : methods) {System.out.println(item); // 这里获取到的结果这里除了对象自身的方法外还有继承于Object的一些方法getName()可获取方法名称System.out.println(item.getName());}// 方法获取到也是可以执行的通过invoke(接收多个对象)System.out.println(------------******--------------);// 案例实现一个可以定义任意类和执行该类的任意方法的框架// 实现步骤1.将要创建的对象的全类名和所需要执行的方法定义在配置文件中 2.在程序中加载读取配置文件 3.使用反射技术来加载类文件进内存 4.执行方法// 1.在项目包文件夹下定义一个pro.properties配置文件文件名可以自定义但是后缀是.properties结尾定义好配置文件后可以通过以下方法加载文件// 1-1.创建Properties对象Properties pro new Properties();// 1-2.调用pro的load方法加载配置文件到内存并将其转换为一个双链集合// 1-2-1.通过getClassLoader()获取类字节码文件的加载器ClassLoader classLoader ReflectDemo1.class.getClassLoader();// 1-2-2.可以借助ClassLoader里面的getResourceAsStream方法获取资源对应的字节流这里和使用io流是一个意思但是io获取就比较麻烦了InputStream isStrem classLoader.getResourceAsStream(pro.properties);// 1-2-3.通过load方法加载字节流pro.load(isStrem);// 2.获取配置文件中定义的数据String className pro.getProperty(className);String methodName pro.getProperty(methodName);// 3.加载该类进内存,返回一个Class对象Class cls Class.forName(className);// 4.创建对象newInstance方法已被启用Object objs cls.newInstance();// 5.获取方法对象Method methObj cls.getMethod(methodName);// 6.执行方法methObj.invoke(objs);// 以上创建对象并执行对象方法的优势可以不用改代码只是修改配置文件就可以让一个新的类创建对象并调用其中的方法不用再去测试代码是否有bug,项目庞大时可扩展性强}
}注解
注解也叫元数据它可以声明在包、类、字段、方法、局部变量、方法参数等的前面用来对这些元素进行说明注释。通过代码里标识的元数据让编译器能够实现基本的编译检查如Override;通过代码里的注解生成doc文档;对代码进行分析等。说白了就是在写代码的时候加上特殊的注释可以通过java相关命令自动生成开发文档以及代码的自校验等
生成开发文档通过命令javadoc 类文件名 可以生成html说明文档如果报错则修改编码为GBK即可
JDK预定义的一些注解
Override检测被该注释标注的方法是否是继承自父类的。
Deprecated:该注解表示已过时表示某个内容已经过时但是可以使用。
SuppressWarnings:压制警告。
自定义注解
自定义注解分两部分1.元注解就是写给自己的注释可以不写 2.写个程序的注解真正生效的注解其格式public interface 注解名称 {}
注解本质public interface MyAnno extends java.lang.annotation.Annotation {}可以看出实际就是一个接口此接口中可以定义属性接口中的抽象方法必须有返回值返回值类型基本类型、枚举、注解
元注解定义的一些注释
Target:描述注解所作用的位置
Retention:描述注解被保留的阶段
Documented:描述注解是否被抽取到api文档中
Inherited:注解是否被子类继承
定义一个注解
// 1.定义一个自定义注解MyAnno(通过反编译可以查询自定义注解的源码反编译步骤1.先javac编译注解java文件 2.javap编译注解class字节码文件)通过反编译得到的结果public interface MyAnno extends java.lang.annotation.Annotation {}注解本质就是一个接口
// 元注解定义import java.lang.annotation.*;
Target(value{ElementType.METHOD,ElementType.TYPE}) // ElementType的值有TYPE表示MyAnno注解只能注解在类上、METHOD可以作用域方法上、FIELD可以作用于成员变量上,多个类型可以同时添加只需要用逗号隔开即可。
Retention(RetentionPolicy.RUNTIME) // 这里也是一个枚举但是一般自己定义的注解一般使用RUNTIME即可表示当前秒数的注解会保留到class字节码文件中并被jvm读取到、 如果设置为CLASS则表示注释会保留到class字节码文件中但不会被jvm读取到
Documented // 加此注解表示当前的注解会被加载到api文档中
Inherited // 加此注解表示子类继承该注解
public interface MyAnno {public String show(); // 这里的抽象方法也可以叫做属性方法的返回值是有要求的基本类型、枚举、注解int show1() default 0; // 使用default可以给默认值如果不给默认值在使用注解时就要给值
}在Person类中使用自定义类
public class Person {public String name;// 2.使用自己定义的注解后面加括号可以传值给注解多个值用逗号隔开,如果不想赋值那么定义的时候就要给默认值MyAnno(show hello, show1 8) // 如果注解只有一个抽象方法并且抽象方法名称为value时这里使用注解时可以直接传值如MyAnno(8)public void sayHi(){System.out.println(hi...);};
}使用注解实现利用反射自动创建对象并调用对象的方法:
定义一个注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义一个描述执行的类名和方法名的注解demo
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
public interface Pro {String className();String methodName();
}定义一个类
public class DemoClass {public void show(){System.out.println(show...);};
}实现过程
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;// 用注解代实现框架创建对象案例
Pro(classNameDemoClass,methodNameshow)
public class ReflectDemo {public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InstantiationException {// 1.解析注释// 1-1.获取该类字节码文件对象ClassReflectDemo refcls ReflectDemo.class;// 1-2.获取上边的注释对象Pro ans refcls.getAnnotation(Pro.class); // 在内存中生成了该注释接口的子类实现类对象// 1-3.调用注解对象中定义的方法获取返回值String className ans.className();String methodName ans.methodName();// 2.加载该类进内存,返回一个Class对象Class cls Class.forName(className);// 3.创建对象newInstance方法已被启用Object objs cls.newInstance();// 4.获取方法对象Method methObj cls.getMethod(methodName);// 5.执行方法methObj.invoke(objs);};
}提示本文图片等素材来源于网络若有侵权请发邮件至邮箱810665436qq.com联系笔者删除。 笔者苦海