String 返回某索引处的字符 判断是否是空字符串 将所有字符转换为小写 将所有字符转换为大写 返回副本,忽略前导空白和尾部空白 比较字符串的内容是否相同 1 boolean equals (Object obj) ;
比较字符串的内容是否相同(忽略大小写) 1 boolean equalsIgnoreCase (String anotherString) ;
比较两个字符串的大小 1 int compareTo (String anotherString) ;
从原字符串中截取一个新字符串 1 String substring (int beginIndex, int endIndex) ;
判断字符串是否以指定的后缀结束 1 boolean endsWith (String suffix) ;
判断字符串(从指定索引开始)是否以指定的前缀开始 1 boolean startsWith (String prefix, int toffset) ;
判断字符串中是否包含指定的char值序列 1 boolean contains (CharSequence s) ;
返回指定字符串在此字符串中(从指定索引开始)第一次出现处的索引 1 int indexOf (String str, int fromIndex) ;
返回指定字符串在此字符串中(从指定索引开始)最右边第一次出现的索引 1 int lastIndexOf (String str, int fromIndex) ;
返回一个新字符串,其中部分被替换 1 2 String replace (char oldChar, char newChar) ; String replace (CharSequence target, CharSequence replacement) ;
String —->基本数据类型、包装类 基本数据类型、包装类 —->String String与char[]之间的转换 1 2 char [] ch = str.toCharArray();String str = new String (ch);
String与byte[]之间的转换 1 2 3 4 5 6 7 byte [] bytes = str.getBytes();byte [] gbks = str.getBytes("gbk" );String str2 = new String (bytes);String str3 = new String (gbks, "gbk" );
StringBuffer和StringBuilder String/StringBuffer/StringBuilder 三者的异同 源码分析: 1 2 3 4 5 6 7 8 String str = new String ();String str1 = new String ("abc" );StringBuffer sb1 = new StringBuffer ();StringBuffer sb2 = new StringBuffer ("abc" );
常用方法(两者类似,以StringBuffer为例) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 StringBuffer s1 = new StringBuffer ("abasgsc" );s1.append(1 ); s1.delete(2 , 4 ); s1.replace(1 , 3 , "sdf" ); s1.insert(2 , "sojfo" ); s1.reverse();
jdk 8之前的日期时间的API System类中currentTimeMillis(); java.util.Date类 1 2 3 4 5 Date date1 = new Date ();Date date1 = new Date (long date);date1.getTime(); date1.toString();
java.sql.Date类 1 2 java.sql.Date date1 = new java .sql.Date(long date); java.sql.Date date1 = new java .sql.Date(date.getTime());
SimpleDateFormat对日期Date类的格式化和解析 1 2 3 4 5 6 7 8 9 SimpleDateFormat sdf = new SimpleDateFormat ();Date date = new Date ();String format = sdf.format(date);String str = new String ("22-5-28 上午9:19" );String parse = sdf.parse(str);
java.util.Calendar类 1 2 3 4 5 6 7 8 9 Calendar calendar = Calendar.getInstance();
jdk 8中日期时间的API LocalDate/LocalTime/LocalDateTime 1 2 3 4 5 6 7 LocalDateTime localdatetime = LocalDateTime.now();
Instant类 1 2 3 4 5 6 7 8 9 10 11 12 13 Instant instant = Instant.now();System.out.println(instant); OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8 ));System.out.println(offsetDateTime); long time = instant.toEpochMilli();Instant instant = Instant.ofEpochMilli(1653706858013L );
格式化或解析日期、时间,类似于SimpleDateFormat 实例化的三种方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;LocalDateTime localDateTime = LocalDateTime.now();String str1 = formatter.format(localDateTime);System.out.println(localDateTime); System.out.println(str1); TemporalAccessor parse = formatter.parse(str1);System.out.println(parse); LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);String str1 = formatter1.format(localDateTime);System.out.println(str1); DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss" );String str2 = formatter2.format(localDateTime);System.out.println(str2);
Comparable和Comparator 自然排序:Comparable接口的使用 定制排序:Comparator接口的使用 1 2 3 4 5 6 Arrays.sort(arr, new Comparator (){ public int compare (Object o1, Object o2) { return 0 ; } });
System类 System类内部包含in,out,err三个成员变量 该类的构造器是private的,所以无法创建对象和实例化 native long currentTimeMillis() void exit(int status) 退出程序。status等于0代表正常退出,非0代表异常退出 void gc() String getProperty(String key) Math类 BigInteger和BigDecimal BigInteger可以表示不可变的任意精度的整数 BigDecimal支持不可变的、任意精度的有符号十进制定点数 枚举类 jdk5.0之前,自定义枚举类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private final String seasonName; private final String seasonDesc; private Season (String seasonName, String seasonDesc) { this .seasonName = seasonName; this .seasonDesc = seasonDesc; } public static final Season SPRING = new Season ("春天" , "春暖花开" ); public static final Season SUMMER = new Season ("夏天" , "夏日炎炎" ); public static final Season AUTUMN = new Season ("秋天" , "秋高气爽" ); public static final Season WINTER = new Season ("冬天" , "冰天雪地" ); public String getSeasonName () { return seasonName; } public String getSeasonDesc () { return seasonDesc; } @Override public String toString () { return "Season{" + "seasonName='" + seasonName + '\'' + ", seasonDesc='" + seasonDesc + '\'' + '}' ; }
jdk5.0,使用enum关键字定义枚举类 使用enum关键字定义的枚举类默认继承java.lang.Enum类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 enum Season1 { SPRING("春天" , "春暖花开" ), SUMMER("夏天" , "夏日炎炎" ), AUTUMN("秋天" , "秋高气爽" ), WINTER("冬天" , "冰天雪地" ); private final String seasonName; private final String seasonDesc; private Season1 (String seasonName, String seasonDesc) { this .seasonName = seasonName; this .seasonDesc = seasonDesc; } public String getSeasonName () { return seasonName; } public String getSeasonDesc () { return seasonDesc; } }
Annotation 生成文档相关的注解 1 2 3 4 5 @author @version @see @param ...
JDK内置的三个基本注解 1 2 3 @Override :限定重写父类方法,该注解只能用于方法@Deprecated :用于表示所修饰的元素已过时@SuppressWarnings :抑制编译器警报
跟踪代码依赖性,实现替代配置文件的功能 自定义注解 JDK中的四个元注解 meta-annotation:对现有的注解进行注解的注解 (元数据:对现有数据进行修饰的数据) @Retention @Target 指定被修饰的Annotation能用于修饰哪些程序元素 @Documented(出现的频率较低) 表示所修饰的注解在被javadoc解析时,保留下来 @Inherited(出现的频率较低) JDK 8中注解的新特性 集合 Collection接口 Collection接口的常用方法 注意:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals();
add(Object obj); size(); addAll(); clear(); isEmpty(); contains(Object obj):判断集合中是否包含obj; containsAll(Collection coll):判断形参coll中的所有元素是否都存在与当前集合中; remove(Object obj):要求obj所在类要重写equals(); removeAll(Collection coll):从当前集合中移除coll中所有的元素; retainAll(Collection coll):求交集; equals(Object obj); hashCode():返回当前对象的哈希值; toArray():集合转换为数组; Arrays.asList():数组转换为集合; iterator():返回Iterator接口的实例,用于遍历集合元素; 使用内部方法:hasNext()/next()/remove() foreach():for(集合元素类型 局部变量 :集合对象) Collection子接口:List接口 ArrayList:线程不安全的,效率高;底层用数组实现 LinkedList:对于频繁的插入、删除操作,底层使用双向链表存储 Vector:线程安全的,效率低;底层用数组实现(已经被淘汰了)List接口中的常用方法 void add(int index, Object ele):在index位置插入ele元素 boolean addAll(int index, Collection eles):从Index位置开始将eles中所有元素添加进来 Object get(int index):获取指定位置index位置的元素 int indexOf(Object obj):返回obj在当前集合中首次出现的位置,如果不存在返回-1 int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 Object remove(int index):移除指定index位置的元素,并返回此元素 Object set(int index, Object ele):设置指定index位置的元素为ele List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开子集合List的遍历方法 增强for循环 Iterator迭代器方式 普通循环 Collection子接口:Set接口 Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法 要求:向Set中添加的数据,其所在的类一定要重写hashCode()和equals() 要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相同的散列码 无序性:不等于随机性。存储的数据在底层数组中并非按照索引的顺序进行添加,而是根据数据的哈希值决定的。 不可重复性:保证添加的元素按照equals()判断时,不能返回true,即:相同的元素只能添加一个 向HashSet中添加元素的过程:向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素: 如果此位置上没有其他元素,则元素a添加成功。——>情况1 如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a和元素b的哈希值,如果hash值不相同,则元素a添加成功。——>情况2 如果hash值相同,进而需要调用元素a所在类的equals()方法,返回true,元素a添加失败。 返回false,则元素a添加成功。——>情况3 对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以链表的方式存储。 jdk 7:元素a放入数组中,指向原来的元素 jdk 8:原来的元素在数组中,指向元素a 七上八下
HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值 LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。对于频繁的遍历操作,LinkedHashSet效率高于HashSet TreeSet:1. 可以按照添加对象的指定属性,进行排序; 2.向TreeSet中添加的数据,要求是相同类的对象; 3.两种排序方式:自然排序和定制排序 4.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals() 5.定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals() Map接口 Map接口的多个实现类 HashMap:作为Map的主要实现类;线程不安全的,效率高;可以存储null的key和valueLinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历;对于频繁的遍历操作,此类的执行效率要高于HashMap TreeMap:保证按照添加的key-value对进行排序,实现排序遍历;考虑key的自然排序和定制排序;底层使用红黑树 Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和valueProperties:常用来处理配置文件;key和value都是String类型 Map结构的理解 Map中的key:无序的,不可重复的,使用Set存储所有的key —->key所在类要重写equals()和hashCode()(以HashMap为例) Map中的value:无序的,可重复的,使用Collection存储所有的value —-> 一个键值对:key-value构成了一个Entry对象 Map中的Entry:无序的,不可重复的,使用Set存储所有的Entry HashMap的底层实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 以jdk7为例 HashMap map = new HashMap(): 在实例化以后,底层创建了长度是16的一维数组Entry[] table ...已经执行过多次put... map.put(key1, value1): 首先调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置 如果此位置上的数据为空,此时的key1-value1添加成功 ----情况1 如果此位置上的数据不为空,说明此位置上存在一个或多个数据(以链表的形式存在),比较key1和已经存在的一个或多个数据的哈希值: 如果key1的哈希值与已经存在数据的哈希值都不相同,此时key1-value1添加成功。 ----情况2 如果key1的哈希值与已经存在的某一个数据的哈希值相同,继续比较:调用key1所在类的equals()方法比较: 如果equals()返回false:此时key1-value1添加成功 ----情况3 如果equals()返回true:使用value1替换相同key的value值 补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储 在不断的添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来 jdk8 相较于jdk7在底层实现方面的不同 1.new HashMap():底层没有创建长度为16的数组 2.jdk 8 底层的数组是:Node[],而非Entry[] 3.首次调用put()方法时,底层创建长度为16的Node[]数组 4.Jdk7底层结构只有数组+链表;jdk8中底层结构:数组+链表+红黑树 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所有数据改为使用红黑树存储
Map中定义的方法 添加、删除、修改操作:
Object put(Object key, Object value):将指定key-value添加(修改)到当前map对象中 void putAll(Map m):将m中所有key-value对存放到当前map中 Object remove(Object key):移除指定key的key-value对,并返回value void claer(): 清空当前map中的所有数据 元素查询:
Object get(Object key):获取指定key对应的value boolean containsKey(Object key):是否包含指定的key boolean containsValue(Object value):是否包含指定的value int size():返回map中key-value对的个数 boolean is Empty():判断当前map是否为空 boolean equals(Object obj):判断当前map和参数对象obj是否相等 元视图操作的方法:
Collections工具类 排序:
reverse(List):反转List中元素的顺序 shuffle(List):对List集合元素进行随机排序 sort(List, Comparator):排序 swap(List, int, int):将指定list集合中的i处元素和j处元素进行交换 查找、替换:
Object max(Collection):根据元素的自然顺序,返回给定集合中最大元素 Object max(Collection, Comparator):略 Object min.. int frequency(Collection, Object):返回指定集合中指定元素的出现次数 void copy(List dest, List src):将src中的内容复制到dest中 boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值 泛型 自定义泛型结构:泛型类、泛型接口;泛型方法 泛型不同的引用不能相互赋值 异常类不能声明为泛型类 静态方法中不能使用类的泛型 泛型方法 泛型方法所属的类是不是泛型类都没有关系 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的,并非是在实例化类时确定的通配符的使用 IO流 File类 常用构造器 常用方法 获取 public String getAbsolutePath():获取绝对路径 public String getPath():获取路径 public String getName():获取名称 public String getParent():获取上层文件目录路径 public long length():获取文件长度 public long lastModified():获取最后一次的修改时间,毫秒值 下面的两个方法适用于文件目录
public String[] list():获取指定目录下的所有文件或者文件目录的名称数组 public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组 重命名 public boolean renameTo(File dest):把文件重命名为指定的文件路径 判断 public boolean isDirectory():判断是否是文件目录 public boolean isFile():判断是否是文件 public boolean exists():判断是否存在 public boolean canRead():判断是否可读 public boolean canWrite():判断是否可写 public boolean isHidden():判断是否隐藏 创建 public boolean createNewFile():创建文件。若文件存在,则不创建,返回false public boolean mkdir():创建文件目录,如果存在,则不创建 public boolean mkdirs():创建文件目录,如果存在,则不创建,如果上层目录不存在,一并创建 删除 注意:java中的删除不走回收站
public boolean delete():删除文件或文件夹 IO流原理及流的分类 缓冲流 按操作数据单位分为:字节流(8 bit),字符流(16 bit) 按数据流的流向分为:输入流、输出流 按流的角色不同分为:节点流(作用在文件上)、处理流(作用在已有的流上) 抽象基类:InputStream, Reader, OutputStream, Writer 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理 对于文本文件(.txt, .java, .c, .cpp),使用字符流处理;对于非文本文件,使用字节流处理 资源关闭:先关闭外层的流,再关闭内层的流;在关闭外层流的同时,内层流的关闭可以省略 转换流 提供了在字符流和字节流之间的转换
属于字符流
InputStreamReader:将一个字节的输入流转换为字符的输入流 OutputStreamWriter:将一个字符的输出流转换为字节的输出流 字符集 字符集 ASCII:美国标准信息交换码 ISO8859-1:拉丁码表。欧洲码表 GB2312:中国的中文编码表。 GBK:中国的中文编码表升级。 Unicode:国际标准码,融合了目前人类使用的所有字符。 UTF-8:变长的编码方式,可用1-4个字节来表示一个字符 ANSI编码,通常指的是平台的默认编码,例如英文操作系统中是ISO-8859-1,中文系统是GBK Unicode字符集只是定义了字符的集合和唯一编号,Unicode编码,则是对UTF-8等具体编码方案的统称而已,而不是具体的编码方案 标准输入输出流 打印流 数据流 对象流 ObjectInputStream和ObjectOutputStream 用于存储和读取基本数据类型或对象的处理流。还可以将Java中的对象写入到数据源中,也能把对象从数据源中还原回来 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制 对象的序列化机制 要想一个Java对象是可序列化的,需要满足相应的要求。 1 2 3 4 5 1.必须实现接口:Serializable 2.必须当前类提供一个全局常量:serialVersionUID public static final long serialVersionUID 3.除了当前类需要实现Serializable接口之外,还必须保证内部的所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化) 4.不能序列化static和transient修饰的属性
serialVersionUID用来表明类的不同版本间的兼容性。 随机存取文件流 创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式:
r:以只读方式打开
rw:打开以便读取和写入
rwd:打开以便读取和写入:同步文件内容的更新
rws:打开以便读取和写入:同步文件内容和元数据的更新
如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建;
如果写出到的文件存在,则会对原有文件内容进行覆盖(默认从头覆盖)
网络编程 通信要素一:IP和端口 java中使用InetAddress类代表IP
域名解析服务器:DNS。将域名解析成IP
本地回路地址:127.0.0.1 对应着:localhost
如何实例化InetAddress:两个方法:getByName(String host), getLocalHost();
两个常用方法:getHostName()/getHostAddress()
端口号标识正在计算机上运行的进程:不同的进程有不同的端口号;被规定为一个16位的整数0~65535;
端口分类:
公认端口:0~1023。被预先定义的服务通信占用 注册端口:1024~49151.分配给用户进程或应用程序 动态/私有端口:49152~65535。 端口号与IP地址的组合得出一个网络套接字:Socket
通信要素二:网络协议 TCP/IP协议簇:传输控制协议(TCP)和网络互联协议(IP) 传输层的两个协议:TCP和UDP(TCP:打电话,UDP:发送短信,发送电报)TCP:1. 传输前,采用三次握手的方式,点对点通信是可靠的。2.在连接中可进行大数据量的传输。3.传输完毕,需要释放已建立的连接,四次挥手,效率低 UDP:1.将数据、源、目的封装成数据包,不需要建立连接。2.不管对方是否准备好,接收方也不确认,是不可靠的。3.可以广播发送。4.发送数据结束后无需释放资源,开销小,速度快。 TCP和UDP的网络编程 URL编程 URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一资源的地址 基本结构:<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表 反射 Reflection是被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法 Java可以称为“准动态语言” 反射能提供的功能:在运行时判断任意一个对象所属的类 构造任意一个类的对象 判断任意一个类所具有的成员变量和方法 获取泛型信息 调用任意一个对象的成员变量和方法 处理注解 生成动态代理 关于java.lang.Class类的理解 类的加载过程:程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中 。此过程就称为类的加载。加载到内存中的类,就称为运行时类,此运行时类,就作为Class的一个实例。 换句话说,Class的实例就对应着一个运行时类。 获取Class的实例的方式: 1 2 3 4 5 6 7 8 9 10 Class clazz1 = Person.class;Person p1 = new Person ();Class clazz2 = p1.getClass();Class clazz3 = Class.forName("Reflection.Person" );ClassLoader classLoader = ReflectionTest.class.getClassLoader();Class clazz4 = classLoader.loadClass("Reflection.Person" );
加载到内存中的运行时类,会缓存一定的时间。在此时间内,我们可以通过不同的方式来获取此运行时类。 哪些类型可以有Class对象:
class:外部类,成员,局部内部类,匿名内部类 interface:接口 []:数组 enum:枚举 annotation:注解@interface primitive type:基本数据类型 void ClassLoader的理解 读取配置文件的两种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Properties pros = new Properties ();ClassLoader classLoader = ClassLoadertest.class.getClassLoader();InputStream is = classLoader.getResourceAsStream("jdbc.properties" );pros.load(is); String user = pros.getProperty("user" );String password = pros.getProperty("password" );System.out.println("user = " + user + ", password = " + password);
创建运行时类的对象 1 2 3 4 5 6 7 8 Class clazz = Class.forName("Reflection.Person" );Person obj = (Person) clazz.newInstance();System.out.println(obj);
获取运行时类的属性结构及其内部结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Class clazz = Class.forName("Reflection2.Person" );Field[] fields = clazz.getFields(); for (Field f : fields){ System.out.println(f); } Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields){ System.out.println(f); } Class clazz = Class.forName("Reflection2.Person" );Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields){ int modifiers = f.getModifiers(); System.out.println(Modifi2 er.toString(modifiers)); Class type = f.getType(); System.out.println(type.getName()); String fName = f.getName(); System.out.println(fName); System.out.println(); }
获取运行时类的方法结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Class clazz = Class.forName("Reflection2.Person" ); Method[] methods = clazz.getMethods(); for (Method m : methods){ System.out.println(m); } System.out.println(); Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method m : methods){ System.out.println(m); }
调用运行时类的指定结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Class clazz = Class.forName("Reflection2.Person" ); Person p = (Person) clazz.newInstance(); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p, "Tom" ); System.out.println(name.get(p)); Class clazz = Class.forName("Reflection2.Person" ); Person p = (Person) clazz.newInstance(); Method show = clazz.getDeclaredMethod("show" , String.class); show.setAccessible(true ); Object chn = show.invoke(p, "CHN" ); Method showDesc = clazz.getDeclaredMethod("showDesc" ); showDesc.setAccessible(true ); Object returnVal = showDesc.invoke(clazz); System.out.println(returnVal);
动态代理 学框架的时候再回过头来看
Java 8 新特性(最重要的改变,一个是Lambda表达式,一个是Stream API) Lambda表达式(这部分以及下面的方法引用部分需要熟练掌握前面的内容才能明白) 格式 ->:lambda操作符或箭头操作符 ->左边:lambda形参列表(其实就是接口中的抽象方法的形参列表) ->右边:lambda体(其实就是重写的抽象方法的方法体) 使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Test public void test1 () { Runnable r1 = () -> System.out.println("我爱北京故宫" ); } @Test public void test2 () { Consumer<String> con1 = (String s) -> System.out.println(); con1.accept("一个是" ); } @Test public void test3 () { Consumer<String> con1 = s -> System.out.println(); con1.accept("算法" ); } @Test public void test4 () { Comparator<Integer> com1 = (o1, o2) -> { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); }; } @Test public void test5 () { Comparator<Integer> com1 = (o1, o2) -> o1.compareTo(o2); }
本质 lambda表达式的本质:作为函数式接口(Functional Interface)的实例 如果一个接口中,只声明了一个抽象方法,就称为函数式接口 我们可以使用@FunctionnalInterface来注解一个接口,来检查是否是一个函数式接口 以后函数式接口的匿名实现类都可以使用Lambda表达式来写 函数式接口 Consumer:消费型接口;void accept(T t); Supplier:供给型接口;T get(); Function:函数型接口;R apply(T t); Predicate:断定型接口;boolean test(T t); 方法引用(Method References) 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用 本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。 使用格式 类(对象) : : 方法名 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同 具体使用的三种情况 对象 ::非静态方法 类::静态方法 类::非静态方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Consumer<String> con1 = str -> System.out.println(str); con1.accept("北京" ); System.out.println("****************************" ); PrintStream ps = System.out;Consumer<String> con2 = ps :: println; con2.accept("北京" ); ==================================================================== Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2); System.out.println(com1.compare(12 , 21 )); System.out.println("**************************" ); Comparator<Integer> com2 = Integer :: compare; System.out.println(com2.compare(21 , 21 )); ===================================================================== Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2); System.out.println(com1.compare("fasd" , "fads" )); System.out.println("***************************" ); Comparator<String> com2 = String :: compareTo; System.out.println(com2.compare("as" , "tewa" ));
构造器引用和项目引用 Stream API Stream的实例化 一系列的中间操作(过滤、映射…) 终止操作 说明 一个中间操作链,对数据源的数据进行处理 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用 Stream的实例化 通过集合 1 2 3 4 5 List<Employee> employees = EmployeeData.getEmployees(); Stream<Employee> stream = employees.stream(); Stream<Employee> parallelStream = employees.parallelStream();
通过数组 1 2 Employee[] arr = new Employee []{e1, e2, e3}; Stream<Employee> stream = Arrays.stream(arr);
通过Stream的of() 1 Stream<Integer> stream = Stream.of(1 , 2 , 3 , 4 , 5 , 6 );
创建无限流 1 2 3 4 Stream.iterate(0 , t -> t + 2 ).limit(10 ).forEach(System.out :: println); Stream.generate(Math :: random).limit(10 ).forEach(System.out :: println);
Stream的中间操作 筛选与切片 1 2 3 4 5 6 7 8 9 10 11 12 13 List<Employee> list = EmployeeData.getEmployees(); Stream<Employee> stream = list.stream(); stream.filter(e -> e.getSalary() > 7000 ).forEach(System.out :: println); list.stream().limit(3 ).forEach(System.out :: println); list.stream().skip(3 ).forEach(System.out :: println); list.stream().distinct().forEach(System.out :: println);
映射 1 2 3 4 5 6 7 8 9 10 11 12 List<String> list = Arrays.asList("aa" , "bb" , "cc" , "dd" ); list.stream().map(str -> str.toUpperCase()).forEach(System.out :: println); List<Employee> employees = EmployeeData.getEmployees(); Stream<String> namesStream = employees.stream().map(Employee :: getName); namesStream.filter(name -> name.length() > 3 ).forEach(System.out :: println); List<String> list = Arrays.asList("aa" , "bb" , "cc" , "dd" ); Stream<Character> characterStream = list.stream().flatMap(StreamAPITest::fromStringToStream); characterStream.forEach(System.out :: println);
排序 1 2 3 4 5 6 List<Integer> list = Arrays.asList(12 , 421 , 123 , 24 , 541 , 23 , 12 , 531 ); list.stream().sorted().forEach(System.out :: println); List<Employee> employees = EmployeeData.getEmployees(); employees.stream().sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()).forEach(System.out :: println);
Stream的终止操作 匹配与查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18 ); boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000 ); boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷" )); Optional<Employee> employee = employees.stream().findFirst(); Optional<Employee> employee1 = employees.parallelStream().findAny(); long count = employees.stream().count(); Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary()); Optional<Double> maxSalary = salaryStream.max(Double::compare); Optional<Double> minSalary = salaryStream.min(Double::compare); employees.stream().forEach(System.out :: println);
归约 1 2 3 4 5 6 7 List<Integer> list = Arrays.asList(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ); Integer sum = list.stream().reduce(0 , Integer::sum); Stream<Double> salaryStream = employees.stream().map(Employee::getSalary); salaryStream.reduce(Double :: sum);
收集 1 2 3 4 List<Employee> employees = EmployeeData.getEmployees(); List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000 ).collect(Collectors.toList()); employeeList.forEach(System.out :: println);
Optional类 神秘按钮