Java基础1

单元1 搭建Java开发环境

任务1.1 安装JDK

1.1 Java的发展

1.2 Java的语言特性

  1. Java语言是一个面向对象的程序设计语言。
  2. 平台无关性-跨平台。
  3. Java语言是分布式的。
  4. Java支持多线程技术。
  5. Java语言是安全的。提供安全机制防止恶意代码攻击。安全防范机制(类ClassLoader)、安全管理机制(类SecurityManager)。

1.3 Java程序的运行流程

Java程序的运行必须通过编写、编译、运行三个步骤。

Java源程序文件*.java——java编译器——字节码文件/类文件*.class——java虚拟机中的解释器——运行

Java虚拟机JVM是运行Java程序的软件环境,Java解释器就是Java虚拟机的一部分。

Java应用程序开发离不开JDK和JRE,JDK是JAVA语言的编译环境,JRE是JAVA的运行环境。

JDK, JRE 和JVM的区别
(1)JRE是个运行环境,JDK是个开发环境,编写Java程序的时候需要JDK,而运行Java程序的时候就需要JRE。
(2)JDK=JRE+Java开发工具(编译器、调试器等);JRE=JVM+Java基础和核心类库。JDK和JRE都包含了JVM,从而使得我们可以运行Java程序。
(3)JVM是Java编程语言实现跨平台的核心并且具有平台独立性。

例题使用cmd运行:写一个Hello.java。然后编译javac Hello.java。最后运行java Hello。(注意文件路径,最好在路径下cmd)

任务1.2 使用开发工具Java

1.4 熟悉Eclipse开发环境

1.5 熟悉NetBeans开发环境

1.6 熟悉idea开发环境(主流)

单元2 Java语言基础

任务2.1 界面设计

2.1 标识符、关键字

1. 标识符

标识符用来表示变量、常量、类名、方法名、数组名、文件名等元素的名字。由字母、下画线、美元符号$的数字组成,并遵循一定的规则。

  1. 区分大小写。
  2. 不能以数字开头。
  3. 以字母、下画线或者$符号开头。
  4. 长度没有限制,最多可以标识65535个字符。
  5. 不能使用Java关键字。
2. 关键字

关键字是Java语言中已经被赋予特定意义的单词,也称保留字。系统事先定义的,对Java的编译器有特殊的作用。

abstractbreakbytebooleancatch
caseclasscharcontinuedefault
doubledoelseextendsfalse
finalfloatforfinallyif
importimplementsintinterfaceinstanceof
longlengthnativenewnull
packageprivateprotectedpublicreturn
switchsynchronizedshortstaticsuper
trytruethisthrowthreadsafe
voidwhilegoto(保留字)const(保留字)

**修饰成员变量volatile **
volatile:贡献变量,用于并发线程的共享,实现线程中的通信。在原子操作的情况下,当变量被volatile修饰时,线程每次使用时都会直接到内存中提取,不会去缓存。volatile 修饰符适用于以下场景:某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值;或者作为状态变量,如 flag = ture,实现轻量级同步。

volatile 属性的读写操作都是无锁的,它不能替代 synchronized,因为它没有提供原子性和互斥性。因为无锁,不需要花费时间在获取锁和释放锁上,所以说它是低成本的。
volatile 只能作用于属性,我们用 volatile 修饰属性,这样编译器就不会对这个属性做指令重排序。
volatile 提供了可见性,任何一个线程对其的修改将立马对其他线程可见。
volatile 提供了 happens-before 保证,对 volatile 变量 V 的写入 happens-before 所有其他线程后续对 V 的读操作。
volatile 可以使纯赋值操作是原子的,如 boolean flag = true; falg = false。
volatile 可以在单例双重检查中实现可见性和禁止指令重排序,从而保证安全性。

**修饰成员方法synchronized **
synchronized:控制多个并发线程的访问 防止冲突 实现同步。在多线程的环境下,多个线程同时访问共享资源会出现一些问题,而synchronized关键字则是用来保证线程同步的。

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
  4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
3. 分隔符

圆括号() 花括号{} 方括号[] 分号; 逗号, 句号.

2.2 数据类型

1. 整型

byte8位 short16位 int32位 long64位

//例2_1整型进制转换
public class Example2_1 {
    public static void main(String[] args) {
        byte a = 56; /* byte占8位(2^7~2^7-1) 以此类推*/
        System.out.println("hello world"+a);
        short b = 63;  /*short占16位*/
        System.out.println("hello world"+b);
        int c = 073; /* int占32位 073八进制数*/
        System.out.println(c);
        long d=0xa38f;  /*long占64位 0xa38f十六进制数*/
        System.out.println(d);
    }
}
2. 浮点类型

float32位 double64位
默认double类型,加F/f为float类型。

//例2_2正方形的面积
public class Example2_2 {
	public static void main(String[] args) {
		/* 浮点类型 */
		float a=4.0f;   /*占32位 加f为float类型*/
		double b = 3.0; /* 占64位 默认double类型*/
		double c=4.0;
		double d=b*c*a;
		System.out.println(d);
	}
}
3. 字符类型

char 转义字符"" 无符号16位
\n 换行、\t 制表符、\b退格、回车、\f换页、\反斜杠、‘单引号、"双引号、
\ddd 1~3位八进制数据所表示的字符’?‘,如’\356’
\uxxxx 十六进制的Unicode码字符’星图形’,如’\u2605’

4. 布尔类型

boolean 变量名;1位1/0

//例2_3布尔类型的使用
public class Example2_3 {
    public static void main(String[] args) {
        String a="123456"; /* 字符串类型 */
        char b='1';  /*字符类型 无符号16位 0-65536*/
        boolean c=true; /*布尔类型*/
        System.out.println(a+b); /*字符类型的连接*/
        System.out.println(c);

        //数据类型的转换 低级-高级(自动) 反之(强制)
        //低-高:(byte,short,char)-int-long-float-double

        // char-int
        char a1=(char)97;
        int b1='\u008a';
        int c1='a';
        System.out.println(a1);
        System.out.println(b1);
        System.out.println(c1);
        
        //instanceof关键字判断变量是否是目标类型 a instanceof int
        int i=1; //int类型变量
        System.out.println(getType(i)); //打印变量类型为int

	}
    public static String getType(Object o) { //获取变量类型方法
        return o.getClass().toString(); //使用int类型的getClass()方法
    }
}
5. 字符串类型

string 变量名;

6. 数据类型转换

低级-高级 自动:(byte short char)-int-long-float-double
高级-低级 强制:(目标数据类型)表达式

7. 引用数据类型

字符串、数组、类、接口等

2.3 常量和变量

1. 常量

final 类型 常量名=常量值

2. 变量

类型 变量名=变量初值

//例2_4常量和变量的使用
public class Example2_4 {

	//成员变量(类中)、局部变量(类的方法中)
	//static关键字-静态变量\静态方法\代码块\嵌套类
	//用final定义常量
    static final double PI=3.14; //静态常量,必须赋初值
	static int member=23;  //静态变量 ,赋初值
	public static void main(String[] args) {
		final int part=123;
		member=24;
		System.out.println(part*member*PI);
	}
}

3. 变量的有效范围

成员变量:在整个类体中都有效。分为静态成员变量(加static)、实例变量。
局部变量:只在方法体类中有效。

package chap2.task2_1;
//例2_5声明静态成员变量和实例变量
public class Example2_5 {

	//成员变量 在整个类中有效, 局部变量在方法中有效
	int x=1; /*实例变量*/
	static int y = 234; /* 静态变量 static*/
}

class print{
	public static void main(String[] args) {
		//定义时使用static 直接通过类名调用,成员变量或方法。但在static静态方法中,只能调用用这种方式静态的变量方法
		System.out.println(Example2_5.y);
		//没有static 需要实例化调用
		System.out.println(new Example2_5().x);
	}
}

2.4 数据操作

1. 运算符

运算符是描述数据运算的符号。它们有相应的优先级、类型、结合性。

2. 算术运算符

算术运算符用于整数类型和浮点数类型。

运算符含义
++自增
自减
+加(或取正)
-减(或取负)
*
/
%取余
//例2_6算术运算测试示例
public class Example2_6 {
	public static void main(String args[]) {
		int a = 5 + 4; // a=9
		int b = a * 2; // b=18
		int c = b / 4; // c=4 浮点数中除数为0,结果为NaN(非数),整数中报错
		int d = b - c; // d=14
		int e = -d; // e=-14 负数
		int f = e % 4; // f=-2 负数求余
		double g = 18.4;
		double h = g % 4; // h=2.4 浮点数求余
		int i = 3;
		int j = i++; // i=4��j=3 先赋值再自增
		int k = ++i; // i=5��k=5 先自增再赋值
		System.out.println("a=" + a);
		System.out.println("b=" + b);
		System.out.println("c=" + c);
		System.out.println("d=" + d);
		System.out.println("e=" + e);
		System.out.println("f=" + f);
		System.out.println("g=" + g);
		System.out.println("h=" + h);
		System.out.println("i=" + i);
		System.out.println("j=" + j);
		System.out.println("k=" + k);
	}
}
3. 关系运算符

整数或浮点数的关系运算符是比较数的大小,字符型数据的是比较其Unicode码的大小。boolean值只能进行==或!=比较。

运算符含义
>大于
>=大于等于
<小于
<=小于等于
==等于
!=不等于
//例题2_7关系运算符使用实例
public class Example2_7 {
	public static void main(String[] args) {
		int n = 3;
		int m = 4;
		System.out.println();
		System.out.println("n<m is " + (n < m)); //结果True
		System.out.println("n=m is " + ((++n) == m)); //结果True
		System.out.println("n>m is " + ((++n) > m)); //结果True
		System.out.println("n is " + n); //n经过了两次自增

		//boolean类型只能进行==或!=比较
	}
}
4. 逻辑运算符

逻辑运算符针对布尔类型数据。!是一元运算符,其余全是二元运算符。

运算符含义
&非简洁与AND
|非简洁或OR
^逻辑异或XOR
逻辑非NOT
&&条件与AND
||条件或OR
//例题2_8逻辑运算使用示例
public class Example2_8 {

    public static void main(String[] args) {
        int a = 3;
        int b = 4;
        boolean result1 = (a > b) && (a != b); //条件与and
        boolean result2 = (a > b) || (a != b); //条件或or
        System.out.println(result1);
        System.out.println(result2);
        // 测试短路现象
        boolean result3 = (a < b) || ((a = 5) > b); //条件或or
        System.out.println(result3 + ",a=" + a + ",b=" + b); //结果通过+变量+拼接
        // 标准逻辑运算符没有短路现象
        boolean result4 = (a < b) | ((a = 5) > b); //非简洁或or 这里出现了赋值
        System.out.println(result4 + ",a=" + a + ",b=" + b);
    }
}
5. 位运算符

位运算操作数只能是整型和字符型,除了"~"外,其余均为二元运算符。

运算符含义
~按位取反
<<按位左移
>>按位右移
>>>无符号按位右移
&按位与
^按位异或
|按位或
//例题2_9位运算使用示例
public class Example2_9 {
	public static void main(String[] args) {
		int a = 3;
		int b = 4;
		// 先把数据变成二进制
		System.out.println(a & b); //按位与,一0即0
		System.out.println(a | b); //按位或,一1即1
		System.out.println(a ^ b); //按位异或,同为0,异为1
		System.out.println(b << 2); //按位左移2位
		System.out.println(b >> 2); //按位右移2位

		//条件运算符-三元运算
		int a1=1,b1=2,c1;
		c1=a1>b1?a1:b1;
		System.out.println(c1);

		//赋值运算符-等号 左变量 右表达式
		int a2;
		a2=5+3/2;
		System.out.println(a2);

	}
}
6. 条件运算符

语法格式:
表达式1?表达式2:表达式3

7. 赋值运算

简单:= 左变量 右表达式
复合:+=、-=、*=、/=、%=、&=、|=、^=。

2.5 表达式与语句

1. 表达式

表达式是由变量、常量、对象、方法调用和操作符等元素的有效组合。
Java中除了表达式语句,还有声明语句(声明变量的数据类型)和流程控制语句(控制语句的执行顺序)。

//例题2_10计算圆的面积和周长
public class Example2_10 {
	public static void main(String[] args) {
		double r = 8.5; // 赋值语句
		double length, area; // 声明语句
		length = 2 * Math.PI * r; //Math类库的常量PI
		area = Math.PI * r * r;
		System.out.println("圆周长为:" + length);// 方法调用语句
		System.out.println("圆面积为:" + area);

		//java中除了表达式语句,还有声明语句和流程控制语句
	}
}
2. 语句

Java程序由语句组成,每一个语句是一个完整的执行单元,以分号";"结尾。

3. 语句块和作用域

语句块由一对{}以及其中的语句组成。每个语句定义了一个作用域。

//例题2_11定义变量i和语句块内的局部变量j,观察i和j不同的作用域
public class Example2_11 {

	public static void main(String[] args) {
		int i = 0;
		//语句块{}和作用域
		{
			int j = 0;
			System.out.println(i+"\n"); // 语句块外定义的变量在语句块内具有可见性
			System.out.println(j); //转义字符以\开头,\n为换行符
		}
		i = 5;
		// j = 10; //j不可使用,语句块内定义的变量在语句块外不具有可见性
	}
}

任务2.2 用户类型选择

2.6 基本程序结构

控制结构的作用是控制程序中语句的执行顺序,它是结构化程序设计的关键。
Java语言有三种基本的流程控制结构:顺序结构、分支结构、循环结构。

2.7 if语句

if(条件表达式){
语句块1
}else if(条件表达式2){
语句块2
}else{
语句块3
}

//例题2_12采用三种if形式,判断某一年是不是闰年
public class Example2_12 {
	public static void main(String args[]) {
		// 第一种形式
		int year = 2000;
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
			System.out.println(year + " is a leap year.");
		} else {
			System.out.println(year + " is not a leap year.");
		}
		// 第二种形式 闰年-能被4和400整除,不能被100整除,一真即真。
		year = 2011;
		boolean leap;
		if (year % 4 != 0) {
			leap = false;
		} else if (year % 100 != 0) {
			leap = true;
		} else if (year % 400 != 0) {
			leap = false;
		} else {
			leap = true;
		}
		if (leap == true) {
			System.out.println(year + " is a leap year.");
		} else {
			System.out.println(year + " is not a leap year.");
		}
		// 第三种形式
		year = 2012;
		if (year % 4 == 0) {
			if (year % 100 != 0) {
				leap = true;
			} else if (year % 400 == 0) {
				leap = true;
			}
		} else {
			leap = false;
		}
		if (leap == true) {
			System.out.println(year + "  is a leap year.");
		} else {
			System.out.println(year + "  is not a leap year.");
		}
	}
}

2.8 switch语句

switch(表达式){
case ‘常量1’:
语句块1
break
case ‘常量2’:
语句块2
break

default:
结尾语句块
}

//例题2_13switch语句的使用示例(注意其中break语句的作用)
//判断输入的值是否为闰年,确定二月天数。
public class Example2_13 {
	public static void main(String[] args) {
		int year;
		int month;
		int days = 0;
		System.out.print("请输入年份和月份:");

		Scanner in = new Scanner(System.in); // 从键盘输入年份和月份数据 调用Scanner函数对象
		year = in.nextInt();
		month = in.nextInt();

		switch (month) {
			case 2: // 判断是否闰年,确定2月份天数
				if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
					days = 29; //是闰年
				else
					days = 28; //不是闰年
				break;

			case 4:
			case 6:
			case 9:
			case 11:
				days = 30;
				break;

			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
			case 12:
				days = 31;
				break;
			default:
				System.out.println("月份数据非法!");
		}
		System.out.println(year + "年" + month + "月有" + days + "天");
	}
}

任务2.3 租金计算

2.9 for循环语句

for(表达式1;表达式2;表达式3){
循环体
}

//例题2_14计算1到10的平方,并输出这10个数得平方和。使用for循环
public class Example2_14 {
	public static void main(String[] args) {
		int sum = 0;
		int temp;
		for (int i = 1; i <= 10; i++) {
			temp = i * i;
			System.out.print(temp + " ");  //使用+ " "让每个值之间有一个空格距离
			sum += temp;
		}
		System.out.println(); //输出空内容,起到换行作用。
		System.out.println(sum);
	}
}

2.10 while循环语句

语句格式:
while(条件表达式){
循环体
}

//例题2_15计算1到10的平方,并输出这10个数得平方和。使用while循环
public class Example2_15 {
	public static void main(String[] args) {
		int sum = 0, i = 1, temp;
		while (i <= 10) {
			temp = i * i;
			System.out.print(temp + " ");
			sum += temp;
			i++; // 改变循环控制变量值
		}
		System.out.println();
		System.out.println(sum);
	}
}

2.11 do-while循环语句

语句格式:
do{
循环体;
}while(条件表达式);

//例题2_16计算1到10的平方,并输出这10个数得平方和。使用do while循环
public class Example2_16 {
	public static void main(String[] args) {
		int sum = 0, i = 1, temp;
		do {
			temp = i * i;
			System.out.print(temp + " ");
			sum += temp;
			i++;
		} while (i <= 10);
		System.out.println();
		System.out.println(sum);
	}
}

2.12 跳转语句

break continue

//例题2_17在循环中使用break语句
public class Example2_17 {
	public static void main(String[] args) {
		int x = 1;
		while (x < 10) {
			System.out.println(" 进入循环,x的初始值为:" + x);
			switch (x) {
				case 0:
					System.out.println(" 进入switch语句,x=" + x);
					break;
				case 1:
					System.out.println(" 进入switch语句,x=" + x);
					break;
				case 2:
					System.out.println(" 进入switch语句,x=" + x);
					break;
			}
			if (x == 5) {
				break; //使用break终止循环的执行
			}
			x++;
			System.out.println(" 跳出switch语句,但还在循环中.");
		}
	}
}
//例题2_18break语句和continue语句的使用示例
public class Example2_18 {
	public static void main(String[] args) {
		String output = "";
		int count;
		for (count = 1; count <= 10; count++) {
			if (count == 4) {
				continue;
			}
			if (count == 9) {
				break;
			}
			//count是int类型,output是string类型。  int类使用+“ “转换成string类型 用” “拼接
			output += count++ + " ";
		}
		output += "\nBreak out of loop count at count =" + count; //循环内拼接完,一次输出。
		System.out.println(output);
	}
}

2.13 for增强型语句

遍历数组 for(初始变量 : 数组名){}

//例题2_19使用foreach语句对数组进行遍历。
public class Example2_19 {
	public static void main(String []args)
	{
		int arr[]={1,2,3,4,5}; //定义一个一维数组
		System.out.println("一维数组中的元素分别为:");
		//for增强型语句,称为foreach,任何foreach可改为for
		for(int a :arr)
		{
			System.out.println(a+"\n");  //每一个输出语句中末尾都有一个\n
		}
	}
}

任务2.4 多用户租金计算

2.14 一维数组的创建和使用

1. 一维数组的创建和声明

数组是由一组类型相同的元素组成的有一定存储顺序的数据集合。

使用数组两个步骤:定义声明、创建数组,为数组分配内存单元。

  1. 方法一

数组定义格式:
数组元素类型 数组名[];
数组元素类型 [] 数组名;

数组创建对象,分内存单元:
数组名=new 数组元素类型[数组元素个数];

  1. 方法二

数组定义格式+数组创建对象,分内存单元:
数组元素类型 数组名[]=new 数组元素类型[数组元素个数];
数组元素类型 [] 数组名=new 数组元素类型[数组元素个数];

  1. 方法三

数组元素类型 数组名[]={值1,值2.值3,……};

2. 一维数组的初始化

数组的初始化分为静态初始化和动态初始化。

静态初始化:
int a[]={1,2,3,4,5};
动态初始化:
int a[]=new int[5];
for(int i=0;i<5;i++){
a[i]=i;
}

  1. 基本数据类型的数组

数组中存放的是基本类型数据,则为数组元素分配内存空间后,直接赋初始值。
int a[]=new int[5];
for(int i=0;i<5;i++){
a[i]=i;
}

  1. 复合数据类型的数组

数组中存放的是复合或引用类型数据,则为数组元素分配内存空间后,还需为每个数组元素单独分配内存空间。
String s[];
s=new String[3]; //为数组元素分配内存空间
s[0]=new String(“How”); //为数组第一个元素分配内存空间
s[1]=new String(“are”);
s[2]=new String(“you”);

3. 数组元素的访问使用

语法格式:数组名[下标] 备注:下标必须是整数或转变成整型的量,下标从0开始。
Java数组即是一个对象,数组有一个重要属性——长度length。语法格式:数组名.length

//例题2_20声明一个整型数组并对它初始化,输出各元素的值和其总和。
public class Example2_20 {
	public static void main(String args[]) {
		//静态初始化
		int a[] = { 1, 2, 3 }; // 定义、创建、初始化数组
		int i, sum = 0;

		for (i = 0; i < a.length; i++)
			sum = sum + a[i]; // 获取数组元素并进行累加

		for (i = 0; i < a.length; i++)
			System.out.println(" a["+ i +"]=" + a[i]); // 获取数组元素并输出其值  " + i + "在字符串中嵌套输出变量
		System.out.println(" sum=" + sum);

		//动态初始化
		int b[]; //定义一个数组变量
		b=new int[6]; //创建数组对象,分配内存单元。
		for (int j = 0; j < 6; j++) {
			b[j]=j;
			System.out.println(b[j]);
		}
	}
}
//例题2_21使用冒泡排序法,对已经数据从小到大排序。
public class Example2_21 {
	public static void main(String args[]) {
		int i, j;
		int intArray[] = { 4, 1, 5, 8, 9 };
		int len = intArray.length;

	/*	//循环实现冒泡排序-两两对换   每次找出最大值。
		for(i=0;i<intArray.length-1;i++) {

			for(j=0;j<intArray.length-i-1;j++) {

				if(intArray[j]>intArray[j+1]) { //改变>或<符号,改变排序
					int temp=intArray[j];
					intArray[j]=intArray[j+1];
					intArray[j+1]=temp;
				}

			}

		}*/

		for (i = 0; i < len - 1; i++)
			for (j = len - 1; j > i; j--)  //这里是数组最后一个数开始两两比较。

				if (intArray[j - 1] > intArray[j]) {
					int t = intArray[j - 1];
					intArray[j - 1] = intArray[j];
					intArray[j] = t;
				}
		//增强型for循环,遍历数组。
		for(int k:intArray){
			System.out.println(k + " ");
		}
	}
}

//对数组元素进行查询,如果能找到,输出该元素的位置
public class Example2_22 {
	public static void main(String[] args) {
		int b = 46;
		int index = 0;
		int a[] = { 23, 56, 78, 12, 34, 90, 46, 22, 14, 79 };
		for (int i = 0; i < 10; i++) {
			System.out.print("\t" + a[i]);
			if (b == a[i])
				index = i;
		}
		System.out.print("\n");
		System.out.print("找到了该数,位置在第:" + (index + 1 + "号!")); //因为下标从0开始。
	}
}

2.15 多维数组的创建和使用

多维数组看做数组的数组,常用于二维表。

语法格式:
数组元素类型 数组名[][];
数组元素类型[][] 数组名;

使用new运算符有两种方式:

  1. 用一条语句为整个二维数组分配空间。

int a[][]=new int[2][3];

  1. 先指定二维数组的行数,再分别为每一行指定列数。

int b[][]=new int[2][];
b[0]=new int[3];
b[1]=new int[3];

不要求每一行的元素个数相等,可以形成不规则的数组,空处不会默认补0。
int b[][]=new int[2][];
b[0]=new int[3];
b[1]=new int[10];

可以不用new运算符,可以用初始化,定义数组并创建对象。
int a[][]={{1,2,3},{4,5,6}}; //规则二维数组
int a[][]={{1,2,3},{4,5,6,7}}; //不规则二维数组

访问格式:
数组名[行下标][列下标] 备注:行小标、列下标都是从0开始。

数组名.length 表示数组的行数
数组名[行下标].length 表示该行中的元素的个数。

//例题2_23定义一个不规则的二维数组,输出其行数的元素个数,并求数组所有元素的和
public class Example2_23 {
	public static void main(String args[]) {
		int b[][] = { { 11 }, { 21, 22 }, { 31, 32, 33, 34 } };
		//System.out.println(b[0][1]); //空出部分不会自动补0
		int sum = 0;
		System.out.println("数组b的行数:" + b.length);
		for (int i = 0; i < b.length; i++) {
			System.out.println("b[" + i + "]行的数据个数:" + b[i].length);
			for (int j = 0; j < b[i].length; j++) {
				sum = sum + b[i][j];
			}
		}
		System.out.println("数组元素的总和:" + sum);
	}
}

//例题2_24定义一个一维数组存储10个学生名字,定义一个二维数组存放这10个学生的6门课的成绩
public class Example2_24 {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		//复合类型的数组
		String[] name = { "lili", "tom", "jack", "susan", "wendy", "tommy", "neil", "paul", "richie", "roger" };// 存储学生的名字
		int[][] grade = { { 50, 60, 70, 80, 90, 10 },
				{ 40, 90, 80, 60, 40, 70 }, { 60, 80, 70, 60, 40, 90 },
				{ 50, 60, 70, 80, 90, 10 }, { 60, 80, 70, 60, 40, 90 },
				{ 60, 70, 80, 90, 70, 70 }, { 60, 80, 70, 60, 40, 90 },
				{ 60, 80, 70, 60, 40, 90 }, { 70, 80, 90, 70, 70, 70 },
				{ 60, 80, 70, 60, 40, 90 } };// 存储学生各科成绩

		System.out.println("输入要查询成绩的学生名字:");
		String chioce = input.nextLine(); //输入字符串
		for (int i = 0; i < 10; i++) {
			//配对输入值是谁
			if (name[i].equals(chioce)) {
				System.out.println("学生:" + name[i] + " 的成绩如下:");
				System.out.println("C程序设计:" + grade[i][0] + "物理:"
						+ grade[i][1] + "英语:" + grade[i][2] + "高数:"
						+ grade[i][3] + "体育:" + grade[i][4] + "政治:"
						+ grade[i][5] + "\n");
				break;
			}
		}
		System.out.println("******************************************************");

		System.out.println("输入要查询不及格人数的科目序号\n");
		System.out.println("1,C程序设计 2,物理  3,英语  4,高数  5,体育  6,政治 ");
		int ch = input.nextInt(); //输入int类型。
		int time = 0;
		System.out.println("不及格的名单为:");
		for (int i = 0; i < 10; i++) {
			if (grade[i][ch - 1] < 60) {
				time++;
				switch (i) {
					case 0: System.out.println(name[i]);
						break;
					case 1: System.out.println(name[i]);
						break;
					case 2: System.out.println(name[i]);
						break;
					case 3: System.out.println(name[i]);
						break;
					case 4: System.out.println(name[i]);
						break;
					case 5: System.out.println(name[i]);
						break;
					case 6: System.out.println(name[i]);
						break;
					case 7: System.out.println(name[i]);
						break;
					case 8: System.out.println(name[i]);
						break;
					case 9: System.out.println(name[i]);
						break;
				}
			}
		}
		System.out.println("该科目不及格人数为:" + time);
	}
}

单元3 面向对象程序设计

任务3.1 财务信息类设计

3.1 面向对象基础知识

面向对象:从现实世界中客观存在的事物(即对象)出发构造软件系统,尽可能运用人类的自然思维方式,使计算机语言对事物的描述和现实世界该事物的本来面目一致。
类、对象就是面向对象方法的核心观念。

类:具有相同属性和服务/行为的一组对象的集合。内部包括属性和行为。
对象:描述客观事物的一个实体,构成系统的一个基本单位。由一组属性和操作这一属性的行为组成。
类的实例化是对象,一组对象的抽象是类。

Java语言中,类是一种最基本的复合数据类型,是组成Java程序的基本要素。
Java类包含变量定义(对象的属性)和方法定义(对象的行为/操作)
Java类支持面向对象(OOP)三个基本特征:封装、继承、多态。

封装:把对象的属性和服务结合成一个独立的相同单位,隐蔽对象的内部细节。

继承:特殊类的对象拥有其一般类的全部属性与操作,称为特殊类对一般类的继承。Java原因只支持单继承,不允许多继承,但可以使用接口实现模拟多继承。

多态:一般类被特殊类继承后,可以具有不同的数据类型或表现出不同的行为。多态的概念比较简单, 就是同一操作作用于不同的对象, 可以有不同的解释, 产生不同的执行结果。
多态性有静态多态和动态多态,分别用方法重载和方法重写。
静态多态-运行:有类继承或者接口实现、 子类要重载父类的方法、 父类的引用指向子类的对象。
动态多态-编译: 子类要重写父类的方法。

//例题3_1声明一个Person类
class Person { // 定义类Person
	private String name; // 私有成员变量,表示姓名
	public void setName(String n) { // 公有方法
		name = n;
	}
	public String getName() {  //公有方法
		return name;
	}
}

3.2 类的定义

定义类就是创建一个新的数据类型,利用定义的类可以定义类实例-创建一个对象。

//例题3_2为Person类声明一组成员变量
class Person1 { // 定义类Person
	String name; // 定义成员变量name
	char sex; // 定义成员变量sex
	int age; // 定义成员变量age
}

1. 类定义格式及说明

类相当于面向过程语言中的结构体
[public][abstract | final] class clasName [extend superclass][implements interfaceNamList] {
//成员变量
[public | protected | default | private][static] [final][transient] [volatile] type variableName;
//成员方法
[public | protected | default | private][static] [final | abstract][native] [synchronized] returnType methodName(paramList) [throws exceptionList]
{
//方法主体
Statements
}
}

2. 类的成员变量

成员变量定义了类的属性。
不对成员变量赋初值,系统会自动赋默认值。

3. 类的成员方法

成员方法描述了对象所具有的功能或操作。相当于过去所说的子程序、函数。

//例题3_3为Person类声明一个成员方法
class Person3 { // 定义类Person
	String name; // 定义成员变量name
	char sex; // 定义成员变量sex
	int age; // 定义成员变量age
	// 定义方法sayHello
	public void sayHello() {
		System.out.println("Hello!"); // 在控制台打印"Hello!"
	}
}

3.3 对象的创建

1. 创建对象

声明格式为:类名 对象名=new 类名()

2. 访问对象的属性和行为

使用格式为:对象名.对象成员
同类的对象可以进行赋值,称为对象赋值。

//例题3_4设计类Number,测试对象间的赋值。
public class Number {
	int i;
	public static void main(String[] args) {
		Number n1 = new Number();
		Number n2 = new Number();
		n1.i = 9;
		n2.i = 47;
		System.out.println("n1.i=" + n1.i + "\t\t" + "n2.i=" + n2.i);
		n1 = n2; //通过对象赋值后,n1 n2其实是一个对象,所以改变一个,另一个自动跟着变。
		System.out.println("n1.i=" + n1.i + "\t\t" + "n2.i=" + n2.i);
		n1.i = 27;
		System.out.println("n1.i=" + n1.i + "\t\t" + "n2.i=" + n2.i);
	}
}

任务3.2 使用static设计财务信息类

3.4 类的访问修饰符

Java语言中访问权限控制符(访问控制修饰符)有四个:public、protected、default、private。定义类时,访问控制修饰符只有一个public。

每个Java程序的主类必须是public类,主类名=文件名。子类没有public,[其他修饰符] class 类名。

访问控制修饰符:主要用于定义类及其成员的作用域。如在哪些范围内访问类及其成员。
类型说明符:主要用于定义类及其成员的一些特殊性质。如是否可以被修改。

能修饰类class的修饰符有:

[public][abstract | final]
public:用public修饰的类或成员拥有公共作用域。
abstract:抽象类,不能被new,没有方法体。
final:方法不能被重写。

能修饰成员变量的修饰符有:

[public | protected | default | private][static] [final][transient] [volatile]
public:用public修饰的类或成员,拥有公共作用域。
protected:用protected修饰的类或成员,拥有受保护作用域,只能被同一个包中所有类及其子类访问。
default:只能被同一包同一类中访问。
private:用private修饰的类或成员,拥有私有作用域,只能在此类中访问。
static:静态变量(类变量),相对于实例变量。
final:常量,其值不能被改变。
transient:暂时性变量,用于对象存档。
volatile:贡献变量,用于并发线程的共享。在原子操作的情况下,当变量被volatile修饰时,线程每次使用时都会直接到内存中提取,不会去缓存

能修饰成员方法的修饰符有:

[public | protected | default | private][static] [final | abstract][native] [synchronized]
public:用public修饰的类或成员,拥有公共作用域。
protected:用protected修饰的类或成员,拥有受保护作用域,只能被同一个包中所有类及其子类访问。
default:只能被同一包同一类中访问。
private:用private修饰的类或成员,拥有私有作用域,只能在次类中访问。
static:类方法,可以通过类名直接调用。
final:方法不能被重写。
abstract:抽象方法,没有方法体。
native:集成其他语言的代码。
synchronized:控制多个并发线程的访问 实现同步。

//例题3_5测试成员变量修饰符的作用
//FieldTest类,子类,没有任何修饰符,默认访问权限,可以在同包下其他类访问
class FieldTest {
	//private int num = 5;// 私有作用域,本类可见
	//public int num = 5;// 工共作用域,所有包/类可见
	protected int num = 5;// 受保护作用域,同包/同类/不同类可见

	public int get() { // 公共作用域,get 方法返回成员变量num的值
		return num;
	}
}

//主类,每个Java程序的主类必须是public,主类名=文件名
public class Example3_5 {
	//子类中的输出类-静态方法
	public static void main(String[] args) {
		FieldTest ft = new FieldTest();
		int t = ft.get(); // 正确访问
		int s=ft.num; //不能访问FieldTest类中私有成员变量num
		System.out.println("t=" + t);
		System.out.println("s="+s);
	}
}

3.5 访问权限

访问控制修饰符:主要用于定义类及其成员的作用域。如在哪些范围内访问类及其成员。
没有使用任务修饰符的,拥有默认访问权限(友好访问权限),可以被同包下的其他类访问。
成员的作用范围受到类的作用范围的限制。
缺省=deault默认范围
image.png

3.6 static修饰符

使用static修饰的变量和方法,称为类变量(静态变量)和类方法(静态方法)。没有用,称为实例变量和实例方法。

类成员(静态成员)属于这个类(即类中所有对象共同拥有),实例成员由每个独享个体独有。

对于实例成员:只能通过对象来访问,不能通过类名进行访问。
对于类成员:在静态方法中,只能调用同类中其他静态成员(变量和方法),不能直接访问类中的非静态成员。在实例方法中,即可访问实例成员,也可访问类成员。

成员变量中必须有类型和变量名,成员方法中必须有类型和方法名(),类中必须有class和类名。

为什么main是static修饰?
static静态方法是存储在静态存储区内的,可以通过类.方法名直接进行调用,不需要进行实例化。
假设不使用static,那么main()方法在调用时必须先对其实例化,而main()做为程序的主入口显然不可能先对其实例化,
所以使用static修饰,可以更方便的直接用类.main()对其调用。

//例题3_6测试对实例成员和类成员的不同访问方式——静态变量使用示例
// Count子类  没有任何修饰符,默认访问权限,可以在同包下其他类访问
class Count {
	private int serial; // 实例变量
	static int counter = 0; // 类变量
	
	/**成员变量中必须有类型和变量名,成员方法中必须有类型和方法名(),类中必须有class和类名*/
//	//Count(){}=语句块功能
//	Count() {
//		counter++; // 实例计数器
//		serial = counter;
//	}

	//语句块{}代替
	{
		counter++; // 实例计数器
		serial = counter;
	}
	int getSerial() {
		return serial;
	}
	int getCounter() {
		return counter;
	}
}

public class Example3_6 {
	//在类方法(静态方法)中,不能直接访问类中的非静态成员
	//为什么main方法必须是static,因为main方法是程序入口点,执行main方法,此时是没有对象的。
	//因此main方法不可能是实例方法

//	static静态方法是存储在静态存储区内的,可以通过类.方法名直接进行调用,不需要进行实例化。
//	假设不使用static,那么main()方法在调用时必须先对其实例化,而main()做为程序的主入口显然不可能先对其实例化,
//	所以使用static修饰,可以更方便的直接用类.main()对其调用。
	
	public static void main(String args[]) {
		Count c1 = new Count();
		Count c2 = new Count();
		System.out.println("c1的serial值:" + c1.getSerial()); // 1
		System.out.println("c1的counter值:" + c1.getCounter());
		System.out.println("c2的sSerial值:" + c2.getSerial()); // 2
		System.out.println("c2的counter值:" + c2.getCounter());
		// System.out.println("类的serial值:"+Count.serial()); //不能通过类名访问非静态变量
		System.out.println("类的counter值:" + Count.counter); // 通过类名访问静态变量
	}
}
//例题3_7测试类变量与实例变量的使用区别
public class Example3_7 {
	int i = 0; //实例变量
	static int j = 0; //类变量(静态变量) 是等程序结束时才释放静态存储区。

	public void print() {
		System.out.println("i=" + i);
		System.out.println("j=" + j);
	}

	public static void main(String[] args) {
		Example3_7 sv1 = new Example3_7();
		sv1.i++;
		sv1.j++;
		sv1.print();
		Example3_7 sv2 = new Example3_7();
		sv2.print();
	}
}

任务3.3 使用构造方法设计财务信息类

3.7 方法重载

同一个类中的两个及以上的方法可以有同一名字,只要它们参数声明不同即可。该方法称为重载,该过程称为方法重载。

作用:在一个类中,多个方法同名不同参数列表,实现多个不同的功能。

3.8 构造方法

每个类都有构造方法,它是类的一种特殊方法,构造方法的名字和类名字完全相同。分为无参构造/有参构造。
对象的创建是通过构造方法完成的,当类实例化一个对象时,类会自动调用构造方法。

基本特点:没有返回值,不用viod。名称=类名。方法可以重载。不能由用户直接调用,只能使用new对象时系统自动调用。

类的构造方法不要求必须定义。没有明确时,Java会自动默认构造一个无参构造方法。

//例题3_8方法重载示例
public class Example3_8 {
	public static void print(String str) {
		System.out.println("String=" + str);
	}

	public static void print(int i) {
		System.out.println("int=" + i);
	}

	public static void print(float i) {
		System.out.println("float=" + i);
	}

	public static void main(String[] args) {
		print("123"); //	通过方法名,直接调用类方法
		print(123);
		print(1.23f);
	}
}
//例题3_9构造方法声明示例
public class Point2D {
	private int x;
	private int y;

	// 定义无参构造
	public Point2D() {
	}

	// 定义带两个参数的构造方法
	public Point2D(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}
}
//例题3_10定义一个水果类——类的构造方法示例
public class Fruit {
	public String color; // 定义颜色成员变量

	// 定义构造方法
	public Fruit() {
		color = "绿色"; // 对变量color进行初始化
	}

	public void harvest() { // 定义收获的方法  重载构造方法
		String color = "红色"; // 定义颜色局部变量
		System.out.println("水果是:" + color + "的!");
		System.out.println("水果已经收获……");
		System.out.println("水果原来是:" + this.color + "的!");
	}

	public static void main(String[] args) {
		// 声明Fruit类的一个对象fruit,并为其分配内存  对象声明-对象实例化
		Fruit myfruit = new Fruit();
		myfruit.harvest(); // 调用Fruit类的harvest()方法
	}
}

3.9 关键字this

this关键字代表引用自身对象,访问本类的成员变量和方法。
语句格式:
this.成员变量名
this.方法名(实参列表)

1. 使用this关键字引用成员变量

参数a的作用范围为构造方法或方法内部。成员变量a的作用范围时类内部。
当变量作用范围重叠时,作用范围小的覆盖作用范围大的。
如果变量名不发生重叠,可以省略this。

//例题3_11this引用成员变量
public class ThisDemo1 {
	private int a; //定私有作用域的成员变量a

	public ThisDemo1(int a) {
		this.a = a; // this.a表示引用该类的成员变量
	}

	public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}

//	参数a的作用范围为构造方法或方法内部。成员变量a的作用范围时类内部。
//	当变量作用范围重叠时,作用范围小的覆盖作用范围大的。
//	如果变量名不发生重叠,可以省略this。
}
2. 使用this关键字在自身构造方法内部引用其他构造方法

this(0)调用本类中的其他构造方法,其中0是根据需要传递的参数类型的值。
调用的代码只能出现在自身构造方法内部的第一行。这样使用最多只有一次。

//例题3_12this引用构造方法
public class ThisDemo2 {
	int a;
	int b;
	public ThisDemo2() {
		this(0,'0'); // this(0)调用本类中的其他构造方法
	}

	public ThisDemo2(int a) {
		this.a = a;
	}

	public ThisDemo2(int a,int b) {
		this.a = a;
		this.b = b;
	}

	public ThisDemo2(int a,char b) {
		this.a = a;
		this.b = b;
	}
}
3. 使用this关键字代表自身类的对象

this代表自身对象

4. 使用this关键字引用成员方法

this引用成员方法 this.方法名(参数)

//例题3_13this引用自身和成员方法
public class ThisDemo3 {
	ThisDemo3 instance; //定义声明对象 创建一个对象=实例化/初始化一个类

	public ThisDemo3() {
		instance = this; // this代表自身对象
		this.test(); // this引用成员方法
	}

	public void test() {
		System.out.println(this); //输出自身对象
	}

	public static void main(String[] args) {
		ThisDemo3 thisDemo3=new ThisDemo3(); //在实例化过程中,自动调用无参/有参构造
	}
}

单元4 继承与多态

任务4.1 求租客户信息类设计

4.1 继承的概念

定义:类继承又称类派生。当B类继承A类时,B类具有A类的全部属性和方法,又具有自己特有的属性和方法。
被继承类A:基类、父类、超类。
继承类B:派生类、子类。

//圆的子类Circle
public class Circle extends Shape {
	double radius; // 定义自己的成员变量

	public double getRadius() { // 定义自己的成员方法
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}

	public double getArea() {
		double area = Math.PI * radius * radius; // 计算圆的面积
		return area;
	}

	public double getPerimeter() {
		return 2 * Math.PI * radius; // 计算并返回圆的周长
	}
}
//父类图形类Shape
public class Shape {
	String type; // 类别

	public void setType(String type) { // 成员方法,设置其图形类型
		this.type = type;
	}

	public String getType() {
		return type;
	}
}
//例题4_1求图形的面积和周长
public class TestCircle {
	public static void main(String[] args) {
		Circle myShape = new Circle();
		myShape.setType("圆"); // 调用超类的方法
		myShape.setRadius(5.2); // 调用子类的方法
		System.out.println("myShape的类别是:" + myShape.getType());
		double area = myShape.getArea();
		System.out.println("myShape的面积是:" + area);
		System.out.println("myShape的周长是:" + myShape.getPerimeter());
	}
}

4.2 继承的实现

语句格式:
[修饰符] class 子类名 extends 父类名 {
//定义新的属性
//重新定义父类中已有的属性
//定义新的成员方法
//重写父类中成员方法
}

补充说明:
类java.long.Object是一切类的父类或根类,为万类之源。
类继承,Java只支持继承,可通过使用接口机制来实现多重继承。

//父类_员工类
public class Employee {
	//成员变量
	int employeeID; //职工号
	String name; //职工姓名
	String address; //住址
	double pay; //工资
	//成员方法
	public Employee() {
		super();
	}
	
	public double getPay() {
		//计算职工工资
		return this.pay;
	}

	// get和set方法
	public int getEmployeeID() {
		return employeeID;
	}

	public void setEmployeeID(int employeeID) {
		this.employeeID = employeeID;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public void setPay(double pay) {
		this.pay = pay;
	}
}
//例题4_2设计并实现公司的职工类
//子类_管理者类
class Manager extends Employee{
	//新增自己的成员变量
	String response;   //职责
	String department;  //所在部门
	//定义自己的成员方法
	public void upPay(double p){
		pay=pay+p;  //这里的pay是Emplyee的变量
	}
	//由于管理者和普通职工计算工资方法不同,根据需要重新定义getPay()方法
	public double getPay()  { //计算管理者工资
		return this.pay*1.5;
	}

	//测试
	public static void main(String[] args) {
		Manager manager=new Manager();
		manager.upPay(100.0);
		System.out.println(manager.getPay());
	}
}

4.3 继承的规则

声明了直接子类继承直接父类,除构造方法外,子类可继承父类所有的变量和方法。
是否能访问,还要看其访问修饰符的控制范围。

4.4 属性的继承

1. 属性的继承和扩展

子类可以继承父类所有的属性,还可以增加自己的成员变量。

2. 属性隐藏

属性隐藏是指子类重新定义一个从父类那里继承来的与变量完全相同的变量。
所谓隐藏,是指子类拥有了两个相同名字的成员变量,一个继承自父类,另一个是自己定义的成员变量。

属性隐藏时:
当子类执行继承父类的方法,处理的是继承自父类的变量。
当子类执行自己定义的方法,处理的是子类自己定义的变量。
在2种情况时,仍希望调用父类的属性,则需要用到super。

class Person {
	String id;
	String name="1";
	String address="1";

	public Person() {
	}

	public void showName() {
		System.out.println(name+","+address); //输出的是父类中name
	}
}

//例题4_3变量隐藏测试
class Student extends Person {
	String address="2"; //重新定义父类变量
	String school="2";

	public Student() {
		//无参构造
	}

	public void showInfo(){
		showName();             //调用父类的方法
		System.out.println("Student:"+address+"Student:"+school);  //使用的是子类的address
	}

	//测试
	public static void main(String[] args) {
		Student student=new Student();
		student.showInfo();
	}

}

4.5 方法的继承

1. 方法的继承和扩展

子类可以继承父类所有的方法,除构造方法外,还可以增加自己的成员方法。

2. 方法重写

方法重写(或覆盖是指子类重新定义从父类继承来的方法,从而使子类具有自己的行为。

注意事项:
1 同方法名、参数列表、范围值类型。同修饰符static,final方法不能重写。
2 访问限制,子类比父类扩大宽松原则,严格顺序:private>default>protected>public
3 部分重写父类方法,在原方法基础上添加新的功能,即在子类的覆盖方法的第一句位置加:super.父类方法名()

什么情况用?
子类实现与父类相同的功能,算法不同。
名字相同方法中,子类比父类操作多。
在子类中取消从父类继承的方法,将方法体设为空。

//子类-Ellipse椭圆类
class Ellipse extends Shape {
	private int centerX; // 圆心X坐标
	private int centerY; // 圆心Y坐标
	private int width; // 椭圆宽度
	private int height; // 椭圆高度

	public Ellipse(int x, int y, int w, int h) {// 构造方法
		super(); // 调用父类的构造方法1
		centerX = x;
		centerY = y;
		width = w;
		height = h;
	}

	public void draw() {// 覆盖父类的draw()方法
		System.out.println("draw a Ellipse");
	}
}
//子类-Rectangle矩形类
class Rectangle extends Shape {
	private int left; // 矩形左上角X坐标
	private int top; // 矩形左上角Y坐标
	private int width; // 矩形长度
	private int height; // 矩形宽度

	public Rectangle(int l, int t, int w, int h) {// 构造方法
		super(2); // 调用父类的构造方法2
		left = l;
		top = t;
		width = w;
		height = h;
	}

	public void draw() {// 覆盖父类的draw()方法
		System.out.println("draw a Rectangle");
	}
}

//父类-Shape形状类
class Shape {
	protected int lineSize; // 线宽

	public Shape() {// 构造方法1
		lineSize = 1;
	}

	public Shape(int ls) {// 构造方法2
		lineSize = ls;
	}

	public void setLineSize(int ls) { // 设置线宽
		lineSize = ls;
	}

	public int getLineSize() {// 获得线宽
		return lineSize;
	}

	public void draw() { // 画图
		System.out.println("Draw a Shape");
	}
}

//例题4_4设计一个画图程序
public class Test {
	public static void main(String args[]) {
		Ellipse ellipse = new Ellipse(30, 30, 50, 60); // 创建子类Ellipse的对象
		//ellipse.setLineSize(2); // 调用父类方法重新设置lineSize 值为2
		System.out.println("LineSize of ellipse : " + ellipse.getLineSize());

		Rectangle rectangle = new Rectangle(0, 0, 20, 30); // 创建子类rectangle对象
		//rectangle.setLineSize(3); // 调用父类方法重新设置lineSize属性为3
		System.out.println("LineSize of rectangle : " + rectangle.getLineSize());
		ellipse.draw(); // 访问子类方法
		rectangle.draw(); // 访问子类方法
	}
}

任务4.2 使用构造方法继承设计求租客户信息类

4.6 关键字super

定义:使用super可以引用被子类隐藏的父类的成员变量或方法。
语法格式:
super.成员变量名
super.方法名(实参列表)

1. 在子类的构造方法内部引用父类的构造方法。

在构造子类对象时,必须调用父类的构造方法。一般自动调用父类中默认的无参构造方法,如果没有默认的,则需要手动调用-super关键字。

super调用构造方法的代码在子类的构造方法中最多出现一句。不能和this调用构造方法的代码一起使用。当调用父类空构造方法时,super可以省略。

//例题4_5super引用父类构造方法
//父类SuperDemo1
public class SuperDemo1 {

	public SuperDemo1() {
	} //父类构造方法1

	public SuperDemo1(int a) {
	} //父类构造方法2
}
//例题4_5super引用父类构造方法
//子类SubDemo1
public class SubDemo1 extends SuperDemo1 {
	public SubDemo1() {
		super(); //可省略,调用父类构造方法1
	}

	public SubDemo1(int a) {
		super(a); //必须放在第一句,调用父类构造方法2
	}

	public SubDemo1(String s) {
		super(); //可省略,调用父类构造方法1
	}
}

2. 在子类中调用父类中的成员方法。

子类调用继承了父类的成员方法,一般直接通过方法名调用。如果在子类覆盖了父类的成员方法后,则需要用super关键字调用。

//例题4_6super引用父类成员方法
//父类SuperDemo2
public class SuperDemo2 {
	public void test() {
	}

	public void print(int a) {
		System.out.println("SuperDemo2: " + a);
	}
}

//例题4_6super引用父类成员方法
//子类SubDemo2
public class SubDemo2 extends SuperDemo2 {
	public void print(int a) {
		super.print(a); //super关键字表示调用父类方法
		System.out.println("Sub Dem2");
	}

	public void t() {
		super.test(); //super可省略
		super.print(0); //不可省略,因为子类方法重写父类方法print()
	}
}

3. 在子类中调用父类中的成员变量。

一般成员变量的覆盖是没有意义的,所以调用成员变量时,super可以省略。

4.7 构造方法的继承

构造方法可以重载,不可以重写。
子类无条件继承父类的无参构造方法。
子类不能继承父类的有参构造方法,只能通过super调用。
子类中调用父类的构造方法,super必须放在第一句。

//例题4_7构造方法的继承与调用顺序示例
class Grandpa {
	protected Grandpa() {
		System.out.println("default Grandpa");
	}

	public Grandpa(String name) {
		System.out.println(name);
	}
}
//例题4_7构造方法的继承与调用顺序示例
class Father extends Grandpa {
	protected Father() {
		System.out.println("default Father");
	}

	public Father(String grandpaName, String fatherName) {
		super(grandpaName); //调用父类的构造方法 有参
		System.out.println(fatherName);
	}
}

//例题4_7构造方法的继承与调用顺序示例
public class Son extends Father {
	//执行顺讯:从最顶层父类,开始往下执行。
	public Son() {
		System.out.println("default Son");
	}

	public Son(String grandpaName, String fatherName, String sonName) {
		super(grandpaName, fatherName); //调用父类有参构造
		System.out.println(sonName);
	}

	public static void main(String args[]) {
		//先执行有参
		Son s1 = new Son("My Grandpa", "My Father", "My Son"); // ①创建子类对象1
		//再执行无参
		Son s2 = new Son(); // ②创建子类对象2
	}
}

4.8 对象类型转换

1. 向上转型

//实现向上转型,子类——>父类
Person p=new Student(); //父类Person引用子类Student。
p.talk();

补充说明:
丢失一些子类新增的变量和方法,但留下了子类继承或重写的变量和方法。
自动转换。
向上转型对象访问重写父类的方法,操作子类的方法。

2.向下转型

//实现向下转型,父类——>子类
Student s=(Student) p; //父类对象p赋给子类对象s,子类Student引用父类Person。
s.learn();

补充说明:
可以操作父类及子类的变量和方法。
强制转换。
向下转型对象访问重写父类的方法,操作子类的方法。

//此向下转型错误 报java.lang.ClassCastException 强制转换无法实现。
Person person=new Person();
Student st=(Student)person; 因为当前Student子类没引用person父类。
st.learn();

//例题4_8测试对象转型,定义父类Person、子类Student和Teacher
public class Person {
	String name;

	public void talk() {
	}// 把父类中的覆盖情况去掉,则子类中的方法不再可见

	public void listen() {
		System.out.println("a person is listening..");
	}
}

//例题4_8测试对象转型,定义父类Person、子类Student和Teacher
public class Teacher extends Person {
	String workNo; // 工号

	public void talk() {
		System.out.println("teacher is talking");
	}

	public void teach() {
		System.out.println("teacher is teaching..");
	}
}

//例题4_8测试对象转型,定义父类Person、子类Student和Teacher
public class Student extends Person {
	String no; // 学号

	public void talk() {
		System.out.println("student is talking");
	}

	public void learn() {
		System.out.println("student is learning..");
	}

	public static void main(String[] args) {
		//实现向上转型,子类——>父类  丢失一些子类新增的变量和方法,但留下了子类继承或重写的变量和方法。自动转换。
		Person p=new Student(); //父类Person对象p引用子类Student新创建的对象。
		p.talk();
		//p.learn(); //丢失了

		//实现向下转型,父类——>子类  可以操作父类及子类的变量和方法。强制转换。
		Student s=(Student) p; //父类对象p赋给子类对象s,当前p是子类Student的引用。
		s.learn();

		//次向下转型错误 报java.lang.ClassCastException 强制转换无法实现。
		Person person=new Person(); //这里没有引用Student对象
		Student st=(Student)person;
		st.learn();
	}
}
3. instanceof运算符

作用:判断该引用变量是否属于该类或该类的子类。
格式:引用变量名 instanceof 类名
结果:是,返回True。不是,返回False

//例题4_9instanceof运算符的使用示例
public class UseOfInstanceof {
	public static void main(String[] args) {
		Person p1 = new Teacher(); // p1是父类对象,但是子类实例
		Person p2 = new Student(); // p2是父类对象,但是子类实例

		pleasetalk(p1); //调用子类Teacher中保留的talk
		pleasetalk(p2); //调用子类Student中保留的talk

		p1.listen(); //调用父类listen
		p2.listen();
		 //p1.teach(); //p1的teach方法是子类方法。不可见
		 //p2.learn(); //p2的learn方法是子类方法,不可见

		if (p1 instanceof Teacher) {
			System.out.println("she is a teacher!");
			((Teacher) p1).teach(); // 如果能够转换则让老师演示教学
		}
		if (p2 instanceof Student) {
			System.out.println("he is a Student!");
			((Student) p2).learn(); // 如果能够转换,则让学生演示学习
		}
		// p1.learn();//子类方法不可见
	}

	static void pleasetalk(Person p) {
		p.talk();
	}
}

任务4.3 添加求租客户信息设计

4.9 多态性

方法的多态,即多种形态,是指属性或方法在子类中表现为多种形态。

1. 编译时多态

编译多态是指在程序编译过程中出现的多态性,通过方法重载实现(静态多态)。

//通过方法重载实现静态多态。
//条件:只用方法重载
public class StopClass {
    public static void print(){
        System.out.println("print_1");
    }

    public static void print(int i){
        System.out.println("print_"+i);
    }

    public static void print(char c){
        System.out.println("print_"+c);
    }

    public static void main(String[] args) {
        //在类(静态)方法中,可以通过类名调用静态方法,不能访问非静态成员。
        print(); //这里类名可以省略
        print(2);
        print('3');
    }
}
2. 运行时多态

运行时多态是指在程序运行时出现的多态性,通过方法重写实现(动态多态)。
动态多态存在的条件有三个:

  1. 类和类之间有继承关系。
  2. 有方法重写。
  3. 存在父类引用子类对象。

通过方法重载实现静态多态。
条件:只用方法重载

//定义父类Shape
class Shape {
	public void draw(){  //父类的draw()方法
		System.out.println("draw a Shape");
	}
}

//定义子类Cirle
class Circle extends Shape {
	public void draw(){     //重写父类的draw()方法
		System.out.println("draw a Circle");
	}
}
//定义子类Elipse
class Ellipse extends Circle {  //定义子类Ellipse
	public void draw(){  //重写父类的draw()方法
		System.out.println("draw a Ellipse");
	}
}
//例题4_10方法多态性示例
//动态多态条件:继承、重写、父类引用子列对象(对象类型转换——向上转型)
public class Test {
	public static void main(String args[]) {
		Shape s = new Shape(); //动态绑定为类Shape对象
		Shape c = new Circle(); //动态绑定为类Circle对象
		Shape e = new Ellipse(); // 动态绑定为类Ellipse对象

		s.draw(); //Shape对象访问父类Shape的方法
		c.draw(); //Shape对象访问子类Circle的方法
		e.draw(); //Shape对象访问子类Ellipse的方法
	}
}
***3. 重载和重写的区别

重载和重写时面向对象设计的两大特征。有相似之处,也有区别:

  1. 方法重载是同一类中的方法之间的关系,是水平关系。方法重写是子类和父类之间,是垂直关系。
  2. 方法重载是多个同名不同参的方法。方法重写是对同一个方法产生关系,要求同名/同参数/同返回类型。
  3. 方法重载对控制修饰符没有要求。方法重写要求不能降低父类的访问控制权限。

4.10 抽象类和最终类

1. 抽象类

定义:类的声明中有abstract关键字的类称为抽象类。
作用:为子类定义共同特征和某些依赖于具体实例而实现的抽象方法。用于对某些类进行概括和抽象,即抽象类定义其子类共有的属性和方法,以免子类重复定义。

声明格式:
public abstract class 抽象类名{
类体;
}

抽象类特点:
不能用new创建抽象类实例
与具体类不同的是,抽象类中可以定义抽象方法。
抽象方法只能出现在抽象类中,抽象类中可以没有抽象方法。
抽象方法必须要在非抽象子类中实现,否则子类也必须声明为抽象类。

2. 抽象方法

定义:类的成员方法有abstract关键字修饰的方法称为抽象方法。
作用:描述系统的功能或规范某些操作,不提供集体的实现。抽象方法的实现通常由继承该类的子类去完成。

语句格式:
权限修饰符 abstract 返回值类型 方法名(形参参数列表);

使用抽象方法:
abstract于static不能同时存在。
任何包含抽象方法的类必须被声明为抽象类。
在程序设计中,抽象类一定是某个类或某些类的父类。
若干个抽象类的子类要实现一些同名的方法。

abstract class Animal {
	String str;
	Animal(String s) {  //定义抽象类的一般方法-构造方法
		str = s;
		System.out.println("animal:"+str);
	}
	abstract void eat(); //定义抽象方法
}
class Dog extends Animal {
	String str;

	Dog(String s) {
		//调用父类的有参构造
		super(s);
	}
    //继承了抽象类,就必须实现抽象类的子类
	void eat() {
		System.out.println("狗吃骨头!");
	}
}
class Horse extends Animal {
	String str;

	Horse(String s) {
		//调用父类的有参构造
		super(s);
	}
	//继承了抽象类,就必须实现抽象类的子类
	void eat(){ // 重写父类的抽象方法
		System.out.println("马吃草料!");
	}
}
//例题4_11抽象类和抽象方法示例
public class Test {
	public static void main(String args[]) {
		Animal h = new Horse("马");
		Animal d = new Dog("狗");
		h.eat();
		d.eat();
	}
}
3. 最终类和最终方法

最终类定义:最终类是指不能被继承的类,即不能再用最终类派生子类。Java规定,最终类中方法都自动成final方法。

最终方法定义:最终方法是指不能被子类重写修改的方法。

语句格式:
public final class 类名{
//最终方法
public final 返回类型 方法名(){
}
}

使用注意:
一个类不能既是最终类,又是抽象类,即abstract和final不能合用。
权限修饰符public等,一般放在abstract和final的前面。

class Person {
	String name;

	public Person() {
	} // 构造方法

	final String getName() // 最终方法
	{
		return "person";
	}
}
//例题4_12最终方法示例
class Student extends Person {
    //构造方法
	public Student() {
	} 
	//final String getName() //重写父类的最终方法,不允许
	//{
	//	return "student";
	//}
}

4.11 接口

1. 接口的定义

一个类通常规定了同一类事物应用的静态属性和动态行为,而一个接口规定了一系列类应用的共同属性和行为。
一个只能继承一个父类,但允许一个类实现(可以说继承)多个接口。抽象类和接口功能类同,实现Java语言的多继承机制是通过接口实现的。

主要功能:

  1. 实现不相关类的相同方法。
  2. 指明多个类需要实现的方法。
  3. 在运行时动态定位类所需调用的方法。

定义格式:

修饰符[public][abstract] interface 接口名 [extends 父接口列表] //接口声明
{
//接口体是有属性(常量)和方法方法声明(抽象方法声明)组成
[public][static][final] 类型 常量名=值; //常量声明
[public][abstract] 返回类型 方法名(参数列表); //抽象方法的声明
}

注意事项:
接口中的属性默认是public static final修饰的常量,必须赋初值。
接口中的方法默认是public abstract修饰的,没有方法体。
接口文件名必须与接口名一致。

2. 接口的实现

定义类时实现一个借口用关键字implements。
语句格式:
[修饰符] class 类名 implements <借口名1>,<借口名2>, …

注意事项:

  1. 如果某个类实现了借口,这个类就可以访问借口中的常量。
  2. 类实现借口方法时,访问控制符必须是public,因为借口方法都是public类型。
  3. 实现接口的类,如果不是抽象类,则必须为所有抽象方法定义方法体,方法头部与接口中的定义一致。
//例题4_13编写接口PrintMessage用来处理各种打印信息操作
public interface PrintMessage {//接口声明
	public int count = 10; //常量声明和赋值
	public void printAllMessage(); //抽象方法声明
	public void printLastMessage(); //抽象方法声明
	public void printFirstMessage(); //抽象方法声明
}
//例题4_14编写一个实现接口PrintMessage的类,并编写一个测试程序进行测试
public class MyPrint implements PrintMessage{  //实现接口的类MyPrint

	private String[] message ; //类中的成员变量message  字符串数组
	private int i; //类中的成员变量i

	public MyPrint(){ // MyPrint类的构造方法
		message = new String[3];
		i = 0;
		this.putMessage("Hello world!"); //使用MyPrint类的方法
		this.putMessage("Hello China!");
		this.putMessage("Hello JIANGZHOU!");
	}
	public void putMessage(String str) {  //类中的方法
		message[i++] = str;
	}
	public void printAllMessage(){  //实现接口中的方法
		for (int k = 0; k < message.length; k++) {
			System.out.println(message[k]);
		}
	}
	public void printLastMessage(){ //实现接口中的方法
		System.out.println(message[message.length - 1]);
	}
	public void printFirstMessage(){  //实现接口中的方法
		System.out.println(message[0]);
	}
}
//例题4_14编写一个实现接口PrintMessage的类,并编写一个测试程序进行测试
public class Test {
	public static void main(String[] args) {
		MyPrint my = new MyPrint(); //定义MyPrint类的对象

		System.out.println("print all messages");
		my.printAllMessage(); //使用实现了的接口方法
		System.out.println("print the first messages");
		my.printFirstMessage(); //使用实现了的接口方法
		System.out.println("print the last messages");
		my.printLastMessage(); //使用实现了的接口方法
	}
}
***3. 抽象类与接口的区别

abstract class 和 interface是Java对抽象类定义支持的两种机制。
语法上:抽象类用关键字abstract class定义,并可以定义自己的成员变量和非抽象的成员方法。接口用interface定义,接口内只有静态的常量,所有的成员方法都是抽象方法。
使用上:抽象类的使用,表示的是一种继承关系,一个类只能使用一次继承关系。但是一个类可以实现多个接口。
设计上:abstract class表示的是"is-a"关系。interface表示的是"like-a"关系。

4.12 包

1. 包的概念

主要定义:包是Java提供的文件组织方式。一个包等于一个文件夹,一个包可以包括很多类文件。包中还有子包,形成包等级。
一个类文件放在包中,就会有两个名字。一个是类文件的短名字(类文件本身),一个是类文件的全限定名(在类文件本身前加上包名)。

主要作用:方便管理,方法软件资源重用,扩大了Java命名空间。

2. 创建包

语法格式:package 包名;
多级包:package 包名 [.子包名 [.子包名 …]];

3. import语句

通用格式:
import package1 [.package2].(类名|*);

注意事项:
除非是文件系统的限制,不存在对于包层次深度的实际限制。
要么指定一个明确的类名,要么使用*号导入所有public类,但后者会增加编译时间,对运行时间性能无影响。

4. 访问保护

对于类成员而言:声明为public的内容可以被任何地方访问。声明为private的成员不能被该类外看到。
没有明确访问说明,则为默认访问控制符,它仅可以被同一包中其他类访问。

任务4.4 使用常用工具类设计添加求租客户

4.13 Math类

定义:Math类是Java提供的一个执行数学基本运算的类,提供的数学运算方法都为static形式,另外还提供了一些数学常量。
语法格式:Math.数学方法 Math.数学常量

1. 三角函数

public static double sin(double a) 正弦
public static double cos(double a) 余弦
public static double tan(double a) 正切
public static double asin(double a)
public static double acos(double a)
public static double atan(double a)
public static double toRadians(double angdeg) 将角度转换成弧度
public static double toDegrees(double angrad) 将弧度转换成角度

//例题4_15三角函数实例
public class example4_15 {
	public static void main(String args[]) {
		System.out.println("60度的正弦值:"+Math.sin(Math.PI/3));//取60度的正弦
		System.out.println("180度的余弦值:"+Math.cos(Math.PI));//取180度的余弦
		System.out.println("90度的正切值:"+Math.tan(Math.PI/2));//取90度的正切
		System.out.println("0的反正弦值:"+Math.asin(0));//取0的反正弦
		System.out.println("1的反余弦值:"+Math.acos(1));//取1的反余弦
		System.out.println("1的反正切值:"+Math.atan(1));//取1的反正切
		//弧度的定义是:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。
		//当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度。

        //圆弧长公式:弧长=nπr/180  n就是角度数,即圆心角n所对应的弧长。
		//用弧度求扇形面积公式:S=|α| r^2/2 二分之一倍的α角的大小,与半径的平方之积。
		//半径为r的扇形面积为nºπr²/360º

		//把度化成弧度的公式:弧度=度×π/180 单位rad
		System.out.println("45度的弧度值:"+Math.toRadians(45));//取45度的弧度值 角度->弧度
		//把弧度化成度的公式:度=弧度×180°/π
		System.out.println("п/2的角度值:"+Math.toDegrees(Math.PI/2));//取п/2的角度值 弧度->角度
	}
}
2. 指数函数

public static double exp(double a) 返回e的a次方
public static double log(double a) 返回a的自然数
public static double log10(double a) 返回底数为10的a的对数
public static double sqrt(double a) 返回a的平方根
public static double pow(double a,double b) 返回a的b次方

//例题4_1指数函数实例
public class example4_16 {
	public static void main(String[] args) {
		System.out.println("e的3次方:"+Math.exp(3));//e的3次方
		System.out.println("3的自然对数:"+Math.log(3));//3的自然对数
		System.out.println("以10为3的自然对数:"+Math.log10(3));//3的自然对数
		System.out.println("9的平方根值:"+Math.sqrt(9));//9的平方根值
		System.out.println("2的3次方值:"+Math.pow(2, 3));//2的3次方值
	}
}
3. 取整函数

public static double ceil(double a) 返回>=a的最小浮点数
public static double floor(double a) 返回<=a的最大浮点数
public static double rint(double a) 返回对a四舍五入后的最近的长整数
public static int round(float a) 返回对a四舍五入后的最近的整数
public static long round(double a) 返回对a四舍五入后的最近的长整数

//例题4_17取整函数实例
public class example4_17 {
	public static void main(String[] args) {
		System.out.println("Math.ceil(8.3)="+Math.ceil(8.3));
		System.out.println("Math.floor(3.5)="+Math.floor(3.5));
		System.out.println("Math.rint(3.7)="+Math.rint(3.7));
		System.out.println("Math.round(2.5)="+Math.round(2.5));
		System.out.println("Math.round(4.3f)="+Math.round(4.3f));
	}
}

4. 取最大值、最小值、绝对值函数

public static int max(int a,int b) 返回两个int值中较大的一个
public static long max(long a,long b) 返回两个long 值中较大的一个
public static float max(float a,float b) 返回两个float 值中较大的一个
public static double max(double a,double b) 返回两个double值中较大的一个
public static int min(int a,int b) 返回两个int值中较小的一个
public static long min(long a,long b) 返回两个long 值中较小的一个
public static float min(float a,float b) 返回两个float 值中较小的一个
public static double min(double a,double b) 返回两个double值中较小的一个
public static int abs(int a) 返回int值的绝对值
public static long abs(long a) 返回long 值的绝对值
public static float abs(float a) 返回float 值的绝对值
public static double abs(double a) 返回double 值的绝对值

//例题4_18取最大值绝对值函数实例
public class example4_18 {
	public static void main(String[] args) {
		System.out.println("4.8和3.2中较大者:"+Math.max(4.8,3.2));
		System.out.println("4.8和3.2中较小者:"+Math.min(4.8,3.2));
		System.out.println("-3的绝对值:"+Math.abs(-3));
	}
}

4.14 StringBuffer类和StringBuilder类

定义:String类创建的字符串是常量,是不可更改的。若对字符串进行动态增减,则用StringBuffer类。StringBuffer又称动态字符串,每个字符串缓冲区都有一定的容量。

1. StringBuffer类

(1)常用构造方法

  • StringBuffer() 构造一个不带字符的字符串缓冲区,初始容量为16个字符。
  • StringBuffer(int iniCapacity) 指定字符容量的字符串缓冲区。
  • StringBuffer(String str) 内容初始化为指定字符串的字符缓冲区。

(2)常用方法

  • public int length() 返回字符串的个数。
  • public append(object obj) 在尾部添加对象。
  • public insert(int StartPos,Object obj) 在StartPos位置插入对象obj。
  • public StringBuffer delete(int start,int end) 删除从start到end-1处的字符串,返回当前对象。
  • public StringBuffer deleteChartAt(int index) 删除索引为index处的字符,返回当前对象。
  • public char CharAt(int index) 返回索引处的字符。
  • public void setCharAt(int index,char c) 设置索引index处的字符为c。
  • public String substring(int startIndex) 返回从startIndex开始直到最后的全部字符。
  • public String substring(int startIndex,int endIndex) 返回范围startIndex~endIndex的字符串。
  • public StringBuffer reverse() 将字符串序列反转,返回当前对象的引用。
  • public String replace(int startIndex,int endIndex,String newStr) 用newStr代替从startIndex到endIndex-1的字符序列,返回当前对象。
//例题4_19StringBuffer的使用
public class example4_19 {
	public static void main(String[] args) {
		// StringBuffer的使用
		String s = "Hello java!";
		StringBuffer str = new StringBuffer();

		// 在str后添加字符(串)
		str.append(s).append("你好!").append("Java!");
		System.out.println(str);

		// 删除索引为0的位置的字符
		str.deleteCharAt(0);
		System.out.println(str);

		// 从索引为0的位置开始,截取11个字符 空格字符也算。
		s = str.substring(0, 11);
		System.out.println(s);

		// 使str内容反向
		str.reverse();
		System.out.println(str);

		// 在4索引后插入第二个参数的内容
		str.insert(4, "这是插入的字符");
		System.out.println(str);
	}
}
2. StringBuilder类

由于StringBuilder没有实现同步机制,而StringBuffer实现了,所以StringBuilder比StringBuffer有更高的性能。
所以优先采用StringBuilder。

4.15 Date类

定义:Date类表示日期和时间,提供了操作日期的时间各组成部分的方法,在java.util包中。

1. 常用构造方法
  • Date()
  • Date(long date)
//例题4_20获取当前时间
public class example4_20 {
	public static void main(String[] args) {
		//直接输出Date类型对象
		Date d = new Date();
		System.out.println(d);
		//将字符串格式的时间转为Date
		String ds="2021-3-29 21:07";
		System.out.println(ds.valueOf(ds));
	}
}
2. 常用方法
  • public void setTime(long time) 设置此Date对象
  • public long getTime() 返回Date对象表示的毫秒数
  • public static Date valueOf(String s) 将字符串格式日期转成Date
3. 相关类SimpleDateFormat

定义:用于格式化日期,在java.text包中。
(1)构造方法
SimpleDateFormat(String FormatString)
FormatString常用样式:

  • y或yy 表示年份
  • m或MM 表示月份
  • d或dd 表示天
  • H或HH 表示小时
  • m或mm 表示分
  • s或ss 表示秒
  • E 表示字符串输出的星期

格式化参数Date对象,返回字符串。
public String format(Date d)
设置解析字符串日期时,是否严格检查日期字符串。true接收无效数字,false不接受无效数字并严格检查。
public setLenient(boolean b)
根据构造函数中的格式,解析字符串日期为date类型,不能解析则抛出异常。
public Date parse(String dateString)

//例题4_21 SimpleDateFormat实例
public class example4_21{
	//throws Exception 抛出运行时的所有异常
	//throws ParseException 抛出运行时的ParseException异常
	public static void main(String[] args) throws ParseException {
		//根据SimpleDateFormat构造函数实例化SimpleDateFormat对象
		//通过Ctrl+B可以查看SimpleDateFormat源码
		SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d=new Date();
		//根据构造函数中的格式将Date对象输出为字符串。
		String DateString=sf.format(d); //返回类似的日期 2014-01-21 16:03:39
		System.out.println(DateString);
        //设置解析字符串日期时,是否严格检查日期字符串。true接收无效数字,false不接受无效数字并严格检查
		sf.setLenient(false);
		//根据构造函数中的格式,解析字符串日期为date类型,用来检验日期字符串
		sf.parse(DateString);
	}
}
4. 相关类DateFormat

定义:用于格式化日期,在java.text包中。
(1)静态方法
public DateFormat getDateTimeInstance(int dateStyle,int timeStyle,Locale alocal) 用于获得一个Dateformat实例
dateStyle为日期常数,timeStyle为日期类型,alocal为地区常数
(2)实例方法
public String format(Date d) 格式化参数Date对象,返回字符串。

//例题4_22 DateFormat实例
public class example4_22 {
	public static void main(String[] args) {
		//public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
		//dateStyle 日期类型
		//timeStyle 时间类型
		//aLocale 地区常数
		DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, Locale.CHINA);
		System.out.println(df.format(new Date())); // 按中国格式显示日期时间
	}
}

4.16 Calendar类

定义:本类提供了日历功能,但这些功能都是由其子类GregorianCalendar实现。

1. GregorianCalendar类

(1)构造方法
GregorianCalendar() 用当前系统日期初始化对象。
(2)常用方法
public int get(int field) 返回与field相关的日期。field是Calenda中的静态字段。
public void set(int field,int value)用value值替换field表示的日期
public final void set(int year,int value) 设置年/月/日
public final void set(int year,int month,int date) 设置年月日
public final void set(int year,int month,int date,int hour,int minute) 设置年月日时分秒
public final void set(int year,int month,int date,int hour,int minute,int second) 设置年月日时分秒毫秒
public long getTimeMillis() 获取对象毫秒数

//例题4_23 获取当前日期时间_使用日历功能
public class example4_23 {
	public static void main(String[] args) {
		GregorianCalendar gre = new GregorianCalendar(); // 获得实例
		//Calendar.YEAR等是Calendar中定义的静态字段 get()返回与静态字段有关的日期
		//日期字符串拼接
		String now = gre.get(Calendar.YEAR) + "-" + (gre.get(Calendar.MONTH) + 1)
				+ "-" + gre.get(Calendar.DATE) + " "
				+ gre.get(Calendar.HOUR_OF_DAY) + ":"
				+ gre.get(Calendar.MINUTE) + ":" + gre.get(Calendar.SECOND);

		System.out.println(now); //显示当前日期时间
		System.out.println(gre.getTimeInMillis()); //获得对象毫秒数
	}
}
2. Calendar类

定义:Calendar类是一个抽象类,但可以使用其中的static方法getInstance()初始化日历对象。它为日历字段之间转换提供方法,为操作日历字段提供方法。
(1)常用方法
public Date getTime() 获取日期,返回一个表示calendar时间值的Date对象
public long getTimeInMillis() 返回此calendar的时间值,以毫秒为单位
public void add(int field,int amount) 根据日历规则,为给定的日历字段添加或减去指定的时间量
public int getMaximum(int field) 返回field最大值
public setTime(Date date) 设置日期
(2)静态字段
YEAR MONTH DATE(DAY_OF_MONTH) 分别表示年月日
HOUR MINUTE SECOND MILLISECOND 分别表示时分秒毫秒 HOUR为12小时制
HOUR_OF_DAY 表示一天中的第几个小时(24小时制)
DAT_OF_YEAR 表示一年中的第几天
WEEK_OF_YEAR 表示一年中的第几周
WEEK_OF_MONTH 表示一月中的第几周
DAY_OF_WEEK 表示一周中的第几天(1表示星期日,2表示星期一,以此类推)

//例题4_24  打印未来几年的10个黑色星期五_使用日历功能
public class example4_24 {
	public static void main(String[] args) {
		//Calendar类是一个抽象类,不能new实例化。但可以使用Calendar类static方法getInstance()初始化一个日历对象。
		Calendar cal = Calendar.getInstance();
		//实例化SimpleDateFormat对象设置日期格式
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd  EEEE");//设置日期格式
		cal.set(Calendar.DAY_OF_MONTH, 13);//设置日期为13号
		int n = 1;
		while (n <= 10) {
			//日历的变化都是有序的。
			System.out.println("输出当前日历"+sdf.format(cal.getTime()));
			//遇到星期五就分段输出结果。 调用静态字段Calendar.DAY_OF_WEEK-表示一周的第几天。
			if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) {//如果是星期五
				Date date = cal.getTime();//获得日期,返回一个表示此Calendar时间值的Date对象
				System.out.println(sdf.format(date));//按照格式打印黑色星期五
				n++;
			}
			cal.add(Calendar.MONTH, 1);//月份增加1个月
		}
	}
}

单元5 集合容器

线程同步安全:喂,SHE

喂(Vector比arraylist多了个同步化机制线程安全)、S(Stack堆栈类,先进后出)、H(hashtable比hashmap多了个线程安全)、E(enumeration枚举,相当于迭代器)
**HashTable **privateMapmap=newHashtable<>();
**SynchronizedMap **privateMapmap= Collections.synchronizedMap(newHashMap());
ConcurrentHashMap 最推荐privateMapmap=newConcurrentHashMap<>();

任务5.1 添加房源信息设计

5.1 Java集合容器框架

定义:sun公司发布的Java应用程序接口(API)的组成部分,放在java.util包。
公式:Java集合框架=集合接口+实现+算法。
数据结构:List列表、Queue队列、Stack栈、Set集、Map键值映射。实现时涉及红黑树、哈希表等数据结构。
image.png
上面图定义了6个接口,5个抽象类,8个实现类。其中:

  • Collection接口是一组允许重复的对象。
  • Set接口继承Collection,但不允许重复,使用自己内部的一个排列机制。
  • List接口继承Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。
  • Map接口是一组成对的键-值对象,即所持有的是key-value pairs。
  • Map中不能有重复的key。拥有自己的内部排列机制。
  • 容器中的元素类型都为Object。从容器取得元素时,必须把它转换成原来的类型。

image.png

5.2 Collection接口

定义:Collection是最基本的集合接口,Collection中的元素是Object,Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用,可以使用子接口实现定义Collection。
注意:集合中只有对象,不能是基本数据类型。Collection不提供get()方法,遍历元素用iterator。
Collection接口的常用方法

方法名称说明
boolean add(E e)向集合中添加一个元素,如果集合对象被添加操作改变了,则返回 true。E 是元素的数据类型
boolean addAll(Collection c)向集合中添加集合 c 中的所有元素,如果集合对象被添加操作改变了,则返回 true。
void clear()清除集合中的所有元素,将集合长度变为 0。
boolean contains(Object o)判断集合中是否存在指定元素
boolean containsAll(Collection c)判断集合中是否包含集合 c 中的所有元素
boolean isEmpty()判断集合是否为空
Iteratoriterator()返回一个 Iterator 对象,用于遍历集合中的元素
boolean remove(Object o)从集合中删除一个指定元素,当集合中包含了一个或多个元素 o 时,该方法只删除第一个符合条件的元素,该方法将返回 true。
boolean removeAll(Collection c)从集合中删除所有在集合 c 中出现的元素(相当于把调用该方法的集合减去集合 c)。如果该操作改变了调用该方法的集合,则该方法返回 true。
boolean retainAll(Collection c)从集合中删除集合 c 里不包含的元素(相当于把调用该方法的集合变成该集合和集合 c 的交集),如果该操作改变了调用该方法的集合,则该方法返回 true。
int size()返回集合中元素的个数
Object[] toArray()把集合转换为一个数组,所有的集合元素变成对应的数组元素。
public class Student {
	private String stuNo;//学号
	private String stuName;//学生姓名
	private int stuAge;//学生年龄
	private String stuAddress;//学生地址

	public Student() {
	}

	public String getStuNo() {
		return stuNo;
	}

	public void setStuNo(String stuNo) {
		this.stuNo = stuNo;
	}

	public String getStuName() {
		return stuName;
	}

	public void setStuName(String stuName) {
		this.stuName = stuName;
	}

	public int getStuAge() {
		return stuAge;
	}

	public void setStuAge(int stuAge) {
		this.stuAge = stuAge;
	}

	public String getStuAddress() {
		return stuAddress;
	}

	public void setStuAddress(String stuAddress) {
		this.stuAddress = stuAddress;
	}
}
//例题5_1Collection接口方法测试,对学生类对象进行添加、删除等操作。
public class Example5_1 {
	public static void main(String[] args) {

		//创建学生对象
		Student stu1 = new Student();

		stu1.setStuNo("0908233111");
		stu1.setStuName("陈君祥");
		stu1.setStuAge(21);
		stu1.setStuAddress("江苏徐州");

		Student stu2 = new Student();
		stu2.setStuNo("0908233112");
		stu2.setStuName("章家其");
		stu2.setStuAge(22);
		stu2.setStuAddress("江苏南京");

		//创建集合对象
		//ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,可以添加或删除元素。
		//ArrayList 继承了 AbstractList ,并实现了 List 接口。
		Collection collection = new ArrayList();


		//add()添加对象
		collection.add(stu1);
		collection.add(stu2);
		System.out.println("after add object:");
		System.out.println("collection.size()=" + collection.size()); //size()判断集合中元素个数

		// 取出对象
		// 1定义迭代器对象collection.iterator()
		// 2循环并判断选择对象iterator.hasNext()
		// 3访问对象iterator.next()
		Iterator iterator=collection.iterator();
		while (iterator.hasNext()){
			Object object=iterator.next();
			Student student=(Student) object; //父对象->子对象
			System.out.println("对象:"+student.getStuName());
		}


		//remove()删除对象
		collection.remove(stu1);
		System.out.println("after remove stu1 :");
		System.out.println("collection.size()=" + collection.size());

		//isEmpty()判断集合是否为空
		boolean isEmpty = collection.isEmpty();
		System.out.println("集合是否为空:" + isEmpty);

		//contains()判断集合中是否包含某个对象
		boolean isContains = collection.contains(stu2);
		System.out.println("集合是否包含stu2:" + isContains);

		//清除集合内对象
		collection.clear();
		System.out.println("afeter clear:");
		System.out.println("collection.size()=" + collection.size());
	}
}

5.3 Iterator迭代接口

定义:Iterator是迭代输出接口,就是将元素一个个进行判断,判断是否有内容,如果有内容则取出。
Iterator iterator=collection.iterator_()_;
while (iterator.hasNext()){}

方法摘要

变量和类型方法描述
default voidforEachRemaining
(Consumer<? super E> action)对每个剩余元素执行给定操作,直到处理完所有元素或操作引发异常。
booleanhasNext()如果迭代具有更多元素,返回 true。
Enext()返回迭代中的下一个元素。
default voidremove()从底层集合中移除此迭代器返回的最后一个元素(可选操作)。
//例题5_2使用Iterator遍历对象进行集合遍历
public class Example5_2 {
	public static void main(String[] args) {
		// 取出对象
		// 1定义迭代器对象collection.iterator()
		// 2循环并判断选择对象iterator.hasNext()
		// 3访问对象iterator.next()

		//创建集合对象
		Collection collection = new ArrayList();
		List list=new ArrayList();

		//添加集合元素
		collection.add("stu1");
		collection.add("stu2");
		collection.add("stu3");

		//获得一个迭代器对象:iterator
		Iterator iterator = collection.iterator();

		//iterator.hasNext()判断是否存在另一个可访问的元素
		while (iterator.hasNext()) {//遍历
			//iterator.next()返回要访问的下一个元素 返回Object。到达集合结尾,则抛出NoSuchElementException
			Object element = iterator.next();
			System.out.println("iterator = " + element);
		}

		if (collection.isEmpty()) {
			System.out.println("collection is Empty!");
		} else {
			System.out.println("collection is not Empty! size="
					+ collection.size());
		}

		//获得一个迭代器对象:iterator2
		Iterator iterator2 = collection.iterator();
		while (iterator2.hasNext()) {//移除元素
			Object element = iterator2.next();
			System.out.println("remove: " + element);
			//删除上次访问返回的对象,本方法必须紧跟在一个元素的访问后。
			// 上次访问后集合被修改,抛出错误IllegalStateException。
			iterator2.remove();
		}

		//获得一个迭代器对象:iterator3
		Iterator iterator3 = collection.iterator();
		if (!iterator3.hasNext()) {//察看是否还有元素
			System.out.println("没有元素了");
		}

		//判断集合是否为空
		if (collection.isEmpty()) {
			System.out.println("collection is Empty!");
		}
	}
}

任务5.2 修改房源信息设计

5.4 List接口

定义:List列表容器是Collection的子接口,对象按次序排列,允许内容重复,可以产生ListIterator,双向遍历对象。
实现类:ArrayList、LinkedList、Vector、Stack等。

方法摘要

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置(可选操作)。
booleanadd(E e)将指定的元素追加到此列表的末尾(可选操作)。
booleanaddAll(int index, Collection<? extends E> c)将指定集合中的所有元素插入到指定位置的此列表中(可选操作)。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的迭代器(可选操作)返回的顺序追加到此列表的末尾。
voidclear()从此列表中删除所有元素(可选操作)。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true 。
booleancontainsAll(Collection<?> c)如果此列表包含指定集合的所有元素,则返回 true 。
static ListcopyOf(Collection<? extends E> coll)以迭代顺序返回包含给定Collection的元素的 unmodifiable List
booleanequals(Object o)将指定对象与此列表进行比较以获得相等性。
Eget(int index)返回此列表中指定位置的元素。
inthashCode()返回此列表的哈希码值。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
booleanisEmpty()如果此列表不包含任何元素,则返回 true 。
Iterator<E>iterator()以适当的顺序返回此列表中元素的迭代器。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
ListIterator<E>listIterator()返回此列表中元素的列表迭代器(按适当顺序)。
ListIterator<E>listIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
static Listof()返回包含零元素的不可修改列表。
static Listof(E e1)返回包含一个元素的不可修改列表。
static Listof(E… elements)返回包含任意数量元素的不可修改列表。
static Listof(E e1, E e2)返回包含两个元素的不可修改列表。
static Listof(E e1, E e2, E e3)返回包含三个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4)返回包含四个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5)返回包含五个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5, E e6)返回包含六个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5, E e6, E e7)返回包含七个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)返回包含八个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)返回包含九个元素的不可修改列表。
static Listof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)返回包含十个元素的不可修改列表。
Eremove(int index)删除此列表中指定位置的元素(可选操作)。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)(可选操作)。
booleanremoveAll(Collection<?> c)从此列表中删除指定集合中包含的所有元素(可选操作)。
default voidreplaceAll(UnaryOperator<E> operator)将该列表的每个元素替换为将运算符应用于该元素的结果。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素(可选操作)。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素(可选操作)。
intsize()返回此列表中的元素数。
default voidsort(Comparator<? super E> c)根据指定的Comparator引发的顺序对此列表进行排序。
default Spliterator<E>spliterator()在此列表中的元素上创建Spliterator
List<E>subList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
public class Student {
	private String name;
	private int score;

	public Student() {
		super();
	}

	public Student(String name, int score) {
		super();
		this.name = name;
		this.score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	//输出此对象时,默认直接调用了
	public String toString() {
		String s = name + " 成绩:" + score;
		return s;
	}
}
//例5_6 List及ListIterator接口的使用
public class Example5_6 {
	List list1 = new LinkedList();
	List list2 = new ArrayList();
	ListIterator it;

	//无参构造
	public Example5_6() {
		Student ZhangSan = new Student("张三", 90);

		// 顺序插入元素
		System.out.println("-----------[演示1] 顺序插入元素---------------------");
		list1.add(0, ZhangSan);
		list1.add(1, "张三");
		list1.add(2, "李四");
		list1.add(3, new Student("王武", 85));
		list1.add(4, new Student("赵榴", 76));
		list1.add(5, ZhangSan);
		printCollection(list1);

		// 删除元素(对于LinkedList 建议使用迭代器遍历删除)
		System.out.println("-----------[演示2] 删除元素---------------------");
		it = list1.listIterator();
		while (it.hasNext()) {
			Object o = it.next();
			if (o instanceof String) {
				System.out.println("String 对象 [ " + o + " ] ——从列表中清除!");
				it.remove();
			}
		}

		// //使用循环遍历时,要考虑删除元素后的索引变化,因此需要使用逆序循环。
		// for (int i=5;i>-1;i--) {
		// if (list1.get(i) instanceof String){
		// System.out.println("String 对象 [ "+list1.remove(i)
		// +" ] ——从列表中清除!");
		// }
		// }
		printCollection(list1);
		// 逆序插入元素 将元素加到尾部
		System.out.println("-----------[演示3] 逆序插入元素--------------------");
		list2.add(0, ZhangSan);
		list2.add(0, "李四");
		printCollection(list2);

		// 插入列表 从index=0开始,将list1列表元素加入list2中
		System.out.println("-----------[演示4] 插入列表---------------------");
        list2.addAll(0,list1);

		printCollection(list2);

		// 定位元素
		System.out.println("-----------[演示5] 定位元素---------------------");
		System.out.println("首个 [ " + ZhangSan + " ] 对象位于"
				+ list2.indexOf(ZhangSan));
		System.out.println("末个 [ " + ZhangSan + " ] 对象位于"
				+ list2.lastIndexOf(ZhangSan));

		// 截取子列表
		System.out.println("-----------[演示6] 截取子列表---------------------");

//		System.out.println("1:"+list1.size()); //列表1长度
//		System.out.println("2:"+list2.size());
		list1 = list2.subList(1,5);
		printCollection(list1);
	}

	//输出集合方法
	private void printCollection(List list) {
		it = list.listIterator();
		int n = 0;
		while (it.hasNext()) {
			System.out.println(n + ":" + it.next());
			n++;
		}
	}

	public static void main(String[] args) {
		new Example5_6(); //实例化 调用无参构造
	}
}

5.5 ArrayList类(实现不同步、线程不安全)

定义:ArrayList是List接口的实现类。大小可变的动态数组列表。允许null元素。
注意:此实现不是同步的,多个线程同时访问一个ArrayList时,至少一个从结构上修改了它,它必须保持外部同步。
_ArrayList_实现了_List_接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现

方法摘要

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置。
booleanadd(E e)将指定的元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c)从指定位置开始,将指定集合中的所有元素插入此列表。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的Iterator返回的顺序附加到此列表的末尾。
voidclear()从此列表中删除所有元素。
Objectclone()返回此 ArrayList实例的浅表副本。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true 。
voidensureCapacity(int minCapacity)如有必要,增加此 ArrayList实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
voidforEach(Consumer<? super E> action)对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
Eget(int index)返回此列表中指定位置的元素。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
booleanisEmpty()如果此列表不包含任何元素,则返回 true 。
Iterator<E>iterator()以适当的顺序返回此列表中元素的迭代器。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
ListIterator<E>listIterator()返回此列表中元素的列表迭代器(按适当顺序)。
ListIterator<E>listIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
Eremove(int index)删除此列表中指定位置的元素。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)。
booleanremoveAll(Collection<?> c)从此列表中删除指定集合中包含的所有元素。
booleanremoveIf(Predicate<? super E> filter)删除此集合中满足给定谓词的所有元素。
protected voidremoveRange(int fromIndex, int toIndex)从此列表中删除索引介于 fromIndex (含)和 toIndex (独占)之间的所有元素。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素。
intsize()返回此列表中的元素数。
Spliterator<E>spliterator()在此列表中的元素上创建late-binding和_故障快速_ Spliterator
List<E>subList(int fromIndex, int toIndex)返回指定的 fromIndex (包含)和 toIndex (不包括)之间的此列表部分的视图。
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
voidtrimToSize()将此 ArrayList实例的容量调整为列表的当前大小。
//例题5_3ArrayList类的方法测试
public class Example5_3 {
	public static void main(String[] args) {

		// 创建ArrayList对象
		List list = new ArrayList();

		// 将指定的元素添加到此列表的尾部
		list.add("王小二");
		list.add("张小三");
		list.add("李小四");
		list.add("陈小六");
		list.add("赵小八");

		System.out.println("list.size=" + list.size());

		// 将指定的元素插入此列表中的指定位
		list.add(2, "孙小五");
		System.out.println("after insert 孙小五");
		System.out.println("list.size=" + list.size());

		// 返回此列表中指定位置上的元素
		String user = (String) list.get(2);
		System.out.println("user=" + user);

		// 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1
		int index = list.indexOf("张小三");
		System.out.println("index=" + index);

		// 返回此列表中最后一次出现的指定元素的索引,如果列表不包含索引,则返回 -1。
		int lastIndex = list.lastIndexOf("张小三");
		System.out.println("lastIndex=" + lastIndex);

		// 如果此列表中没有元素,则返回 true
		System.out.println("列表是否为空:" + list.isEmpty());

		// 移除此列表中指定位置上的元素
		list.remove(2);
		System.out.println("after remove index=2");
		System.out.println("list.size=" + list.size());

		// 移除此列表中首次出现的指定元素(如果存在)
		list.remove("张小三");
		System.out.println("after remove 张小三");
		System.out.println("list.size=" + list.size());

		// 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。
		System.out.println("list.toArray遍历****");
		Object[] users = (Object[]) list.toArray();
		for (int i = 0; i < users.length; i++) {
			System.out.print(users[i] + "  ");
		}
		System.out.println();

		// ArrayList遍历方法一
		System.out.println("ArrayList中元素遍历方法一list.get(i)****");
		for (int i = 0; i < list.size(); i++) {
			// 返回此列表中指定位置上的元素
			String userName = (String) list.get(i);
			System.out.print(userName + "   ");
		}

		// ArrayList遍历方法二 iterator列表迭代器
		System.out.println("\nArrayList中元素遍历方法二list.iterator()*****");
		Iterator iterator = list.iterator();

		while (iterator.hasNext()) {
			String userName = (String) iterator.next();
			System.out.print(userName + "   ");
		}

		System.out.println("\n清除列表中所有元素******");
		//清除列表中所有元素
		list.clear();
		System.out.println("after clear list");
		System.out.println("list.size=" + list.size());
	}
}

5.6 LinkedList类(实现不同步、线程不安全)

定义:LinkedList是List接口的链接列表实现类。可以用作Stack堆栈、Queue队列或双端队列。
区别:ArrayList允许随机访问,插入删除效率差。LinkedList最佳适合遍历,不适合随机访问,插入删除效率较高。
关于栈或队列,现在的首选是_ArrayDeque_,它有着比_LinkedList_(当作栈或队列使用时)有着更好的性能。
_LinkedList_底层通过双向链表实现

方法摘要

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此列表中的指定位置。
booleanadd(E e)将指定的元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c)从指定位置开始,将指定集合中的所有元素插入此列表。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素按指定集合的迭代器返回的顺序附加到此列表的末尾。
voidaddFirst(E e)在此列表的开头插入指定的元素。
voidaddLast(E e)将指定的元素追加到此列表的末尾。
voidclear()从此列表中删除所有元素。
Objectclone()返回此 LinkedList的浅表副本。
booleancontains(Object o)如果此列表包含指定的元素,则返回 true 。
Iterator<E>descendingIterator()以相反的顺序返回此双端队列中元素的迭代器。
Eelement()检索但不删除此列表的头部(第一个元素)。
Eget(int index)返回此列表中指定位置的元素。
EgetFirst()返回此列表中的第一个元素。
EgetLast()返回此列表中的最后一个元素。
intindexOf(Object o)返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
intlastIndexOf(Object o)返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
ListIterator<E>listIterator(int index)从列表中的指定位置开始,返回此列表中元素的列表迭代器(按正确顺序)。
booleanoffer(E e)将指定的元素添加为此列表的尾部(最后一个元素)。
booleanofferFirst(Ee)在此列表的前面插入指定的元素。
booleanofferLast(E e)在此列表的末尾插入指定的元素。
Epeek()检索但不删除此列表的头部(第一个元素)。
EpeekFirst()检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
EpeekLast()检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。
Epoll()检索并删除此列表的头部(第一个元素)。
EpollFirst()检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。
EpollLast()检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。
Epop()弹出此列表所代表的堆栈中的元素。
voidpush(E e)将元素推送到此列表所表示的堆栈上。
Eremove()检索并删除此列表的头部(第一个元素)。
Eremove(int index)删除此列表中指定位置的元素。
booleanremove(Object o)从该列表中删除指定元素的第一个匹配项(如果存在)。
EremoveFirst()从此列表中删除并返回第一个元素。
booleanremoveFirstOccurrence(Object o)删除此列表中第一次出现的指定元素(从头到尾遍历列表时)。
EremoveLast()从此列表中删除并返回最后一个元素。
booleanremoveLastOccurrence(Object o)删除此列表中最后一次出现的指定元素(从头到尾遍历列表时)。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素。
intsize()返回此列表中的元素数。
Spliterator<E>spliterator()在此列表中的元素上创建late-binding和_故障快速_ Spliterator
Object[]toArray()以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
T[]toArray(T[] a)以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
/**
 * 例题5_4运用LinkedList 链接列表 模拟栈结构(Stack)
 * 插入、删除的一端为栈顶Top。另一端为栈底Bottom。栈为后进先出的线性表-LIFO表。
 */

public class Example5_4 {
	// 创建LinkedList对象 private私有作用域,只能在本类中有效。
	private LinkedList list = new LinkedList();

	// 入栈 每加一个之前,整体往右移动一个位置
	public void push(Object o) {
		list.addFirst(o);
	}

	// 出栈 栈顶为开头元素
	public Object pop() {
		return list.removeFirst();
	}

	// 获取栈顶元素
	public Object peek() {
		return list.getFirst();
	}

	// 栈是否为空
	public boolean empty() {
		return list.isEmpty();
	}

	public static void main(String[] args) {
		//因为方法不是类方法,所以要实例化后,才能被使用
		Example5_4 stack = new Example5_4();

		// 入栈
		stack.push("王小二"); //第1个进栈,作为栈底。
		stack.push("张小三");
		stack.push("李小四"); //最后1个进栈,作为栈顶。

		// 出栈
		System.out.println("出栈元素:" + stack.pop());

		// 显示栈顶元素
		System.out.println("栈顶元素:" + stack.peek());

		// 出栈
		System.out.println("出栈元素:" + stack.pop());

		// 显示栈顶元素
		System.out.println("栈顶元素:" + stack.peek());

		System.out.println("栈是否为空:" + stack.empty());
	}
}
/**
 * 例题5_6 运用LinkedList模拟队列结构(Queue)
 * 队列只允许在一端插入-队尾Rear,而在另一端删除-对头Front的运算受限的线性表。队列为先进先出-FIFO表。
 */
public class Example5_5 {
	// 创建LinkedList对象 私有
	private LinkedList list = new LinkedList();

	// 入队 每加一个之前,整体往左移动一个位置
	public void put(Object o) {
		list.addLast(o);
	}

	// 出队:使用removeFirst()方法,返回队列中第一个数据,然后将它从队列中删除
	public Object get() {
		return list.removeFirst();
	}

	// 队列是否为空
	public boolean empty() {
		return list.isEmpty();
	}

	public static void main(String[] args) {

		Example5_5 queue = new Example5_5();
		// 入队
		queue.put("王小二"); //第一个入队列,为队头
		queue.put("张小三");
		queue.put("李小四"); //最后一个入队列,为队尾

		// 出队
		System.out.println("出队元素:" + queue.get());
		System.out.println("出队元素:" + queue.get());
		System.out.println("出队元素:" + queue.get());

		// 判断队列是否为空
		System.out.println("队列是否为空:" + queue.empty());
	}
}

5.7 Stack类(实现同步、线程安全)

定义:Stack堆栈是Vector的一个子类,表示后进先出(LIFO)的对象堆栈。 它通过五个操作扩展了类Vector ,允许将向量视为堆栈。 提供了通常的push和pop操作,以及在堆栈顶部项目中的peek的方法,用于测试堆栈是否为empty的方法,以及用于项目的堆栈的方法以及发现它的距离search是从顶部。
Deque接口及其实现提供了更完整和一致的LIFO堆栈操作集,应优先使用此类。 例如:
Deque stack = new ArrayDeque();

方法摘要

变量和类型方法描述
booleanempty()测试此堆栈是否为空。
Epeek()查看此堆栈顶部的对象,而不将其从堆栈中删除。
Epop()移除此堆栈顶部的对象,并将该对象作为此函数的值返回。
Epush(E item)将项目推到此堆栈的顶部。
intsearch(Object o)返回对象在此堆栈上的从1开始的位置。
//例题5_7 向堆栈Stack中添加元素并弹出

public class Example5_7 {
	public static void main(String[] args) {
		Stack stack1 = new Stack();// 构造一个空堆栈stack1
		try {
			stack1.push(new Integer(0)); //堆栈底
			stack1.push(new Integer(1));
			stack1.push(new Integer(2));
			stack1.push(new Integer(3));
			stack1.push(new Integer(4)); //堆栈顶

			System.out.print((Integer) stack1.pop()+"\n"); //默认输出时,末尾是没有换行符的。
			System.out.print("  "+(Integer) stack1.pop());
			System.out.print("  "+(Integer) stack1.pop());
			System.out.print("  "+(Integer) stack1.pop());
			System.out.print("  "+(Integer) stack1.pop()); //pop返回栈顶元素并删除

			System.out.print(stack1.empty()); //peek只返回栈顶元素,在堆栈为空时,抛出异常。

		} catch (EmptyStackException e) {
			e.printStackTrace();
		}
	}
}



Java中_PriorityQueue_实现了_Queue_接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为_PriorityQueue_的底层实现。

5.8 Vector类(实现同步、线程安全)

定义:Vector提供向量(Vector)类以实现类似动态数组的功能,与ArrayList相似,但Vector的线程是安全同步的。Vector类实现了可增长的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是 Vector的大小可以根据需要增大或缩小,以便在创建Vector后添加和删除项目。

构造方法摘要

构造器描述
Vector()构造一个空向量,使其内部数据数组的大小为 10 ,其标准容量增量为零。
Vector(int initialCapacity)构造一个具有指定初始容量且容量增量等于零的空向量。
Vector(int initialCapacity, int capacityIncrement)构造具有指定初始容量和容量增量的空向量。
Vector(Collection<? extends E> c)按照集合的迭代器返回的顺序构造一个包含指定集合元素的向量。

方法摘要

变量和类型方法描述
voidadd(int index, E element)将指定元素插入此Vector中的指定位置。
booleanadd(E e)将指定的元素追加到此Vector的末尾。
booleanaddAll(int index,Collection<extends E> c)将指定Collection中的所有元素插入到此Vector中的指定位置。
booleanaddAll(Collection<? extends E> c)将指定Collection中的所有元素追加到此Vector的末尾,按照指定Collection的Iterator返回的顺序。
voidaddElement(E obj)将指定的组件添加到此向量的末尾,将其大小增加1。
intcapacity()返回此向量的当前容量。
voidclear()从此Vector中删除所有元素。
Objectclone()返回此向量的副本。
booleancontains(Object o)如果此向量包含指定的元素,则返回 true 。
booleancontainsAll(Collection<?> c)如果此Vector包含指定Collection中的所有元素,则返回true。
voidcopyInto(Object[] anArray)将此向量的组件复制到指定的数组中。
EelementAt(int index)返回指定索引处的组件。
Enumeration<E>elements()返回此向量的组件的枚举。
voidensureCapacity(int minCapacity)如有必要,增加此向量的容量,以确保它至少可以容纳由minimum capacity参数指定的组件数。
booleanequals(Object o)将指定的Object与此Vector进行比较以获得相等性。
EfirstElement()返回此向量的第一个组件(索引 0处的项)。
voidforEach(Consumer<? super E> action)对 Iterable每个元素执行给定操作,直到处理 Iterable所有元素或操作引发异常。
Eget(int index)返回此Vector中指定位置的元素。
inthashCode()返回此Vector的哈希码值。
intindexOf(Object o)返回此向量中第一次出现的指定元素的索引,如果此向量不包含该元素,则返回-1。
intindexOf(Object o, int index)返回此向量中第一次出现的指定元素的索引,从 index向前搜索,如果找不到该元素,则返回-1。
voidinsertElementAt(E obj, int index)将指定对象作为此向量中的组件插入指定的 index 。
booleanisEmpty()测试此向量是否没有组件。
Iterator<E>iterator()以适当的顺序返回此列表中元素的迭代器。
ElastElement()返回向量的最后一个组件。
intlastIndexOf(Object o)返回此向量中指定元素最后一次出现的索引,如果此向量不包含该元素,则返回-1。
intlastIndexOf(Object o, int index)返回此向量中最后一次出现的指定元素的索引,从 index向后搜索,如果找不到该元素,则返回-1。
ListIterator<E>listIterator()返回此列表中元素的列表迭代器(按适当顺序)。
ListIterator<E>listIterator(int index)从列表中的指定位置开始,返回列表中元素的列表迭代器(按正确顺序)。
Eremove(int index)删除此Vector中指定位置的元素。
booleanremove(Object o)删除此向量中第一次出现的指定元素如果向量不包含该元素,则不会更改。
booleanremoveAll(Collection<?> c)从此Vector中删除指定Collection中包含的所有元素。
voidremoveAllElements()从此向量中移除所有组件并将其大小设置为零。
booleanremoveElement(Object obj)从此向量中移除参数的第一个(索引最低)事件。

| void | removeElementAt
(int index) | 删除指定索引处的组件。 |
| boolean | removeIf
(Predicate<? super [E](https://www.runoob.com/manual/jdk11api/java.base/java/util/Vector.html)> filter) | 删除此集合中满足给定谓词的所有元素。 | | protected void | [removeRange](https://www.runoob.com/manual/jdk11api/java.base/java/util/Vector.html#removeRange(int,int))(int fromIndex, int toIndex) | 从此列表中删除索引介于 fromIndex (含)和 toIndex (独占)之间的所有元素。 | | void | [replaceAll](https://www.runoob.com/manual/jdk11api/java.base/java/util/Vector.html#replaceAll(java.util.function.UnaryOperator))([UnaryOperator](https://www.runoob.com/manual/jdk11api/java.base/java/util/function/UnaryOperator.html)<[E](https://www.runoob.com/manual/jdk11api/java.base/java/util/Vector.html)> operator) | 将该列表的每个元素替换为将运算符应用于该元素的结果。 | | boolean | [retainAll](https://www.runoob.com/manual/jdk11api/java.base/java/util/Vector.html#retainAll(java.util.Collection))([Collection](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collection.html)<?> c) | 仅保留此Vector中包含在指定Collection中的元素。 |
| E | set(int index, E element) | 用指定的元素替换此Vector中指定位置的元素。 |
| void | setElementAt
(E
obj, int index) | 将此向量的指定 index处的组件设置为指定对象。 |
| void | setSize(int newSize) | 设置此向量的大小。 |
| int | size() | 返回此向量中的组件数。 |
| Spliterator<E> | spliterator() | 在此列表中的元素上创建late-binding和_失败快速_ Spliterator 。 |
| List<E> | subList(int fromIndex, int toIndex) | 返回此List的部分在fromIndex(包含)和toIndex(独占)之间的视图。 |
| Object[] | toArray() | 以正确的顺序返回包含此Vector中所有元素的数组。 |
| T[] | toArray(T[] a) | 以正确的顺序返回包含此Vector中所有元素的数组; 返回数组的运行时类型是指定数组的运行时类型。 |
| String | toString
() | 返回此Vector的字符串表示形式,包含每个元素的String表示形式。 |
| void | trimToSize() | 修剪此向量的容量为向量的当前大小。 |

任务5.3 删除房源信息设计

5.9 Set接口

定义:Set接口是Collection的子接口,不允许集合中有重复项,依赖equals()方法检查独一性。
实现类:HashSet、TreeSet、LinkedHashSet

方法摘要

变量和类型方法描述
booleanadd(E e)如果指定的元素尚不存在,则将其添加到此集合(可选操作)。
booleanaddAll(Collection<? extends E> c)如果指定集合中的所有元素尚未存在(可选操作),则将其添加到此集合中。
voidclear()从该集合中删除所有元素(可选操作)。
booleancontains(Object o)如果此set包含指定的元素,则返回 true 。
booleancontainsAll(Collection<?> c)如果此集合包含指定集合的所有元素,则返回 true 。
static SetcopyOf(Collection<? extends E> coll)返回包含给定Collection的元素的 unmodifiable Set
booleanequals(Object o)将指定对象与此set进行相等性比较。
inthashCode()返回此set的哈希码值。
booleanisEmpty()如果此集合不包含任何元素,则返回 true 。
Iterator<E>iterator()返回此set中元素的迭代器。
static Setof()返回包含零元素的不可修改集。
static Setof(E e1)返回包含一个元素的不可修改集。
static Setof(E… elements)返回包含任意数量元素的不可修改集。
static Setof(E e1, E e2)返回包含两个元素的不可修改集。
static Setof(E e1, E e2, E e3)返回包含三个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4)返回包含四个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5)返回包含五个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5, E e6)返回包含六个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5, E e6, E e7)返回包含七个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)返回包含八个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)返回包含九个元素的不可修改集。
static Setof(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)返回包含十个元素的不可修改集。
booleanremove(Object o)如果存在,则从该集合中移除指定的元素(可选操作)。
booleanremoveAll(Collection<?> c)从此集合中删除指定集合中包含的所有元素(可选操作)。
booleanretainAll(Collection<?> c)仅保留此集合中包含在指定集合中的元素(可选操作)。
intsize()返回此集合中的元素数(基数)。
default Spliterator<E>spliterator()在此集合中的元素上创建 Spliterator 。
Object[]toArray()返回包含此set中所有元素的数组。
T[]toArray(T[] a)返回一个包含此set中所有元素的数组; 返回数组的运行时类型是指定数组的运行时类型。

5.10 hashCode和equal方法

image.png

  1. hashCode方法
    定义:在Java中,哈希码代表对象的特征,hashCode()是用来计算哈希值的。主要用于帮助集合中元素的定位。哈希码并不完全唯一,它是一种算法。
  2. equals方法
    定义:equals是判断2个对象是否相等的方法,在Object类里有实现,判断的是2个对象的内存地址。
    equals和“==”的区别:equals是指内容相等,==是指地址相等,都来自于Object。没有重写equals方法的类,它们是一样的。基础数据类型和重写equals方法的类,则不是。
  3. 重写hashcode和equals方法
    定义:先hashCode方法,哈希值不同,则不需调用equals方法。哈希值一样,再调用equals方法继续比较。equals相同,说明元素存在。equals不同,在散列一次计算该元素的hashCode(),若此时位置为空,说明元素不存在。若存在元素,在进行eqauls,反复下去。
    hashcode和equals的关系
    equals相等,hashCode必须相等。equals不相等,hashCode有可能会相等。hashCode不相等,equals肯定不相等。
public class Point extends Object{
	private double x;
	private double y;

	public Point() {
		super(); //调用父类的无参构造
	}

	public Point(double x, double y) {
		super(); //调用父类的有参构造
		this.x = x;
		this.y = y;
	}

	public double getX() {
		return x;
	}

	public void setX(double x) {
		this.x = x;
	}

	public double getY() {
		return y;
	}

	public void setY(double y) {
		this.y = y;
	}

	@Override
	public String toString() {
		return this.x + " " + this.y;
	}

	//重写hashCode方法-使用hashCode方法计算哈希值???????
	//这里重写的是Object类的hashCode()
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		//计算哈希码值
		temp = Double.doubleToLongBits(x);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(y);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	//重写equals方法-判断x与y是否相等-内容相等???????????
	//这里重写的是Object类的equals(Object obj)
	@Override
	public boolean equals(Object obj) {
		if (this == obj) //this代表对象Point
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Point other = (Point) obj;
		if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
			return false;
		if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
			return false;
		return true;
	}
}
/**
 * 例题5_8重写hashcode及equals方法测试
 */
public class Example5_8 {
    public static void main(String[] args)
    {
        //实例化数组列表 允许重复,按特定顺序排列
        ArrayList al=new ArrayList();
        Point rp1=new Point(3,3);
        Point rp2=new Point(5,6);
        Point rp3=new Point(3,3);

        al.add(rp1);
        al.add(rp2);
        al.add(rp3);
        al.add(rp1);
        System.out.println("list:"+al.size());//list: 4
        System.out.println(al);

        //实例化Set集合 不允许重复,不按特定顺序排列
        Set hs=new HashSet();
        hs.add(rp1);
        hs.add(rp2);
        hs.add(rp3);
        hs.add(rp1);
        //重写了hashCode方法和equals方法,rp1重复添加了,只添加一个rp1,rp1和rp3也重复,不添加rp3
        System.out.println("hs:"+hs.size()); //hs:2 [集合内存放的是rp1和rp2]
        System.out.println(hs);//[3 3, 5 6]

        //问题?????????????
        //集合中添加了元素rp1后,修改对象rp1的成员变量值,这个成员变量是参与了hashCode()值的运算,进行移除rp1操作

        rp1.setX(100.0); //因为对rp1修改,删除,新增,都会修改hashCode值。修改后就不能移除原来的rp1对象。
        hs.remove(rp1);//移除元素,移除失败。
        // 但可以放在修改前移除,就可以成功移除。
        //发现还是2个元素,remove方法因为哈希值被修改了,无法移除原来的rp1对象,造成内存泄露!!
        System.out.println(hs);
    }
}

5.11 HashSet类-哈希值(实现不同步、线程不安全)

定义:HashSet类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。允许null元素。不保证Set的迭代顺序,不保证顺序恒久不变。hashset类实现不是同步的
Java8 对 HashSet 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
前面已经说过_HashSet_是对_HashMap_的简单包装,对_HashSet_的函数调用都会转换成合适的_HashMap_方法,因此_HashSet_的实现非常简单,只有不到300行代码。

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。 [1]
红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。 [2]
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。 [2]
红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL 。

方法摘要

变量和类型方法描述
booleanadd(E e)如果指定的元素尚不存在,则将其添加到此集合中。
voidclear()从该集中删除所有元素。
Objectclone()返回此 HashSet实例的浅表副本:未克隆元素本身。
booleancontains(Object o)如果此set包含指定的元素,则返回 true 。
booleanisEmpty()如果此集合不包含任何元素,则返回 true 。
Iterator<E>iterator()返回此set中元素的迭代器。
booleanremove(Object o)如果存在,则从该集合中移除指定的元素。
intsize()返回此集合中的元素数(基数)。
Spliterator<E>spliterator()在此集合中的元素上创建late-binding和_失败快速_ Spliterator
/**
 * //例题5_9HashSet类的方法测试
 */
public class Example5_9 {
	public static void main(String[] args) {
		// 创建HashSet对象
		Set set = new HashSet();

		// set中添加元素
		set.add("Aaron");
		set.add("Abel");
		set.add("Adam");

		//输出set中元素数目
		System.out.println("set.size=" + set.size());

		//添加一个已存在元素,不会报错,只是添加无效。
		set.add("Abel");
		System.out.println("添加与存在的元素后的set.size=" + set.size());

		// HashSet元素的遍历
		Iterator iterator = set.iterator();
		System.out.println("set集合中的元素是:");
		//循环是否存在另一个可访问的元素iterator.hasNext()
		while (iterator.hasNext()) {
			//返回要访问的下一个元素iterator.next()
			System.out.print(iterator.next() + " ");
		}
	}
}

5.12 Comparble自比较接口

定义:Comparable接口适用于一个有自然顺序的类,把同一类型的集合排序成自然顺序。
注意:若元素所在类实现类Comparable接口,可以直接使用Collections或Arrays类的sort方法对集合或数组排序。

//模型类实现Comparable接口 把集合排序成自然排序
public class Customer implements Comparable {
	private String name;
	private int age;

	public Customer(String name, int age) {
		this.age = age;
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public boolean equals(Object obj) {
		// 重写equals方法
		if (this == obj) //地址比对
			return true;
		if (!(obj instanceof Customer))
			return false;
		final Customer other = (Customer) obj;
		if (this.name.equals(other.getName()) && this.age == other.getAge()) //内容比对
			return true;
		else
			return false;
	}

	//重写Comparable接口下的compareTo(Object o)方法
	//把集合排序成自然顺序,从大到小,从长到短。
	public int compareTo(Object o) {
		Customer other = (Customer) o;
		// 先按照name属性排序
		if (this.name.compareTo(other.getName()) > 0)
			return 1; //在o后面
		if (this.name.compareTo(other.getName()) < 0)
			return -1; //在o前面
		// 再按照age属性排序
		if (this.age > other.getAge())
			return 1; //在o后面
		if (this.age < other.getAge())
			return -1; //在o前面
		return 0; //位置相同
	}

	//hashCode()方法,提供快速定位集合中元素的位置,提高查询/插入速度。
	@Override
	public int hashCode() {
		// 重写equals方法必须重写hashCode方法
		int result;
		//name不为空 取出哈希值
		result = (name == null ? 0 : name.hashCode());
		result = 29 * result + age;
		return result;
	}

	//输出Customer对象时,自动调用toString方法输出相关内容
	public String toString() {
		return "姓名:" + this.getName() + "  年龄:" + this.getAge();
	}
}
/**
 * 例题5_10Comparable接口使用测试-静态绑定排序
 * 把集合中元素排成自然顺序,先名称、再年龄
 */

public class Example5_10 {
	public static void main(String[] args) {
		Set<Customer> set = new HashSet<Customer>();
		//compareTo(Object o)方法把集合排序成自然顺序,从大到小,从长到短。
		Customer customer1 = new Customer("Tom", 17);
		Customer customer2 = new Customer("Tony", 16);
		Customer customer3 = new Customer("Tony1", 15);
		set.add(customer1);
		set.add(customer2);
		set.add(customer3);

		System.out.println(set.size());
		//System.out.println(customer1.compareTo(customer2)); //返回-1,表示目前对象1在对象2前面(自然排序前)
		System.out.println(set);
	}
}

5.13 TreeSet类-树结构(实现不同步、线程不安全)

定义:TreeSet类实现Set接口,还实现了java.util.SortedSet接口,保证遍历集合时按照递增的顺序获取对象。
注意:实现Set集合中的对象,必须实现Comparable接口,也可以指定比较器递增排序。肯定可以比较对象大小,从而实现对象排序。

TreeSet底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(), get(), put(), remove()都有着log(n)的时间复杂度。
说_TreeSet里面有一个TreeMap_(适配器模式)

方法摘要

变量和类型方法描述
booleanadd(E e)如果指定的元素尚不存在,则将其添加到此集合中。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素添加到此集合中。
Eceiling(E e)返回此set中大于或等于给定元素的 null元素,如果没有这样的元素,则 null 。
voidclear()从该集中删除所有元素。
Objectclone()返回此 TreeSet实例的浅表副本。
booleancontains(Object o)如果此set包含指定的元素,则返回 true 。
Iterator<E>descendingIterator()以降序返回此集合中元素的迭代器。
NavigableSet<E>descendingSet()返回此set中包含的元素的逆序视图。
Efirst()返回此集合中当前的第一个(最低)元素。
Efloor(E e)返回此set中小于或等于给定元素的最大元素,如果没有这样的元素,则 null 。
SortedSet<E>headSet(E toElement)返回此set的部分视图,其元素严格小于 toElement 。
NavigableSet<E>headSet(E toElement, boolean inclusive)返回此set的部分视图,其元素小于(或等于,如果 inclusive为true) toElement 。
Ehigher(E e)返回此集合中的最小元素严格大于给定元素,如果没有这样的元素,则 null 。
booleanisEmpty()如果此集合不包含任何元素,则返回 true 。
Iterator<E>iterator()以升序返回此集合中元素的迭代器。
Elast()返回此集合中当前的最后一个(最高)元素。
Elower(E e)返回此集合中的最大元素严格小于给定元素,如果没有这样的元素,则 null 。
EpollFirst()检索并删除第一个(最低)元素,如果此组为空,则返回 null 。
EpollLast()检索并删除最后一个(最高)元素,如果此集合为空,则返回 null 。
booleanremove(Object o)如果存在,则从该集合中移除指定的元素。
intsize()返回此集合中的元素数(基数)。
Spliterator<E>spliterator()在此集合中的元素上创建late-binding和_故障快速_ Spliterator
NavigableSet<E>subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)返回此set的部分视图,其元素范围为 fromElement到 toElement 。
SortedSet<E>subSet(E fromElement, E toElement)返回此set的部分视图,其元素范围从 fromElement (含)到 toElement (独占)。
SortedSet<E>tailSet(E fromElement)返回此set的部分视图,其元素大于或等于 fromElement 。
NavigableSet<E>tailSet(E fromElement, boolean inclusive)返回此set的部分视图,其元素大于(或等于,如果 inclusive为true) fromElement 。
/**
 * 例题5_11TreeSet类的方法测试-树型集合
 */
public class Example5_11 {
	public static void main(String[] args) {
		/**
		 * 创建TreeSet对象,它不仅是实现了Set接口,还是实现了java.util.SortedSet接口,遍历集合时递增顺序获取对象。
		 */
		Set set = new TreeSet();

		// set中添加元素   添加的对象必须实现Comparable接口,也可以是指定比较其递增排序。不然抛出RuntimeException错误
		set.add("jack");
		set.add("alen");
		set.add("rose");
		set.add("black");
		set.add("helo");

		System.out.println("set.size=" + set.size());

		// TreeSet中元素遍历(默认从小到大) TreeSet类让遍历集合时递增顺序获取对象(这里是按照首字母顺序排列)
		Iterator iterator = set.iterator();
		System.out.println("显示set中所有元素");
		while (iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
	}
}

任务5.4 查询房源信息设计

5.14 Map接口

定义:Map是一种键对象和值对象关联的容器,键不重复,值可重复,没有继承Collection接口。值对象可以是Map,以此类推,实现多级映射。
Map提供三种集合视图,1一组key集合、2一组value集合、3一组key-value映射。
实现类:HashMap、Hashtable、HashMap子类LinkedHashMap、SortedMap子接口及其实现类TreeMap。
Map内部类Entry,封装了一个key-value对。Map是特殊的Set,不过元素是Entry对象Map.Entry<K,V>。

方法摘要

voidclear()从此映射中删除所有映射(可选操作)。
default Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)尝试计算指定键及其当前映射值的映射(如果没有当前映射, null )。
default VcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)如果指定的键尚未与值关联(或映射到 null ),则尝试使用给定的映射函数计算其值并将其输入此映射,除非 null 。
default VcomputeIfPresent(K key,BiFunction<? super K,? super V,? extends V> remappingFunction)如果指定键的值存在且为非null,则尝试在给定键及其当前映射值的情况下计算新映射。
booleancontainsKey(Object key)如果此映射包含指定键的映射,则返回 true 。
booleancontainsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true 。
static <K,V> Map<K,V>copyOf(Map<? extends K,? extends V> map)返回包含给定Map的条目的 unmodifiable Map
static <K,V> Map.Entry<K,V>entry(K k, V v)返回包含给定键和值的不可修改的Map.Entry
Set<Map.Entry<K,V>>entrySet()返回此映射中包含的映射的Set视图。
booleanequals(Object o)将指定对象与此映射进行比较以获得相等性。
default voidforEach(BiConsumer<? super K,? super V> action)对此映射中的每个条目执行给定操作,直到处理完所有条目或操作引发异常。
Vget(Object key)返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。
default VgetOrDefault(Object key, V defaultValue)返回指定键映射到的值,如果此映射不包含键的映射,则返回 defaultValue 。
inthashCode()返回此映射的哈希码值。
booleanisEmpty()如果此映射不包含键 - 值映射,则返回 true 。
Set<K>keySet()返回此映射中包含的键的Set视图。
default Vmerge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)如果指定的键尚未与值关联或与null关联,则将其与给定的非空值关联。
static <K,V> Map<K,V>of()返回包含零映射的不可修改映射。
static <K,V> Map<K,V>of(K k1, V v1)返回包含单个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2)返回包含两个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3)返回包含三个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4)返回包含四个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4, K k5, V v5)返回包含五个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4, K k5, V v5, K k6, V v6)返回包含六个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3,K k4, V v4, K k5, V v5, K k6, V v6, K k7,V v7)返回包含七个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8)返回包含八个映射的不可修改的映射。
static <K,V> Map<K,V>of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9)返回包含九个映射的不可修改的映射。

| static <K,V> Map<K,V> | of
(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) | 返回包含十个映射的不可修改的映射。 |
| static <K,V> Map<K,V> | ofEntries(Map.Entry<? extends K,? extends V>… entries) | 返回包含从给定条目中提取的键和值的不可修改的映射。 |
| V | put(K key, V value) | 将指定的值与此映射中的指定键相关联(可选操作)。 |
| void | putAll(Map<? extends K,? extends V> m) | 将指定映射中的所有映射复制到此映射(可选操作)。 |
| default V | putIfAbsent(K key, V value) | 如果指定的键尚未与值关联(或映射到 null ), null其与给定值关联并返回 null ,否则返回当前值。 |
| V | remove(Object key) | 如果存在,则从该映射中移除键的映射(可选操作)。 |
| default boolean | remove(Object key, Object value) | 仅当指定键当前映射到指定值时才删除该条目的条目。 |
| default V | replace(K key, V value) | 仅当指定键当前映射到某个值时,才替换该条目的条目。 |
| default boolean | replace(K key, V oldValue, V newValue) | 仅当前映射到指定值时,才替换指定键的条目。 |
| default void | replaceAll(BiFunction<? super K,? super V,? extends V> function) | 将每个条目的值替换为在该条目上调用给定函数的结果,直到所有条目都已处理或函数抛出异常。 |
| int | size() | 返回此映射中键 - 值映射的数量。 |
| Collection<V> | values() | 返回此映射中包含的值的Collection视图。 |

5.15 HashMap类(实现不同步、线程不安全)

定义:HashMap类是基于哈希表的Map接口的实现,允许使用null值和null键。不保证映射的顺序,不保证顺序恒久不变。用到了哈希值算法。
Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
可将_LinkedHashMap_看作采用_linked list_增强的_HashMap_。

方法摘要

voidclear()从此映射中删除所有映射。
Objectclone()返回此 HashMap实例的浅表副本:未克隆键和值本身。
Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)尝试计算指定键及其当前映射值的映射(如果没有当前映射, null )。
VcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)如果指定的键尚未与值关联(或映射到 null ),则尝试使用给定的映射函数计算其值并将其输入此映射,除非 null 。
VcomputeIfPresent(K key,BiFunction<? super K,? super V,? extends V> remappingFunction)如果指定键的值存在且为非null,则尝试在给定键及其当前映射值的情况下计算新映射。
booleancontainsKey(Object key)如果此映射包含指定键的映射,则返回 true 。
booleancontainsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true 。
Set<Map.Entry<K,V>>entrySet()返回此映射中包含的映射的Set视图。
Vget(Object key)返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。
booleanisEmpty()如果此映射不包含键 - 值映射,则返回 true 。
Set<K>keySet()返回此映射中包含的键的Set视图。
Vmerge(K key, V value, BiFunction<? super V,?super V,? extends V> remappingFunction)如果指定的键尚未与值关联或与null关联,则将其与给定的非空值关联。
Vput(K key, V value)将指定的值与此映射中的指定键相关联。
voidputAll(Map<? extends K,? extends V> m)将指定映射中的所有映射复制到此映射。
Vremove(Object key)从此映射中删除指定键的映射(如果存在)。
intsize()返回此映射中键 - 值映射的数量。
Collection<V>values()返回此映射中包含的值的Collection视图。
public class Student {
	private String no;
	private String name;
	private int age;
	private String address;

	public Student() {
		//但没有继承类时,每个类默认继承Object类。super()调用Object类的无参构造方法
		super();
	}

	public Student(String no, String name, int age, String address) {
		super();
		this.no = no;
		this.name = name;
		this.age = age;
		this.address = address;
	}

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	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 getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	//重写hashCode方法-使用hashCode方法为Student对象计算哈希值
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((no == null) ? 0 : no.hashCode());
		return result;
	}

	//重写equals方法-判断x与y是否相等-内容相等
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (no == null) {
			if (other.no != null)
				return false;
		} else if (!no.equals(other.no))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "学生学号:   " + this.getNo() + "学生姓名:   " + this.getName()
				+ "学生年龄:   " + this.getAge() + "学生地址:   " + this.getAddress();
	}
}
/**
 * 例题5_12HashMap类的方法测试
 */

public class Example5_12 {
	public static void main(String[] args) {

		//创建HashMap对象
		Map map=new HashMap();

		//创建学生对象
		Student stu1=new Student();
		stu1.setNo("0908001");
		stu1.setName("张阳");
		stu1.setAge(20);
		stu1.setAddress("江苏徐州");

		Student stu2=new Student();
		stu2.setNo("0908002");
		stu2.setName("孙旭");
		stu2.setAge(19);
		stu2.setAddress("江苏常州");

		Student stu3=new Student();
		stu3.setNo("0908003");
		stu3.setName("李东");
		stu3.setAge(21);
		stu3.setAddress("江苏苏州");

		//以stuNo为key,student对象为value保存中map中   这里按年龄进行递增排序
		map.put(stu1.getNo(), stu1);
		map.put(stu2.getNo(), stu2);
		map.put(stu3.getNo(), stu3);

		System.out.println(map); //Student.toString方法输出格式

		//containsKey:如果此映射包含 对于指定键 的映射关系,则返回 true。
		boolean isContainsKey=map.containsKey(stu1.getNo());
		System.out.println("根据学生学号判断是否包含学生一:"+isContainsKey);

		//containsValue:如果此映射将一个或多个键映射到 指定值 ,则返回 true。
		boolean isContainsValue=map.containsValue(stu2);
		System.out.println("根据学生对象值判断是否包含学生二:"+isContainsValue);

		//get(Object key) :返回指定键所映射的值。
		Student stu=(Student)map.get(stu3.getNo());
		System.out.println("stuName="+stu.getName());

		//entrySet() :返回此映射所包含的映射关系key-value的 Set 视图。
		Set entry=map.entrySet();
		Iterator iterator=entry.iterator();
		System.out.println("映射关系");
		while(iterator.hasNext()){
			System.out.println(iterator.next());
		}

		//keySet() :返回此映射中所包含的键key的 Set 视图。
		Set keys=map.keySet();
		System.out.println("map中的key");
		Iterator iterator1=keys.iterator();
		while(iterator1.hasNext()){
			System.out.println(iterator1.next());
		}

		//遍历HashMap中values 返回所有value组成的collection
		Collection stuValues=map.values();
		System.out.println("map中学生对象");

		Iterator iterator2=stuValues.iterator();
		while(iterator2.hasNext()){
			Student student=(Student)iterator2.next();
			System.out.println(student.getNo()+":"+student.getName()+":"
					+student.getAge()+":"+student.getAddress());
		}

		//remove(Object key) :从此映射中移除指定键的映射关系(如果存在)。
		System.out.println("删除前 的 map.size="+map.size());
		map.remove(stu2.getNo());
		System.out.println("删除后的 map.size="+map.size());

		//clear() :从此映射中移除所有映射关系。 size()表示key-value对的个数
		System.out.println("清除前 的 map.size="+map.size());
		map.clear();
		System.out.println("清除后的 map.size="+map.size());
	}
}

5.16 TreeMap类(实现不同步、线程不安全)

定义:TreeMap类通过使用树实现Map接口。提供了按排序顺序存储关键字/值对的方法,元素按照关键字升序排序,允许快速检索。
_TreeMap_底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(), get(), put(), remove()都有着log(n)的时间复杂度。

方法摘要

变量和类型方法描述
Map.Entry<K,V>ceilingEntry(K key)返回与大于或等于给定键的最小键关联的键 - 值映射,如果没有此键,则 null 。
KceilingKey(K key)返回大于或等于给定键的 null键,如果没有这样的键,则 null 。
voidclear()从此映射中删除所有映射。
Objectclone()返回此 TreeMap实例的浅表副本。
booleancontainsKey(Object key)如果此映射包含指定键的映射,则返回 true 。
booleancontainsValue(Object value)如果此映射将一个或多个键映射到指定值,则返回 true 。
NavigableSet<K>descendingKeySet()返回此映射中包含的键的反向顺序NavigableSet视图。
NavigableMap<K,V>descendingMap()返回此映射中包含的映射的逆序视图。
Set<Map.Entry<K,V>>entrySet()返回此映射中包含的映射的Set视图。
Map.Entry<K,V>firstEntry()返回与此映射中的最小键关联的键 - 值映射,如果映射为空,则 null 。
KfirstKey()返回此映射中当前的第一个(最低)键。
Map.Entry<K,V>floorEntry(K key)返回与小于或等于给定键的最大键关联的键 - 值映射,如果没有此键,则 null 。
KfloorKey(K key)返回小于或等于给定键的最大键,如果没有这样的键,则 null 。
Vget(Object key)返回指定键映射到的值,如果此映射不包含键的映射,则返回 null 。
SortedMap<K,V>headMap(K toKey)返回此映射的部分视图,其键严格小于 toKey 。
NavigableMap<K,V>headMap(K toKey, boolean inclusive)返回此映射的部分视图,其键小于(或等于,如果 inclusive为真) toKey 。
Map.Entry<K,V>higherEntry(K key)返回与严格大于给定键的最小键关联的键 - 值映射,如果没有此键,则 null 。
KhigherKey(K key)返回严格大于给定键的最小键,如果没有这样的键,则返回 null 。
Set<K>keySet()返回此映射中包含的键的Set视图。
Map.Entry<K,V>lastEntry()返回与此映射中的最大键关联的键 - 值映射,如果映射为空,则 null 。
KlastKey()返回此映射中当前的最后一个(最高)键。
Map.Entry<K,V>lowerEntry(K key)返回与严格小于给定键的最大键相关联的键 - 值映射,如果没有这样的键,则 null 。
KlowerKey(K key)返回严格小于给定键的最大键,如果没有这样键,则返回 null 。
NavigableSet<K>navigableKeySet()返回此映射中包含的键的NavigableSet视图。
Map.Entry<K,V>pollFirstEntry()删除并返回与此映射中的最小键关联的键 - 值映射,如果映射为空,则 null 。
Map.Entry<K,V>pollLastEntry()删除并返回与此映射中的最大键关联的键 - 值映射,如果映射为空,则 null 。
Vput(K key, V value)将指定的值与此映射中的指定键相关联。
voidputAll(Map<? extends K,? extends V> map)将指定映射中的所有映射复制到此映射。
Vremove(Object key)如果存在,则从此TreeMap中删除此键的映射。
intsize()返回此映射中键 - 值映射的数量。
NavigableMap<K,V>subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)返回此映射部分的视图,其键范围为 fromKey至 toKey 。
SortedMap<K,V>subMap(K fromKey, K toKey)返回此映射部分的视图,其键的范围从 fromKey (包括 toKey )到 toKey (独占)。
SortedMap<K,V>tailMap(K fromKey)返回此映射的部分视图,其键大于或等于 fromKey 。
NavigableMap<K,V>tailMap(K fromKey, boolean inclusive)返回此映射的部分视图,其键大于(或等于,如果 inclusive为真) fromKey 。
Collection<V>values()返回此映射中包含的值的Collection视图。

5.17 Comparator接口

定义:Comparator是自定义指定比较器的自比较接口,提供自然排序功能-从大到小。
区别:Comparable要和具体要进行排序的类的实例绑定,静态绑定排序,只能实现该接口一次。Comparator通过构造方法指定一个比较器可以实现,自定义比较方式,提供多种排序方式,动态绑定排序。

方法摘要

变量和类型方法描述
intcompare(T o1, T o2)比较它的两个参数的顺序。
static <T,U extends Comparable<? super U>>Comparatorcomparing(Function<? super T,? extends U>keyExtractor)接受从类型T中提取Comparable排序键的T ,并返回按该排序键进行比较的Comparator 。

| static <T,U>Comparator | comparing(Function<? super T,?extends U>keyExtractor,
Comparator<? super U> keyComparator) | 接受从类型T中提取排序键的T ,并返回Comparator ,使用指定的Comparator通过该排序键进行比较。 |
| static Comparator | comparingDouble(ToDoubleFunction<? super T> keyExtractor) | 接受从类型 T中提取 double排序键的 T ,并返回按该排序键进行比较的 Comparator 。 |
| static Comparator | comparingInt(ToIntFunction<? super T> keyExtractor) | 接受从类型 T中提取 int排序键的 T ,并返回按该排序键进行比较的 Comparator 。 |
| static Comparator | comparingLong(ToLongFunction<? super T> keyExtractor) | 接受从类型 T中提取 long排序键的 T ,并返回按该排序键进行比较的 Comparator 。 |
| boolean | equals(Object obj) | 指示某个其他对象是否“等于”此比较器。 |
| static <T extends Comparable<? super T>>Comparator | naturalOrder() | 返回一个比较器,按自然顺序比较Comparable个对象。 |
| static Comparator | nullsFirst(Comparator<? super T> comparator) | 返回一个空值友好的比较器, null视为小于非null。 |
| static Comparator | nullsLast(Comparator<? super T> comparator) | 返回一个空值友好的比较器, null视为大于非null。 |
| default Comparator<T> | reversed() | 返回一个比较器,它强制执行此比较器的反向排序。 |
| static <T extends Comparable

<? super T>> [Comparator](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html) | [reverseOrder](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html#reverseOrder())() | 返回一个比较器,它强加 _自然顺序_的反转。 | | default [Comparator](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html)<[T](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html)> | [thenComparing](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html#thenComparing(java.util.Comparator))([Comparator](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html)<? super [T](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html)> other) | 返回带有另一个比较器的字典顺序比较器。 | | default

| static Enumeration | emptyEnumeration() | 返回没有元素的枚举。 |
| static Iterator | emptyIterator() | 返回没有元素的迭代器。 |
| static List | emptyList() | 返回一个空列表(不可变)。 |
| static ListIterator | emptyListIterator() | 返回没有元素的列表迭代器。 |
| static <K,V>Map<K,V> | emptyMap() | 返回一个空映射(不可变)。 |
| static <K,V>NavigableMap<K,V> | emptyNavigableMap() | 返回一个空的可导航地图(不可变)。 |
| static NavigableSet | emptyNavigableSet() | 返回一个空的可导航集(不可变)。 |
| static Set | emptySet() | 返回一个空集(不可变)。 |
| static <K,V>SortedMap<K,V> | emptySortedMap() | 返回一个空的有序映射(不可变)。 |
| static SortedSet | emptySortedSet() | 返回一个空的有序集(不可变)。 |
| static Enumeration | enumeration(Collection c) | 返回指定集合的枚举。 |
| static void | fill(List<? super T> list, T obj) | 用指定的元素替换指定列表的所有元素。 | | static int | [frequency](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collections.html#frequency(java.util.Collection,java.lang.Object))([Collection](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collection.html)<?> c, Object o) | 返回指定集合中等于指定对象的元素数。 |
| static int | indexOfSubList(List<?> source, [List](https://www.runoob.com/manual/jdk11api/java.base/java/util/List.html)<?> target) | 返回指定源列表中第一次出现的指定目标列表的起始位置,如果不存在,则返回-1。 |
| static int | lastIndexOfSubList(List<?> source, [List](https://www.runoob.com/manual/jdk11api/java.base/java/util/List.html)<?> target) | 返回指定源列表中指定目标列表最后一次出现的起始位置,如果不存在,则返回-1。 |
| static ArrayList | list(Enumeration e) | 返回一个数组列表,其中包含指定枚举返回的元素,这些元素按枚举返回的顺序排列。 |
| static <T extends Object & Comparable<? super T>> T | [max](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collections.html#max(java.util.Collection))([Collection](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collection.html)<? extends T> coll) | 根据元素的 _自然顺序_返回给定集合的最大元素。 | | static T | [max](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collections.html#max(java.util.Collection,java.util.Comparator))([Collection](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collection.html)<? extends T> coll, [Comparator](https://www.runoob.com/manual/jdk11api/java.base/java/util/Comparator.html)<? super T> comp) | 根据指定比较器引发的顺序返回给定集合的最大元素。 | | static

| static Collection | synchronizedCollection
(Collection c) | 返回由指定集合支持的同步(线程安全)集合。 |
| static List | synchronizedList(List list) | 返回由指定列表支持的同步(线程安全)列表。 |
| static <K,V>Map<K,V> | synchronizedMap(Map<K,V> m) | 返回由指定映射支持的同步(线程安全)映射。 |
| static <K,V>NavigableMap<K,V> | synchronizedNavigableMap(NavigableMap<K,V> m) | 返回由指定的可导航映射支持的同步(线程安全)可导航映射。 |
| static NavigableSet | synchronizedNavigableSet
(NavigableSet s) | 返回由指定的可导航集支持的同步(线程安全)可导航集。 |
| static Set | synchronizedSet(Set s) | 返回由指定集支持的同步(线程安全)集。 |
| static <K,V>SortedMap<K,V> | synchronizedSortedMap(SortedMap<K,V> m) | 返回由指定的有序映射支持的同步(线程安全)有序映射。 |
| static SortedSet | synchronizedSortedSet(SortedSet s) | 返回由指定有序集支持的同步(线程安全)有序集。 |
| static Collection | unmodifiableCollection(Collection<? extends T> c) | 返回指定集合的 unmodifiable view 。 |
| static List | unmodifiableList(List<? extends T> list) | 返回指定列表的 unmodifiable view 。 |
| static <K,V>Map<K,V> | unmodifiableMap(Map<? extends K,? extends V> m) | 返回指定映射的 unmodifiable view 。 |
| static <K,V>NavigableMap<K,V> | unmodifiableNavigableMap(NavigableMap<K,? extends V> m) | 返回指定的可导航地图的 unmodifiable view 。 |
| static NavigableSet | unmodifiableNavigableSet(NavigableSet s) | 返回指定的可导航集的 unmodifiable view 。 |
| static Set | unmodifiableSet(Set<? extends T> s) | 返回指定集的 unmodifiable view 。 |
| static <K,V>SortedMap<K,V> | unmodifiableSortedMap(SortedMap<K,? extends V> m) | 返回指定有序映射的 unmodifiable view 。 |
| static SortedSet | unmodifiableSortedSet(SortedSet
s) | 返回指定有序集的 unmodifiable view 。 |

/**
 * 例题5_15 Collections集合类的工具 使用测试
 * 主要针对List和Set集合
 */
public class Example5_15 {
	public static void main(String[] args) {
		//实例化一个链接列表,存放String类型数据
		LinkedList<String> list = new LinkedList<String>();
		list.add("1");
		list.add("2");
		list.add("3");

		// 创建一个逆序的比较器-自定义
		Comparator<String> r = Collections.reverseOrder();
		// 通过逆序的比较器进行排序
		Collections.sort(list, r);
		System.out.println("逆序的比较器进行排序******");
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}

		System.out.println("反顺序******");
		// 反顺序-上面反、这里反——得正
		Collections.reverse(list);
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}


		System.out.println("打乱顺序******");
		// 打乱顺序
		Collections.shuffle(list);
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}

		System.out.println("输出最大和最小的数******");
		// 输出最大和最小的数
		System.out.println(Collections.max(list) + ":" + Collections.min(list));
	}
}

队列和栈创建使用

/**
 * @author cmy
 * @version 1.0
 * @date 2022/7/5 0005 16:05
 * @description 队列和栈
 */
public class QueueStack {

    /**
     * 队列练习:先进先出
     *
     * LinkedList底层用的双向链表,下标操作线性时间,头尾删除常数时间,没有实现同步synchronized。
     * LinkedList同时实现了List接口和Deque接口,即可做队列,也可做栈。
     * 关于栈或队列,首选是ArrayDeque,底层通过循环数组实现,比LinkedList(当作栈或队列使用时)更好性能
     * https://blog.csdn.net/tyh1579152915/article/details/118529597
     */
    public static void QueueTest(){
        //add()和remove()方法在失败的时候会抛出异常(不推荐)
        Queue<String> queue = new ArrayDeque<String>();
        //入队:添加元素
        queue.offer("a");
        queue.offer("b");
        queue.offer("c");
        queue.offer("d");
        queue.offer("e");

        //循环输出_出队
        for(String q : queue){
            System.out.println(q);
        }

        System.out.println("===");

        //出队:返回并删除此队列的头部,如果此队列为空,则返回 null
        System.out.println("poll="+queue.poll());
        for(String q : queue){
            System.out.println(q);
        }

        System.out.println("===");

        //返回不删除此队列的头部,为空不抛异常
        System.out.println("element="+queue.element());
        for(String q : queue){
            System.out.println(q);
        }

        System.out.println("===");

        //返回不删除此队列的头部,为空抛异常
        System.out.println("peek="+queue.peek());
        for(String q : queue){
            System.out.println(q);
        }
    }


    /**
     * 入栈
     * @param st
     * @param a
     */
    static void showpush(Deque<Integer> st, int a) {
        st.push(new Integer(a));
        System.out.println("push(" + a + ")");
        System.out.println("stack: " + st);
    }

    /**
     * 出栈
     * @param st
     */
    static void showpop(Deque<Integer> st) {
        System.out.print("pop -> ");
        Integer a = (Integer) st.pop();
        System.out.println(a);
        System.out.println("stack: " + st);
    }

    /**
     * 栈练习:后进先出
     *
     * 栈的重点应该在于 栈先进后出的思想,以及对 入栈(push),出栈(pop) 两种操作的运用。
     * 解决相关括号匹配,迷宫求解,表达式求值等问题,都是一个不错的选择。
     * https://blog.csdn.net/qq_42124842/article/details/91420306
     */

    public static void StackTest(){
        效率低、线程安全
        //Stack<Integer> st = new Stack<Integer>();
        //效率高、线程不安全
        Deque<Integer> st=new ArrayDeque<Integer>();

        System.out.println("stack: " + st);
        showpush(st, 42);
        showpush(st, 66);
        showpush(st, 99);
        showpop(st);
        showpop(st);
        showpop(st);

        //stack为空抛异常
        try {
            showpop(st);
        } catch (EmptyStackException e) {
            System.out.println("empty stack");
        }
    }

    public static void main(String[] args) {
        //队列
        //QueueTest();
        //栈
        StackTest();
    }
}

单元6 图形用户界面设计

任务6.1 用户登录界面设计

6.1 组件概述

6.2 常用容器

6.3 布局管理

任务6.2 求租人信息设置

6.4 按钮

6.5 文本框

6.6 文本域

6.7 单选按钮

6.8 复选框

6.9 列表框

任务6.3 出租人信息设置

6.10 事件处理模型

6.11 常见事件处理

6.12 事件适配器

任务6.4 系统主界面设计

6.13 菜单

6.14 对话框

6.15 树结构视图

6.16 表格

单元7 JDBC

任务7.1 求租人信息查询

7.1 JDBC技术

7.2 JDBC中常用类和接口

7.3 连接数据库

7.4 Statement接口

7.5 ResultSet接口

任务7.2 出租人信息查询设计

7.6 PreparedStatement接口

7.7 CallableStatement接口

7.8 数据库查询

7.9 游动查询

任务7.3 租赁业务处理

7.10 添加数据

7.11 删除数据

7.12 修改数据

ACM IO练习

System.in输入

JDK5之前输入方法,System.in 包装在一个 BufferedReader 对象中来创建一个字符流。

BufferedReader 对象创建后,我们便可以使用 read() 方法从控制台读取一个字符,或者用 readLine() 方法读取一个字符串。

//使用 BufferedReader 在控制台读取字符
 
import java.io.*;
 
public class BRRead {
    public static void main(String[] args) throws IOException {
        char c;
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("输入字符, 按下 'q' 键退出。");
        // 读取字符
        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != 'q');
    }
}
//从标准输入读取一个字符串需要使用 BufferedReader 的 readLine() 方法。
//使用 BufferedReader 在控制台读取字符
import java.io.*;
 
public class BRReadLines {
    public static void main(String[] args) throws IOException {
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        System.out.println("Enter lines of text.");
        System.out.println("Enter 'end' to quit.");
        do {
            str = br.readLine();
            System.out.println(str);
        } while (!str.equals("end"));
    }
}

java.util.Scanner 是 Java5 的新特征,获取用户的输入。

通过 Scanner 类的 next() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要 使用 hasNext 与 hasNextLine 判断是否还有输入的数据。

import java.util.Scanner; 
 
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 从键盘接收数据
 
        // next方式接收字符串
        System.out.println("next方式接收:");
        // 判断是否还有输入
        if (scan.hasNext()) {
            String str1 = scan.next();
            System.out.println("输入的数据为:" + str1);
        }
        scan.close();
    }
}
import java.util.Scanner;
 
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 从键盘接收数据
 
        // nextLine方式接收字符串
        System.out.println("nextLine方式接收:");
        // 判断是否还有输入
        if (scan.hasNextLine()) {
            String str2 = scan.nextLine();
            System.out.println("输入的数据为:" + str2);
        }
        scan.close();
    }
}

next() 与 nextLine() 区别

next():
1、一定要读取到有效字符后才可以结束输入。
2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
next() 不能得到带有空格的字符串。
nextLine():
1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
2、可以获得空白。
如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,但是在输入之前最好先使用 hasNextXxx() 方法进行验证,再使用 nextXxx() 来读取:

System.out输出

制台的输出由 print( ) 和 println() 完成。这些方法都由类 PrintStream 定义,System.out 是该类对象的一个引用。
PrintStream 继承了 OutputStream类,并且实现了方法 write()。这样,write() 也可以用来往控制台写操作。

import java.io.*;
 
//演示 System.out.write().
public class WriteDemo {
    public static void main(String[] args) {
        int b;
        b = 'A';
        System.out.write(b);
        System.out.write('\n');
    }
}

输入输出实例

public class LeetCodeIO {

    public static void main(String[] args) {
        //1、BufferedReader_read()在控制台标准输入中读取一个字符
        //BufferedReader_read();

        //2、BufferedReader_readLine()在控制台标准输入中读取一个字符串
        //BufferedReader_readline();

        //3、通过 Scanner类的next()与nextLine()方法获取输入的字符串。
        //Scanner_next();
        //Scanner_nextLine();
        //Scanner_next_nextLine();

        //4、Scanner读取整数、浮点数等基础数据类型
        //Scanner_baseTypes();

        //5、Scanner读取整型\字符串数组
        //Scanner_StringArray();

        //6、Scanner读取二维数组
        //Scanner_TwoArray();

        //7、Scanner换行读取数字、字符串、字符串数组(包含空格),字符串分割为数组
        Scanner_IntStringArraySpace();
    }

    /**
     * 1、BufferedReader_read()在控制台标准输入中读取一个字符
     *
     * @Test测试启动会无视输入操作
     */
    @Test
    public static void BufferedReader_read() {
        char c;
        //使用System.in创建BufferedReader
        //InputStreamReader:将一个字节的输入流转换为字符的输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("输入字符, 按下 'q' 键退出。");
        // 读取字符
        try {
            do {
                c = (char) br.read();
                System.out.println(c);
            } while (c != 'q');
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 2、BufferedReader_readLine()在控制台标准输入中读取一行字符串
     */
    @Test
    public static void BufferedReader_readline() {
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        System.out.println("Enter lines of text.");
        System.out.println("Enter 'end' to quit.");

        try {
            do {
                str = br.readLine();
                System.out.println(str);
            } while (!str.equals("end"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 3、通过 Scanner类的next()与nextLine()方法获取输入的字符串。
     * java.util.Scanner是Java5的新特征,获取用户的输入。
     * 读取前使用hasNext与hasNextLine判断是否还有输入的数据。
     * <p>
     * next() 与 nextLine() 区别
     * next():
     * 1、一定要读取到有效字符后才可以结束输入。
     * 2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
     * 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
     * 4、next() 不能得到带有空格的字符串。
     * <p>
     * nextLine():
     * 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
     * 2、可以获得空白。
     * <p>
     * 如果要输入 int 或 float 类型的数据,在 Scanner 类中也有支持,
     * 但是在输入之前最好先使用 hasNextXxx() 方法进行验证,再使用 nextXxx() 来读取:
     */
    @Test
    public static void Scanner_next() {
        // 从键盘接收数据
        Scanner scan = new Scanner(System.in);
        // next方式接收字符串
        System.out.println("next方式接收:");
        // 判断是否还有输入
        if (scan.hasNext()) {
            String str1 = scan.next();
            System.out.println("输入的数据为:" + str1);
        }
        scan.close();
    }

    @Test
    public static void Scanner_nextLine() {
        // 从键盘接收数据
        Scanner scan = new Scanner(System.in);
        // nextLine方式接收一行字符串
        System.out.println("nextLine方式接收:");
        // 判断是否还有输入
        if (scan.hasNextLine()) {
            String str2 = scan.nextLine();
            System.out.println("输入的数据为:" + str2);
        }
        scan.close();
    }

    public static void Scanner_next_nextLine() {
        Scanner sc = new Scanner(System.in);
        System.out.println("输入字符串:");

        //next():只读取输入直到空格。空格作为停止符
        String str = sc.next();

        //这里不换行,输入str后,enter直接九结束了,str2为空
        //解决方式:1、将str、str2输入到一行以空格隔开。2、加入sc.nextLine()光标换行操作

        //nextLine():读取输入,包括单词之间的空格和除回车以外的所有符号。回车作为停止符
        String str2 = sc.nextLine();

        System.out.println("str:" + str);
        System.out.println("str2:" + str2);

        //关闭
        sc.close();
    }

    /**
     * 4、Scanner读取整数、浮点数等基础数据类型
     */
    @Test
    public static void Scanner_baseTypes() {
        // 从键盘接收数据
        Scanner scan = new Scanner(System.in);
        // next方式接收整形,以空白为结束符
        System.out.println("nextInt方式接收整型:");
        // 判断是否还有输入
        if (scan.hasNextInt()) {
            int int1 = scan.nextInt();
            System.out.println("输入的数据为:" + int1);
        }
        scan.close();
    }

    /**
     * 5、Scanner读取整型\字符串数组
     */
    @Test
    public static void Scanner_StringArray() {
        //创建对象
        Scanner sc = new Scanner(System.in);
        System.out.println("输入数据:");
        //输入整型数组长度n 字符串数组长度m
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[] arr = new int[n];
        String[] str = new String[m];
        //int等基本数据类型的数组,用nextInt(),同行或不同都可以
        for (int i = 0; i < n; i++) {
            if (sc.hasNextInt()) {
                arr[i] = sc.nextInt();
            }
        }
        //String字符串数组, 读取用next(),以空格划分
        for (int i = 0; i < m; i++) {
            if (sc.hasNext()) {
                str[i] = sc.next();
            }
        }

        //调用方法进行操作
        System.out.println("数据n:" + n + ", 数据m:" + m);
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(str));
        //关闭
        sc.close();
    }

    /**
     * 6、Scanner读取二维数组
     */
    @Test
    public static void Scanner_TwoArray() {
        Scanner sc = new Scanner(System.in);
        System.out.println("输入数据:");

        //二维数组
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[][] arr2 = new int[n][m];
        System.out.println("Test02 输入二维数组数据:");

        //可以直接读入
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                //读取用nextInt(),以空格划分
                arr2[i][j] = sc.nextInt();
            }
        }

        //输出二维数组
        System.out.println("数据n:" + n + ", 数据m:" + m);
        for (int i = 0; i < n; i++) {
            System.out.println(Arrays.toString(arr2[i]));
        }
        System.out.println("数组行数: arr.length= " + arr2.length);
        System.out.println("数组列数: arr[0].length= " + arr2[0].length);
        //关闭
        sc.close();
    }

    /**
     * 7、Scanner换行读取数字、字符串、字符串数组(包含空格),字符串分割为数组
     * next()读取到空白停止,在读取输入后将光标放在同一行中。
     * nextLine()读取到回车停止 ,在读取输入后将光标放在下一行。
     * <p>
     * next()和nextLine()链接注意:换行sc.nextLine();
     */
    @Test
    public static void Scanner_IntStringArraySpace() {
        Scanner sc = new Scanner(System.in);
        //输入以一个整形
        int n = sc.nextInt();

        //注意!!!光标换到下一行
        sc.nextLine();

        //输入一行空格间隔字符串
        String spaceString = sc.nextLine();
        //字符串分割为数组
        String[] split = spaceString.split(" ");

        //定义字符串数组
        String[] strs = new String[n];
        //将光标移动到下一行
        sc.nextLine();
        //循环输出字符串,每次获取输入回车之前的所有字符,加入字符串数组
        for (int i = 0; i < n; i++) {
            String str = sc.nextLine();
            strs[i] = str;
        }

        System.out.println(n);
        System.out.println(Arrays.toString(split));
        输出字符串数组
        //for (int i = 0; i < strs.length; i++) {
        //    String str = strs[i];
        //    System.out.println(str);
        //}
        sc.close();
    }
}

通过JAVA 实现对 File 文件夹及文件内容的增删改查、复制移动

/**
 * 例8-1 new/del/copy/move操作文件
 * 通过JAVA 实现对 File 文件目录文件夹 文件 文件内容的增删改查、复制移动
 */
public class FileOperate {
	public FileOperate() {
	}
	public static void main(String args[]) {
		//	创建中文名时出现乱码 需要调整编码方式
		newFolder("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\Folder");
		//当前目录
		newFile("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\File.txt","这是文件内容");
		//文件重命名
		renameFile("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\File.txt");
		//删除文件
		delFile("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\FileRename.txt");
		//删除文件夹
		delFolder("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\Folder");

	}

	//新建目录
	public static void newFolder(String folderPath) {
		//抛出异常
		try {
			//目录新建 new File(folderPath) 建立文件目录对象 根据路径
			File myFilePath = new File(folderPath);
			//判断路径是否存在
			if (!myFilePath.exists()) {
				//文件目录创建
				myFilePath.mkdir();
			}
		} catch (Exception e) {
			System.out.println("新建目录操作出错");
			e.printStackTrace();
		}
	}

	// 新建文件 文件名、文件内容
	public static void newFile(String filePathAndName, String fileContent) {

		try {
			//实例化File 建立文件对象 传入构造参数-文件名
			File myFilePath = new File(filePathAndName);
			//判断文件路径是否存在
			if (!myFilePath.exists()) {
				//创建新的文件
				myFilePath.createNewFile();
			}
			//实例化FileWriter写入文件路径 得到文件字符输出流
			FileWriter resultFile = new FileWriter(myFilePath);
			//resultFile作为对象写入文件 将对象的格式化表示打印到文本输出流。
			PrintWriter myFile = new PrintWriter(resultFile);
			//把内容写进入文件
			String strContent = fileContent;
			myFile.println(strContent);
			//关闭文件
			resultFile.close();

		} catch (Exception e) {
			System.out.println("新建目录操作出错");
			e.printStackTrace();
		}

	}

	//文件重命名
	public static void renameFile(String filePathAndName) {
		try {
			//新建文件对象,根据文件路径
			File myDelFile = new File(filePathAndName);
			//文件重命名
			myDelFile.renameTo(new File("F:\\intellij2020-1\\idea\\JavaBook\\src\\chap8\\task8_1\\Example8_1\\FileRename.txt"));
		} catch (Exception e) {
			System.out.println("删除文件操作出错");
			e.printStackTrace();
		}
	}

	//删除文件 
	public static void delFile(String filePathAndName) {
		try {
			//新建文件对象,根据文件路径
			File myDelFile = new File(filePathAndName);
			//文件删除
			myDelFile.delete();
		} catch (Exception e) {
			System.out.println("删除文件操作出错");
			e.printStackTrace();
		}
	}

	// 删除文件夹 
	public static void delFolder(String folderPath) {
		try {
			delAllFile(folderPath); //1 删除完里面所有内容
			File myFilePath = new File(folderPath); //通过folderPath得到
			myFilePath.delete(); //2 删除空文件夹目录本身
		} catch (Exception e) {
			System.out.println("删除文件夹操作出错");
			e.printStackTrace();
		}
	}

	//删除文件夹里面的所有文件 递归操作 根据路径删除
	public static void delAllFile(String path) {
		File file = new File(path);
		//如果文件不存在 返回
		if (!file.exists()) {
			return;
		}
		//如果不是文件目录 返回
		if (!file.isDirectory()) {
			return;
		}
		//如果是目录 就递归处理 用String列表
		String[] tempList = file.list();
		File temp = null;
		for (int i = 0; i < tempList.length; i++) {
			//如果是子目录,重新构造File处理 系统相关的默认名称分隔符,为方便起见表示为字符串。该字符串包含单个字符
			if (path.endsWith(File.separator)) {
				temp = new File(path + tempList[i]);
			} else {
				//反之 则加入File.separator 在linux正斜杠 在windows反斜杠
				temp = new File(path + File.separator + tempList[i]);
			}
			// 如果是文件就 删除
			if (temp.isFile()) {
				temp.delete();
			}
			//如果是目录 就递归删除
			if (temp.isDirectory()) {
				delAllFile(path + "/" + tempList[i]); //1 先删除文件夹里面的文件
				delFolder(path + "/" + tempList[i]); //2 再删除空文件夹
			}
		}
	}

	// 复制单个文件
	public static void copyFile(String oldPath, String newPath) {
		try {
			int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { //文件存在时
				//读入原文件 定义文件字节输入流  从数据源中把字节数据读取进来
				InputStream inStream = new FileInputStream(oldPath);
				//文件字节输出流 将字节数据局写到目标设备中 过滤流实现对不同类型数据操作
				FileOutputStream fs = new FileOutputStream(newPath);
				//定义字节数组 存放字节流数据
				byte[] buffer = new byte[1444];
				int length;
				//将数据 读取进字节数组buffer中
				while ((byteread = inStream.read(buffer)) != -1) {
					bytesum += byteread; //字节数 文件大小
					System.out.println(bytesum);
					//将数据写到字节数组中中
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
			}
		} catch (Exception e) {
			System.out.println("复制单个文件操作出错");
			e.printStackTrace();
		}
	}

	//复制整个文件夹内容
	public static void copyFolder(String oldPath, String newPath) {
		try {
			(new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
			File a = new File(oldPath);
			String[] file = a.list();
			File temp = null;
			for (int i = 0; i < file.length; i++) {
				if (oldPath.endsWith(File.separator)) {
					temp = new File(oldPath + file[i]);
				} else {
					temp = new File(oldPath + File.separator + file[i]);
				}
				if (temp.isFile()) {
					FileInputStream input = new FileInputStream(temp);
					FileOutputStream output = new FileOutputStream(newPath
							+ "/" + (temp.getName()).toString());
					byte[] b = new byte[1024 * 5];
					int len;
					while ((len = input.read(b)) != -1) {
						output.write(b, 0, len);
					}
					output.flush();
					output.close();
					input.close();
				}
				if (temp.isDirectory()) {//如果是子文件夹
					copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
				}
			}
		} catch (Exception e) {
			System.out.println("复制整个文件夹内容操作出错");
			e.printStackTrace();
		}
	}

	//移动文件到指定目录
	public static void moveFile(String oldPath, String newPath) {
		copyFile(oldPath, newPath);
		delFile(oldPath);
	}

	//移动文件夹到指定目录
	public static void moveFolder(String oldPath, String newPath) {
		copyFolder(oldPath, newPath);
		delFolder(oldPath);
	}
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值