数组是相同数据类型的有序集合,数组本身也是一个对象.
数组的三个基本特点:
(1)长度是确定的,数组一但被创建大小就无法被改变.
(2)其元素必须是相同类型,不允许出现混合类型。
(3)数组类型可以是任何数据类型,包括基本类型和引用类型。
数组声明的两种方式:
type[] arr_name; //(推荐使用这种方式) type arr_name[];
数组声明注意事项:
(1)声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
(2)声明一个数组的时候并没有数组真正被创建。
(3)构造一个数组,必须指定长度。
[实例1.2.1]创建一个基本类型一维数组
public class TestArr{ public static void main(String args[]) { int[] s = null; // 声明数组; s = new int[10]; // 给数组分配空间; for (int i = 0; i < 10; i++) { s[i] = 2 * i + 1;//给数组元素赋值; System.out.println(s[i]); } } }
[实例1.2.2]创建引用类型一维数组
class Man{ private int age; private int id; public Man(int id,int age) { super(); this.age = age; this.id = id; } } public class AppMain { public static void main(String[] args) { Man[] mans; //声明引用类型数组; mans = new Man[10]; //给引用类型数组分配空间; Man m1 = new Man(1,11); Man m2 = new Man(2,22); mans[0]=m1;//给引用类型数组元素赋值; mans[1]=m2;//给引用类型数组元素赋值; } }
数组初始化的三种方式:
(1)静态初始化数组
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
int[] a = { 1, 2, 3 };// 静态初始化基本类型数组; Man[] mans = { new Man(1, 1), new Man(2, 2) };// 静态初始化引用类型数组;
(2)动态初始化数组
数组定义与为数组元素分配空间并赋值的操作分开进行。
int[] a1 = new int[2];//动态初始化数组,先分配空间; a1[0]=1;//给数组元素赋值; a1[1]=2;//给数组元素赋值;
(3)数组默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
int a2[] = new int[2]; // 默认值:0,0 boolean[] b = new boolean[2]; // 默认值:false,false String[] s = new String[2]; // 默认值:null, null
数组的下标索引序列区间为[0,length-1],我们通过下标来遍历数组中的元素,遍历时读取元素的值或修改元素的值.
[实例1.4.1]通过循环遍历初始化和读取数组
public class Test { public static void main(String[] args) { int[] a = new int[4]; //初始化数组元素的值 for(int i=0;i<a.length;i++){ a[i] = 100*i; } //读取元素的值 for(int i=0;i<a.length;i++){ System.out.println(a[i]); } } }
增强for循环for-each循环,专门用于读取数组或者集合中的所有元素,即对数组或集合进行遍历
[实例1.4.2]for-each循环
public class Test { public static void main(String[] args) { String[] ss = { "aa", "bbb", "ccc", "ddd" }; for (String temp : ss) { System.out.println(temp); } } }
for-each循环注意事项:
(1)for-each增强for循环在遍历数组过程中不能修改数组中某元素的值。
(2)for-each仅适用于遍历,不涉及有关索引(下标)的操作。
arraycopy是System包里的一个方法,它是用来把数组中的一段元素,复制到另一个数组中.
调用方法:
System.arraycopy(src, srcPos, dest, destPos, length);
src是从哪个数组,dest是拷向哪个数组,
srcPos是从src的哪个下标开始拷贝,
destPos是从dest哪个下标开始粘贴,
length是拷贝和粘贴的长度是几
[实例1.5.1]数组拷贝
public class TestArrayCopy { public static void main(String[] args) { String[] s1 = {"aa","bb","cc","dd","ee"}; String[] s2 = new String[6]; System.arraycopy(s1, 2, s2, 0, s1.length-2); for(String s:s2){ System.out.println(s); } } }
还可以使用arraycopy方法把一个数组中的一段元素拷贝到原数组中,根据这个用法可以完成数组的删除、插入等方法
[实例1.5.2]数组的自拷贝和插入删除
public class TestArrayCopy { public static void main(String[] args) { String[] s1 = {"aa","bb","cc","dd","ee"}; String[] s2 = new String[6]; System.arraycopy(s1, 2, s2, 0, s1.length-2); for(String s:s2){ System.out.println(s); } //TestDelCopy(s1,2); s1 = TestInset(s1, 2, "zz"); } //删除数组中指定索引位置的元素 public static String[] TestDelCopy(String[] s,int index){ System.arraycopy(s, index+1, s, index, s.length-index-1); s[s.length-1] = null; for(String str:s){ System.out.println(str); } return s; } //在指定索引位置插入指定元素 public static String[] TestInset(String[] s,int i,String sr){ String[] s1 = new String[s.length+1]; System.arraycopy(s, 0, s1, 0, i); s1[i] = sr; System.arraycopy(s, i, s1, i+1, s.length-i); for(String tem:s1){ System.out.println(tem); } return s1; } }
注意:数组的扩容本质上就是创建一个新数组然后原封不动的把原数组的元素再拷贝到新数组中
[实例1.5.3]数组的扩容
public class TestArrayKuo { public static void main(String[] args) { String[] s1 = {"aa","bb","cc","dd","ee"}; s1 = arrayKuo(s1); for(String temp:s1){ System.out.println(temp); } } //封装了一个把数组扩容两倍的方法 public static String[] arrayKuo(String[] s1){ String[] s2 = new String[s1.length*2]; System.arraycopy(s1, 0, s2, 0, s1.length); return s2; } }
JDK提供的java.util.Arrays类,包含了常用的数组操作,方便我们日常开发。Arrays类包含了:排序、查找、填充、打印内容等常见的操作。
[实例1.6.1]打印数组(Arrays.toString(array))*
import java.util.Arrays; public class Test { public static void main(String args[]) { int[] a = { 1, 2 }; System.out.println(a); // 打印数组引用的值; System.out.println(Arrays.toString(a)); // 打印数组元素的值; } }
注意:
此处的Arrays.toString()方法是Arrays类的静态方法,不是父类Object的toString()方法。
[实例1.6.2]数组元素是基本类型的排序(Arrays.sort(array))
import java.util.Arrays; public class Test { public static void main(String args[]) { int[] a = {1,2,323,23,543,12,59}; System.out.println(Arrays.toString(a)); Arrays.sort(a); System.out.println(Arrays.toString(a)); } }
[实例1.6.3]数组元素是引用类型的排序(Arrays.sort(array)并使用Comparable接口)
import java.util.Arrays; public class Test { public static void main(String[] args) { Man[] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") }; Arrays.sort(msMans); System.out.println(Arrays.toString(msMans)); } } class Man implements Comparable { int age; int id; String name; public Man(int age, String name) { super(); this.age = age; this.name = name; } public String toString() { return this.name; } public int compareTo(Object o) { Man man = (Man) o; if (this.age < man.age) { return -1; } if (this.age > man.age) { return 1; } return 0; } }
[实例1.6.4]数组的二分查找(Arrays.binarySearch(array,x))
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] a = {1,2,323,23,543,12,59}; System.out.println(Arrays.toString(a)); Arrays.sort(a); //使用二分法查找,必须先对数组进行排序; System.out.println(Arrays.toString(a)); //返回排序后新的索引位置,若未找到返回负数。 System.out.println("该元素的索引:"+Arrays.binarySearch(a, 12)); } }
注意:要使用二分查找,必须先对数组进行排序,然后再进行查找,找到了返回所在位置的索引,找不到返回-1
[实例1.6.5]数组填充(Arrays.fill(array,x,y,z))
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] a= {1,2,323,23,543,12,59}; System.out.println(Arrays.toString(a)); Arrays.fill(a, 2, 4, 100); //将2到4索引的元素替换为100; System.out.println(Arrays.toString(a)); } }
使用详解:(Arrays.fill(array,x,y,z),array为填充哪个数组,x为从哪开始,y为到哪结束,z为填充成什么
多维数组可以看成以数组为元素的一维数组,可以有二维数组,三维数组甚至更多维数组,实际开发基本使用最多的是二维数组,甚至二维数组都不会使用很多(学完容器以后基本使用容器)
[实例1.7.1]二维数组的声明
public class Test { public static void main(String[] args) { // Java中多维数组的声明和初始化应按从低维到高维的顺序进行 int[][] a = new int[3][]; a[0] = new int[2]; a[1] = new int[4]; a[2] = new int[3]; // int a1[][]=new int[][4];//非法 } }
注意:int a1[][]=new int[][4]; 这种写法是错误的
[实例1.7.2]二维数组的静态初始化和动态初始化
public class TestMultidimensionalArray { public static void main(String[] args) { //动态初始化二维数组 int[][] a = new int[3][]; //a[0] = {10,20,30};//错误,没有声明类型就初始化 a[0] = new int[] {11,20,30}; a[1] = new int[] {48,5,98,75}; a[2] = new int[] {77,5,99,24,66}; System.out.println(a[2][2]); //静态初始化二维数组 int[][] b = { {11,20,30}, {48,5,98,75}, {77,5,99,24,66} }; System.out.println(b[2][2]); } }
注意:a[0] = {10,20,30};//错误,没有声明类型就初始化
[实例1.7.3]获取二维数组的长度
//获取的二维数组第一维数组的长度。 System.out.println(a.length); //获取第二维第一个数组长度。 System.out.println(a[0].length);
数组存储表格数据:就是把多个object数组赋给一个object数组
[实例1.7.4]把下面表转换成二维数组程序
ID | 姓名 | 年龄 | 职能 | 入职日期 |
---|---|---|---|---|
1001 | 费杨 | 18 | 前端 | 2001.1.1 |
1002 | 费二杨 | 19 | 后端 | 2002.1.1 |
1003 | 费三杨 | 20 | 架构 | 2003.1.1 |
import java.util.Arrays; public class TestTableArray { public static void main(String[] args) { Object[] a1 = {1001,"费杨",18,"前端","2001.1.1"}; Object[] a2 = {1002,"费二杨",19,"后端","2002.1.1"}; Object[] a3 = {1003,"费三杨",20,"架构","2003.1.1"}; Object[][] a = new Object[3][]; a[0] = a1; a[1] = a2; a[2] = a3; for(Object[] temp:a){ System.out.println(Arrays.toString(temp)); } } }
冒泡排序的核心就是比较相邻的两个数然后通过交换的方式把大的往后放
[实例1.8.1]冒泡排序基础算法
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] values = { 3, 1, 6, 2, 9, 0, 7, 4, 5, 8 }; bubbleSort(values); System.out.println(Arrays.toString(values)); } public static void bubbleSort(int[] values) { int temp; for (int i = 0; i < values.length; i++) { for (int j = 0; j < values.length - 1 - i; j++) { if (values[j] > values[j + 1]) { temp = values[j]; values[j] = values[j + 1]; values[j + 1] = temp; } } } } }
通过结果来看,没有到最后就排列好了顺序,后面很多轮的循环都是多余的,所以我们可以通过加一个标志的方式看是否排序好,只要这理论for循环里面的if执行了,就会改变标志的值,如果没改变说明排序完毕,就会通过判断标志的值来结束循环
[实例1.8.2]冒泡排序的优化算法
import java.util.Arrays; public class Test1 { public static void main(String[] args) { int[] values = { 3, 1, 6, 2, 9, 0, 7, 4, 5, 8 }; bubbleSort(values); System.out.println(Arrays.toString(values)); } public static void bubbleSort(int[] values) { int temp; int i; // 外层循环:n个元素排序,则至多需要n-1趟循环 for (i = 0; i < values.length - 1; i++) { // 定义一个布尔类型的变量,标记数组是否已达到有序状态 boolean flag = true; /*内层循环:每一趟循环都从数列的前两个元素开始进行比较,比较到无序数组的最后*/ for (int j = 0; j < values.length - 1 - i; j++) { // 如果前一个元素大于后一个元素,则交换两元素的值; if (values[j] > values[j + 1]) { temp = values[j]; values[j] = values[j + 1]; values[j + 1] = temp; //本趟发生了交换,表明该数组在本趟处于无序状态,需要继续比较; flag = false; } } //根据标记量的值判断数组是否有序,如果有序,则退出;无序,则继续循环。 if (flag) { break; } } } }
二分查找就是给定一个数组先进行排序(必须先进行排序),然后定义两个key,一个key的值是开头,一个key的值是索引的结束位置,然后定义一个mid,然后索引的数如果等于mid就是找到了,可以直接返回索引下标,如果索引的数大于mid,就把索引的两个key中的结束key的值变为数组的mid-1,在进行下次索引,直到找到,如果索引的数小于mid,就把索引的开始key的值变为mid+1,再进行下次索引,直到找到索引的数并返回下标,如果开始的key大于结束的key那么程序结束,说明没找到,可以返回-1
[实例1.9.1]二分查找代码
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] arr = { 30,20,50,10,80,9,7,12,100,40,8}; int searchWord = 20; // 所要查找的数 Arrays.sort(arr); //二分法查找之前,一定要对数组元素排序 System.out.println(Arrays.toString(arr)); System.out.println(searchWord+"元素的索引:"+binarySearch(arr,searchWord)); } public static int binarySearch(int[] array, int value){ int low = 0; int high = array.length - 1; while(low <= high){ int middle = (low + high) / 2; if(value == array[middle]){ return middle; //返回查询到的索引位置 } if(value > array[middle]){ low = middle + 1; } if(value < array[middle]){ high = middle - 1; } } return -1; //上面循环完毕,说明未找到,返回-1 } }
包装类就是把基本数据类型转换成对象,把对象转换成基本数据类型
包装类均位于java.lang包,八种包装类和基本数据类型的对应关系如图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u7hwFgu6-1621259671449)(C:\Users\Administrator\Desktop\1495593568889579.png)]
[实例2.1.1]简单包装类
public class WrapperClassTest { public static void main(String[] args) { //将int类型的数转换成Integer对象 Integer i = new Integer(10); Integer j = new Integer(50); } }
包装类的用途:
(1)作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作。
(2)包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
public class Test { /** 测试Integer的用法,其他包装类与Integer类似 */ void testInteger() { // 基本类型转化成Integer对象 Integer int1 = new Integer(10); Integer int2 = Integer.valueOf(20); // 官方推荐这种写法 // Integer对象转化成int int a = int1.intValue(); // 字符串转化成Integer对象 Integer int3 = Integer.parseInt("334"); Integer int4 = new Integer("999"); // Integer对象转化成字符串 String str1 = int3.toString(); // 一些常见int类型相关的常量 System.out.println("int能表示的最大整数:" + Integer.MAX_VALUE); } public static void main(String[] args) { Test test = new Test(); test.testInteger(); } }
String被创建以后就无法被修改,因为它的底层是一个final修饰的char类型的数组,字符串的拼接通常用’+'号,因为String本身也是一个对象,所以比较两个对象是否一样**尽量使用equals()**而避免使用"=="
String类常用的方法有:
(1)String类的下述方法能创建并返回一个新的String对象: concat()、 replace()、substring()、 toLowerCase()、 toUpperCase()、trim()。
(2)提供查找功能的有关方法: endsWith()、 startsWith()、 indexOf()、lastIndexOf()。
(3)提供比较功能的方法: equals()、equalsIgnoreCase()、compareTo()。
(4)其它方法: charAt() 、length()。
StringBuilder和StringBuffer是可变字符串,区别是,StringBuilder线程不安全,效率高(通常使用),StringBuffer线程安全,效率慢
StringBuilder的常见方法:
(1)append方法:给字符串后面拼接上字符串、字符或者其他.
使用方法:str.append(需要拼接的内容),(仍返回自身,可反复调用);
sb.append('*');//为字符串sb后面拼接上*
(2)delect方法:可以删除一个字符串从一个索引到另一个索引的字符串,删除的后面的元素会往前补(使用后仍返回自己,可反复调用)
使用方法:str.delect(start,end),(删除的索引是[start,end-1]);
sb.delete(2, 4);
(3)deleteCharAt方法:可以删除一个索引上的元素,删除后面的元素会往前补(使用后仍返回自己,可反复调用)
使用方法:Str.delectCharAt(index);
sb.deleteCharAt(3);
(4)insert方法:实现了在某个索引位置插入一个字符或者字符串等元素
使用方法:sb2.insert(index, 需要插入的内容);
sb2.insert(5, "爸爸");
(5**)reverse**方法:把字符串序列倒序(使用后仍返回自己,可反复调用)
使用方法:sb2.reverse();
sb2.reverse();
(6)**toString()**方法:返回此序列中数据的字符串表示形式。
使用方法:sb2.toString();
System.out.println(sb2.toString());
DateFormat就是时间和字符串指定格式的互相转换
DateFormat不能自己实现这个作用,通常使用DateFormat的实现类SimpleDateFormat来实现
使用方法:DateFormat df = new SimpleDateFormat(“里面加规定格式”);
Date//把时间格式化转换为字符串 DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String str = df.format(new Date()); System.out.println(str);
format方法用来将一个时间转换成上面定义的格式的时间字符串
//把时间格式化转换为字符串 DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String str = df.format(new Date()); System.out.println(str); //测试其他格式化用法:D:时间处于一年中的多少天 DateFormat df3 = new SimpleDateFormat("D"); String str2 = df3.format(new Date()); System.out.println(str2);
parse方法用来将一个按上述格式定义的时间字符串转换成时间
//把格式化的时间字符串转换成时间 DateFormat df2 = new SimpleDateFormat("yyyy年MM月dd日hh点mm分ss秒"); Date d = df2.parse("2021年5月12日19点03分51秒"); System.out.println(d);
代码中的格式化字符的具体含义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uPp9trMD-1621259671453)(C:\Users\Administrator\Desktop\1495609352295957.png)]
[实例2.4.1]当前时间处于一年中第几天
import java.text.SimpleDateFormat; import java.util.Date; public class TestDateFormat2 { public static void main(String[] args) { SimpleDateFormat s1 = new SimpleDateFormat("D"); String daytime = s1.format(new Date()); System.out.println(daytime); } }
Calendar是一个抽象类,为我们提供了关于日期计算的相关功能,比如:年月日小时秒分周几的展示和计算
GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。
注意:
(1)程序算出来的周几是从1-7的计数,但是1不是星期一,而是星期日,2才是星期一,以此类推
(2)程序算出来的月计数是0-11,所以一月是0,11是十二月
使用方法:Calendar calendar = new GregorianCalendar(要操作或展示的时间);(如果不写就是当前时间)
Calendar calendar = new GregorianCalendar(2021,05,13,12,50,14);
使用方法:calendar.set(calendar.YEAR, 修改为多少年); //calendar是上面定义的时间
//修改时间的年和秒 calendar.set(calendar.YEAR, 2021); calendar.set(calendar.SECOND, 01);
使用方法:calendar.add(calendar.YEAR, 进行计算的数); //calendar是上面定义的时间
//日期推算:往前100年是哪一年 calendar.add(calendar.YEAR, -100); year = calendar.get(calendar.YEAR); System.out.println(year);
使用方法:int year = calendar.get(calendar.YEAR); //calendar是上面定义的时间
//获取时间的秒和年 int year = calendar.get(calendar.YEAR); System.out.println(year); int second = calendar.get(calendar.SECOND); System.out.println(second);
math类的常用方法:
(1)abs 绝对值
(2)acos,asin,atan,cos,sin,tan 三角函数
(3)sqrt 平方根
(4)pow(double a, double b) a的b次幂
{5}max(double a, double b) 取大值
(6)min(double a, double b) 取小值
(7) ceil(double a) 大于a的最小整数
(8)floor(double a) 小于a的最大整数
(9)random() 返回 0.0 到 1.0 的随机数
(10)long round(double a) double型的数据a转换为long型(四舍五入)
(11)toDegrees(double angrad) 弧度->角度
(12)toRadians(double angdeg) 角度->弧度
[实例2.6.1]Math类的应用
public class TestMath { public static void main(String[] args) { //取整相关操作 System.out.println(Math.ceil(3.2)); System.out.println(Math.floor(3.2)); System.out.println(Math.round(3.2)); System.out.println(Math.round(3.8)); //绝对值、开方、a的b次幂等操作 System.out.println(Math.abs(-45)); System.out.println(Math.sqrt(64)); System.out.println(Math.pow(5, 2)); System.out.println(Math.pow(2, 5)); //Math类中常用的常量 System.out.println(Math.PI); System.out.println(Math.E); //随机数 System.out.println(Math.random());// [0,1) } }
Math类为我们提供了生成随机数的Math.random()方法,但是我们通常要使用的随机数范围不是[0,1)之间的小树,这就要使用Random类了,Random这个类专门用来生成随机数并且Math.random()底层调用的就是Random的nextDouble()方法。
[实例2.6.2]Random类的使用
import java.util.Random; public class TestRandom { public static void main(String[] args) { Random rand = new Random(); //随机生成[0,1)之间的double类型的数据 System.out.println(rand.nextDouble()); //随机生成int类型允许范围之内的整型数据 System.out.println(rand.nextInt()); //随机生成[0,1)之间的float类型的数据 System.out.println(rand.nextFloat()); //随机生成false或者true System.out.println(rand.nextBoolean()); //随机生成[0,10)之间的int类型的数据 System.out.print(rand.nextInt(10)); //随机生成[20,30)之间的int类型的数据 System.out.print(20 + rand.nextInt(10)); //随机生成[20,30)之间的int类型的数据(此种方法计算较为复杂) System.out.print(20 + (int) (rand.nextDouble() * 10)); } }
java.io.File类:代表文件和目录。 在开发中,读取文件、生成文件、删除文件、修改文件的属性时经常会用到File类。
通过File对象可以访问文件的属性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HZPwyzRV-1621259671459)(C:\Users\Administrator\Desktop\1495611382530451.png)]
[实例2.7.1]通过File对象访问文件的属性
import java.io.File; import java.io.IOException; import java.util.Date; public class TestFile { public static void main(String[] args) throws IOException { File file = new File("d:/feiyang.txt"); file.createNewFile(); //file.renameTo(new File("d:/liuyuqing.txt"));//rename是改名操作 //file.delect(); //delect删除文件 System.out.println("File是否存在" + file.exists()); System.out.println("File是否是目录" + file.isDirectory()); System.out.println("File是否是文件" + file.isFile()); System.out.println("File最后的修改时间:" + new Date(file.lastModified())); System.out.println("File的大小" + file.length()); System.out.println("File的文件名" + file.getName()); System.out.println("File的路径" + file.getPath()); System.out.println("File的绝对路径:" + file.getAbsolutePath()); } }
通过File对象创建空文件或目录(在对象指定的文件或目录不存在的情况下)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OGuJtzWE-1621259671463)(C:\Users\Administrator\Desktop\1495611400819053.png)]
[实例2.7.2]测试mkdir()和mkdirs()创建目录
import java.io.File; public class TestFile3 { public static void main(String[] args) throws Exception { File f = new File("d:/c.txt"); f.createNewFile(); // 会在d盘下面生成c.txt文件 f.delete(); // 将该文件或目录从硬盘上删除 File f2 = new File("d:/电影/华语/大陆"); boolean flag = f2.mkdir(); //目录结构中有一个不存在,则不会创建整个目录树 System.out.println(flag);//创建失败 } }
mkdir()和mkdirs()的区别:
mkdir()只要目录中缺少任何一个都不会被创建
mkdirs()目录中缺少任何一个都会被创建
[实例2.7.3]使用递归打印目录树
import java.io.File; public class TestFile6 { public static void main(String[] args) { File f = new File("d:/电影"); printFile(f, 0); } /** * 打印文件信息 * @param file 文件名称 * @param level 层次数(实际就是:第几次递归调用) */ static void printFile(File file, int level) { //输出层次数 for (int i = 0; i < level; i++) { System.out.print("-"); } //输出文件名 System.out.println(file.getName()); //如果file是目录,则获取子文件列表,并对每个子文件进行相同的操作 if (file.isDirectory()) { File[] files = file.listFiles(); for (File temp : files) { //递归调用该方法:注意等+1 printFile(temp, level + 1); } } } }
容器就是存储和和处理数据的,容器可以看成一个可扩容的数组
数组的优势:是一个有序线性序列,可以快速的访问数据元素适合查找和赋值,效率高
数组的劣势:不灵活,定义好以后就确定了数组的最大长度,无法扩展
容器可以扩展,容器可以看成一个数组,而泛型就是可以看成一个限制数据类型的限制器,它控制存入容器中的元素的数据类型
容器Colloction有两个接口:List(通常使用)和Set
List和Set的区别:
List是一个有序可以重复的容器
Set是一个无序不可重复的容器
泛型就是一个控制存入容器中的元素的数据类型的控制器,过去定义了泛型为String,那容器中只能存入String类的数据
我们声明泛型的时候通常使用<T,E,V>这三个字母
[实例4.2.1]自定义泛型(泛型类的声明)
class MyCollection<E> {// E:表示泛型; Object[] objs = new Object[5]; public E get(int index) {// E:表示泛型; return (E) objs[index]; } public void set(E e, int index) {// E:表示泛型; objs[index] = e; } }
泛型E像一个占位符一样表示“未知的某个数据类型”,我们在真正调用的时候传入这个“数据类型”。
[实例4.2.2]自定义泛型(泛型类的应用)
public class TestGenerics { public static void main(String[] args) { // 这里的”String”就是实际传入的数据类型; MyCollection<String> mc = new MyCollection<String>(); mc.set("aaa", 0); mc.set("bbb", 1); String str = mc.get(1); //加了泛型,直接返回String类型,不用强制转换; System.out.println(str); } }
[实例4.2.3]泛型在容器中使用
public class Test { public static void main(String[] args) { // 以下代码中List、Set、Map、Iterator都是与容器相关的接口; List<String> list = new ArrayList<String>(); Set<Man> mans = new HashSet<Man>(); Map<Integer, Man> maps = new HashMap<Integer, Man>(); Iterator<Man> iterator = mans.iterator(); } }
Collection有两个接口类:List和Set,因为List和Set是Collection子接口,所以都有Collection的方法;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQ2T5HEa-1621259671468)(E:\学习\Typora笔记\图片\1495614959696503.png)]
List是有序、可重复容器.
有序:List的每个元素都有索引标记,可以根据元素的索引标记(在List中的位置)访问元素,从而精确控制这些元素。
可重复:List允许加入重复的元素。更确切地讲,List通常允许满足 e1.equals(e2) 的元素重复加入容器。
除了Collection接口中的方法,List多了一些跟顺序(索引)有关的方法,参见下表:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2icQEYWw-1621259671470)(E:\学习\Typora笔记\图片\1495616109914665.png)]
List接口常用的实现类有3个:ArrayList(通常使用)、LinkedList和Vector。
[实例4.4.1]Collection的方法和List的方法测试
Collection<String> collection = new ArrayList<>(); System.out.println(collection.size()); System.out.println(collection.isEmpty()); collection.add("沸羊羊"); collection.add("费杨仔"); System.out.println(collection); System.out.println(collection.contains("美羊羊")); Object[] object = collection.toArray(); System.out.println(Arrays.toString(object)); collection.remove("沸羊羊"); System.out.println(collection); collection.clear(); System.out.println(collection.size());
[实例4.4.2]测试两个List的元素处理
public class TestList { public static void main(String[] args) { test02(); } /** * 测试两个容器之间元素处理 */ public static void test02() { List<String> list = new ArrayList<String>(); list.add("高淇"); list.add("高小七"); list.add("高小八"); List<String> list2 = new ArrayList<String>(); list2.add("高淇"); list2.add("张三"); list2.add("李四"); System.out.println(list.containsAll(list2)); //false list是否包含list2中所有元素 System.out.println(list); list.addAll(list2); //将list2中所有元素都添加到list中 System.out.println(list); list.removeAll(list2); //从list中删除同时在list和list2中存在的元素 System.out.println(list); list.retainAll(list2); //取list和list2的交集 System.out.println(list); } }
[实例4.4.3]List中操作索引的常用方法
public static void test03(){ List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("e"); System.out.println(list); list.add(2, "费杨"); System.out.println(list.get(2)); System.out.println(list); list.remove(2); System.out.println(list); list.set(2, "刘宇晴"); System.out.println(list); list.add("a"); System.out.println(list); System.out.println(list.indexOf("a")); System.out.println(list.lastIndexOf("a")); }
Map就是键值对(键key-值value),我们很多数据都 需要成 对存储,这时候我们就需要用到我们的Map类了
注意:Map类中存储的"键值对"通过键来标识,所以"键对象"不能重复
Map 接口的实现类有HashMap(通常使用)、TreeMap、HashTable、Properties等。
Map接口中常用的方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2r2ub27-1621259671472)(E:\学习\Typora笔记\图片\1495616109914665.png)]
HashMap采用哈希算法实现,是Map接口最常用的实现类。 由于底层采用了哈希表存储数据,我们要求键不能重复,如果发生重复,新的键值对会替换旧的键值对。 HashMap在查找、删除、修改方面都有非常高的效率。
**[实例4.5.1]测试Map方法
import java.util.HashMap; import java.util.Map; /** * 练习Map方法 * @author 费杨 * */ public class TestMap { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "费小羊"); map.put(2, "费二羊"); map.put(3, "费三羊"); System.out.println(map); System.out.println(map.get(2)); System.out.println(map.size()); System.out.println(map.isEmpty()); map.remove(2); System.out.println(map); System.out.println(map.containsKey(2)); System.out.println(map.containsValue("费小羊")); Map<Integer, String> map2 = new HashMap<>(); map2.put(2, "费二羊"); map2.put(4, "刘小晴"); map.putAll(map2); System.out.println(map); //注意key不可以重复,重复的话就是覆盖原来的key对应的value map.put(1, "刘二晴"); System.out.println(map); System.out.println(map2); map2.clear(); System.out.println(map2); } }
HashTable类和HashMap用法几乎一样,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低。
HashMap与HashTable的区别:
(1)HashMap: 线程不安全,效率高。允许key或value为null。
(2)HashTable: 线程安全,效率低。不允许key或value为null。
[实例4.5.2]用Map存储实体化对象
import java.util.HashMap; import java.util.Map; public class TestMap2 { public static void main(String[] args) { Map<Integer, Employee> eMap = new HashMap<Integer, Employee>(); Employee e1 = new Employee(1001, "费小晴", 25741); Employee e2 = new Employee(1002, "刘小晴", 35741); Employee e3 = new Employee(1003, "费小羊", 45741); Employee e4 = new Employee(1004, "刘小羊", 55741); eMap.put(1001, e1); eMap.put(1002, e2); eMap.put(1003, e3); eMap.put(1004, e4); System.out.println(eMap.get(1001).getEname()); } } class Employee{ private Integer id; private String ename; private Integer salary; @Override public String toString() { return "Employee [id=" + id + ", ename=" + ename + ", salary=" + salary + "]"; } public Employee(Integer id, String ename, Integer salary) { super(); this.id = id; this.ename = ename; this.salary = salary; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Integer getSalary() { return salary; } public void setSalary(Integer salary) { this.salary = salary; } }
迭代器使用很是麻烦,但是为我们提供了统一的遍历容器的方式,如果遇到遍历容器时,同时判断一个元素在不在容器中,同时删除这个元素时,用迭代器遍历!
//使用迭代器遍历List public static void testIteratorList(){ List<String> list = new ArrayList<>(); list.add("aa"); list.add("bb"); list.add("cc"); System.out.println(list); for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){ String temp = iterator.next(); System.out.println(temp); if(temp.endsWith("c")){ //删除结尾为c的字符串 iterator.remove(); } } System.out.println(list); }
注意:
此处的删除是iterator.remove不是list.remove
//使用迭代器遍历Set public static void testIteratorSet(){ Set<String> set = new HashSet<>(); set.add("aa"); set.add("b"); set.add("cc"); System.out.println(set); for(Iterator<String> iterator = set.iterator();iterator.hasNext();){ String temp = iterator.next(); System.out.println(temp); } }
[实例4.6.3]用迭代器遍历Map
//使用迭代器遍历Map public static void testIteratorMap(){ Map<Integer, String> map = new HashMap<>(); map.put(100, "费杨"); map.put(200, "费二杨"); map.put(300, "费三杨"); Set<Integer> keyset = map.keySet(); for(Iterator<Integer> iterator = keyset.iterator();iterator.hasNext();){ Integer key = iterator.next(); System.out.println(key + ":" + map.get(key)); } }
java.util.Collections 提供了对Set、List、Map进行排序、填充、查找元素的辅助方法。
(1)shuffle
使用方法:Collections.shuffle(容器名);
(2)reverse
使用方法:Collections.reverse(容器名);
(3)sort
使用方法:Collections.sort(容器名);
(4)binarySearch
使用方法:Collections.binarySearch(容器名, “查找内容”)
(5)fill
使用方法:Collections.fill(容器名, “填充内容”);
[实例4.7.1]测试Collections工具类的方法
import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 测试Collections工具类(不是Collection接口) * @author Administrator * */ public class TestCollections { public static void main(String[] args) { List<String> list = new ArrayList<>(); for(int i = 0;i <= 9;i++){ list.add("费:" + i); } System.out.println(list); Collections.shuffle(list); //随机序列 System.out.println(list); Collections.reverse(list); //倒序 System.out.println(list); Collections.sort(list); //排序 System.out.println(list); System.out.println(Collections.binarySearch(list, "费:5")); Collections.fill(list, "111"); System.out.println(list); } }
[实例4.7.2]测试JavaBean存储表格数据
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * 测试javabean存储表格数据 * @author 费杨 * */ public class TestJavaBean { public static void main(String[] args) { Emp emp1 = new Emp(1001, "张三", 80000, "2001.5.13"); Emp emp2 = new Emp(1001, "李四", 70000, "2005.5.13"); Emp emp3 = new Emp(1001, "王五", 15000, "2010.5.13"); List<Emp> list = new ArrayList<>(); list.add(emp1); list.add(emp2); list.add(emp3); for(Emp emp:list){ System.out.println(emp); } Map<Integer, Emp> map = new HashMap<>(); map.put(1001, emp1); map.put(1002, emp2); map.put(1003, emp3); Set<Integer> keyset = map.keySet(); for(Integer key:keyset){ System.out.println(map.get(key)); } } } class Emp{ private Integer id; private String ename; private double salary; private String date; public Emp(Integer id, String ename, double salary, String date) { super(); this.id = id; this.ename = ename; this.salary = salary; this.date = date; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } @Override public String toString() { return "id=" + id + ", ename=" + ename + ", salary=" + salary + ", date=" + date; } }
c void main(String[] args) {
Emp emp1 = new Emp(1001, "张三", 80000, "2001.5.13"); Emp emp2 = new Emp(1001, "李四", 70000, "2005.5.13"); Emp emp3 = new Emp(1001, "王五", 15000, "2010.5.13"); List<Emp> list = new ArrayList<>(); list.add(emp1); list.add(emp2); list.add(emp3); for(Emp emp:list){ System.out.println(emp); } Map<Integer, Emp> map = new HashMap<>(); map.put(1001, emp1); map.put(1002, emp2); map.put(1003, emp3); Set<Integer> keyset = map.keySet(); for(Integer key:keyset){ System.out.println(map.get(key)); } }
}
class Emp{
private Integer id; private String ename; private double salary; private String date; public Emp(Integer id, String ename, double salary, String date) { super(); this.id = id; this.ename = ename; this.salary = salary; this.date = date; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } @Override public String toString() { return "id=" + id + ", ename=" + ename + ", salary=" + salary + ", date=" + date; }
}
## 第五章 IO技术 ## 第六章多线程技术 ## 第七章网络编程