【java1】if/switch/for/while,数组,属性/方法,可变参数/构造器,this/super/继承,抽象/初始化,接口/多态,权限修饰符,包装类/集合/泛型/内部类

文章目录


1.jdk安装:JAVA_HOME

如下链接:https://pan.baidu.com/s/11Uw-bnuFmITCWU5Ne5z_sw 提取码:dgtr。双击如下jdk1.8安装,安装到D:\development\jdk1.8,弹出新框jre安装到D:\development\jdk1.8\jre1.8
在这里插入图片描述
此电脑右击属性(可查看计算机多少位)-高级系统设置-环境变量,在下面框的系统环境变量新建。
在这里插入图片描述
如下选中path系统变量点编辑再点编辑文本,将上面路径添加进去再加bin以分号结束,取变量。
在这里插入图片描述
在这里插入图片描述

2.idea安装:全局settings

idea软件链接:https://pan.baidu.com/s/1T9O7QiGyNEMoT-xehDnNEg 提取码:p5yd。安装到D:\development,自动生成IntelliJ IDEA 2018.1文件夹
在这里插入图片描述
JetbrainsCrack-2.7..jar包(链接:https://pan.baidu.com/s/1pQTyb7OT0S4DPPwPnA9HDQ 提取码:igri)复制到D:\development\IntelliJ IDEA 2018.1\bin(右击idea图标点属性),在bin目录下找到两个idea…vmoptions文件最后一行都添加-javaagent:D:\development\IntelliJ IDEA 2018.1\bin\JetbrainsCrack-2.7-release-str.jar,双击idea软件如下复制进去
在这里插入图片描述

ThisCrackLicenseId-{
"licenseId":"ThisCrackLicenseId",
"licenseeName":"Gail_Hu",
"assigneeName":"",
"assigneeEmail":"Gail_Hu@126.com",
"licenseRestriction":"For This Crack, Only Test! Please support genuine!!!",
"checkConcurrentUse":false,
"products":[
{"code":"II","paidUpTo":"9999-12-31"},
{"code":"DM","paidUpTo":"9999-12-31"},
{"code":"AC","paidUpTo":"9999-12-31"},
{"code":"RS0","paidUpTo":"9999-12-31"},
{"code":"WS","paidUpTo":"9999-12-31"},
{"code":"DPN","paidUpTo":"9999-12-31"},
{"code":"RC","paidUpTo":"9999-12-31"},
{"code":"PS","paidUpTo":"9999-12-31"},
{"code":"DC","paidUpTo":"9999-12-31"},
{"code":"RM","paidUpTo":"9999-12-31"},
{"code":"CL","paidUpTo":"9999-12-31"},
{"code":"PC","paidUpTo":"9999-12-31"}
],
"hash":"2911276/0",
"gracePeriodDays":7,
"autoProlongated":false}

在idea软件打开界面右下角点击Configure-Project Defaults-Project Structure 如下点New配置JDK。
在这里插入图片描述
如下点Configure-settings,Editor-General如下点击apply。
在这里插入图片描述
在这里插入图片描述

3.关键字/常量/变量:javac

//HelloWorld.java,类名和文件名要同
public class HelloWorld {
	public static void main(String[] args) {
		System.out.println("HelloWorld");
	}
}

1.为什么要编译:代码最终是要交给JVM去执行的,而我们写的代码JVM不认识,所以我们必须要将我们自己写的代码翻译成JVM他认识的代码,这样他才能够去执行。 这个翻译的过程其实就是编译。

2.编译使用的工具:编译要使用jdk的bin目录下的工具javac.exe去完成。

3.编译的步骤:将HelloWorld.java移动到jdk的bin目录(因为我们需要使用Jdk的bin目录中的javac.exe进行编译)。在jdk的bin目录打开控制台,然后输入命令javac HelloWorld.java(编译完之后,会生成一个.class文件,这个.class文件就是将来要交给JVM执行的文件),再输入命令java HelloWorld(运行的真正是.class文件,但是运行的时候不要带扩展名)。

4.配置环境变量的目的:为了可以在任何目录下使用jdk的bin目录下的工具(javac.exe, java.exe),在第一章已配置好,重新打开dos窗口。在Java内置好的,被Java赋予特殊含义的单词就是关键字。关键字所有字母都小写且在高级的编辑器中会变色,如下java关键字。
在这里插入图片描述
在这里插入图片描述
所有常量中,空常量null不能直接输出,其他的常量都是可以直接使用输出语句进行输出的。
在这里插入图片描述
如下short取值范围-32768到32767,int是-21亿多到21亿多bsil fd cb
在这里插入图片描述
不管代码文件中char使用的是什么编码,都将被JVM转化为UTF-16而且只用两个字节,也就是说Java中的char占用两个字节。
在这里插入图片描述

4.数据类型/标识符/类型转换:小大自

标识符就是我们自己给变量, 给方法, 给类…所起的名字。标识符起名软性规定如下:
在这里插入图片描述
硬性规定如下:记住字下美+字下美数:如下看红字前面即=号前面。
在这里插入图片描述
在这里插入图片描述
如下100亿超出int范围,所以要加L,并不是错误。
在这里插入图片描述
在这里插入图片描述
如下bsil fd多了一个c。
在这里插入图片描述
如下打印出结果为7。
在这里插入图片描述
在这里插入图片描述
如下报错:不兼容的类型: 从int转换到byte会有损失。
在这里插入图片描述

5.算术/赋值/自增运算符:前先自加1,48/65/97,ascii,转义符

/*
 /:做除法。如果两个整数相除,结果只取整数部分。如果想要得到小数,那么只需要把除法两边任意一个改成小数
 
 %:取余(模)运算。获取两个数相除之后的余数部分。可以判断一个数能否被另一个数整除,如果一个数可以被另一个数整除,那么取余的结果就是0
*/
public class Demo01Operator {
	public static void main(String[] args) {
		//定义两个变量
		int a = 5;
		int b = 3;
		// /:做除法
		System.out.println(a / b);//1
		
		//得到小数,只需要把除法两边任意一个数改成小数,imt自动类型转换double
		//System.out.println(5 / 3.0);//1.6666666666667
		
		//%:取余(模运算)【获取a和b相除之后的余数部分】
		System.out.println(a % b);//2
		
		//判断653252能否被3整除,看结果是不是为0
		System.out.println(653253 % 3);		
	}
}
/*
	+号多种用途:
		1. 如果对数值相加,起到的就是普通的数学中的加法运算。
		2. 如果是字符运算,会先查询ASCII码表,将字符转成数字,然后再进行运算。
		3. 如果加号只要有一个是字符串,那么此时就是在对字符串相加。
		   如果是对字符串相加,加号起到的作用就是拼接(连接)
		   任何类型只要和字符串相加,结果都是字符串类型。		
		
	ASCII码表是数字和字符的对应关系表
		'a'	->	97
		'A'	->	65 中间
		'0'	->	48
*/
public class Demo02Operator {
	public static void main(String[] args) {
		int a = 3;
		int b = 4;
		System.out.println(a + b);//7
		
		//定义两个字符,char转int运算
		char c1 = 'a';//97
		char c2 = '0';//48
		System.out.println(c1 + c2);//145
		
		//字符串相加,运算从左往后
		System.out.println("HelloWorld" + a);//HelloWorld3
		System.out.println("HelloWorld" + a + b);//HelloWorld34
		System.out.println(a + b + "HelloWorld");//7HelloWorld
	}
}

“A”:只有一个字符的字符串。ASCII控制字符前32个:不可打印,用于控制外设。如下32-127可打印,先看字符这一列:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/*
	赋值运算符
		基本的赋值运算符
			=:将右边的值交给左边的变量保存。
		扩展的赋值运算符
			+=,-=,*=,/=,%=
			作用:先求出运算符两边操作的结果,然后把这个结果赋值给左边的变量。
			举例:
			m += n:先求出m和n相加的结果,然后把这个结果赋值给左边的变量m。 运算结果相当于: m = m + n
			m *= n:先求出m和n相乘的结果,然后把这个结果赋值给左边的变量m。 运算结果相当于: m = m * n
			注意:
				扩展的赋值运算符中蕴含了强制类型转换的功能。
*/
public class Demo03Operator{
	public static void main(String[] args) {		
		short s = 10;
		//使用+=符号进行运算  m+=n 运算结果相当于 m = m + n;
		s += 3; //蕴含了强制类型转换或写成s = (short)(s + 3); //不加(short)报错为int转short有损失	
		System.out.println("s:" + s); //13
	}
}

如果++运算符单独使用,++放在变量前和变量后没有任何区别,都是将变量本身的值加1,如果参与其他操作,是有区别的。前先加1,后先用1次
在这里插入图片描述
在这里插入图片描述
如上解释如下:

public class Demo05Operator {
	public static void main(String[] args) {
		int x = 4; //6
		int y = (x++) + (++x) + (x * 10);
		//	70  = 4 (运算完变成了5) +  6  +  60
		System.out.println("x:" + x);//6
		System.out.println("y:" + y);//70
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
j++看为一整体。
在这里插入图片描述
如下原始4个都没有报错。
在这里插入图片描述

6.关系/逻辑/三元运算符:&&短路

1.Create New Project-选择最下面的Empty Project,项目/模块/包/类。
在这里插入图片描述
2.如下将光标放在External Libraries上再New。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.如下新建包,包名(所有字母小写)是域名(网址)的倒叙,包中圆点就是分隔文件夹。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果编译出现java无效发行版9,则File->Project Structure,将Modules和project菜单中Language level改为8。
在这里插入图片描述
File-Close Project。删除模块在idea中右击remove了还要到计算机里手动删除。模块导入:先手动将模块文件夹复制到计算机项目文件夹下,再进行Project Structure。
在这里插入图片描述
选中src右击新建Package命名为com.itheima.demo02,选中demo02右击新建类。
在这里插入图片描述
与:有0为0或:有1为1异或:同0
在这里插入图片描述

/*
    && 和 &的区别
    相同点:运算结果相同。都是有false则结果是false。

    不同点:
        & 不管左边是true还是false,都会去计算右边
        && 如果左边是false,那么就不去计算右边的。 因为&&是有false则结果是false,左边是false,不管右边是啥,结果肯定是false。这种行为叫做短路行为。

    |也可以写成两个||
        ||同样也是具有短路行为的,如果左边是true,那么就不去计算右边了。 因为||是有true则true。
*/

在这里插入图片描述

package com.itheima.demo02;
/*
    三元运算符
    作用:可以实现对结果进行二选一的操作。
    格式:
        布尔表达式 ? 值1 : 值2
    执行流程:
        1. 先判断布尔表达式的结果是true还是false。
        2. 如果布尔表达式是true,那么整个三元运算符式子的结果就是值1.
           如果布尔表达式是false,那么整个三元运算符式子的结果就是值2
    注意:
        三元运算符不能单独出现,要么用一个变量接受一下三元运算符的结果,要么直接使用【比如直接输出】
    要求:
        定义两个变量,获取这两个变量中的最大值
*/
public class Demo04Operator {
    public static void main(String[] args) {
        //定义两个变量
        int a = 10;
        int b = 20;
        //使用三元运算符求出结果
        int max = a > b ? a : b;
        //输出max
        System.out.println("max:" + max); //20
    }
}
package com.itheima.demo02;
/*
    需求:动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,请用程序实现判断两只老虎的体重是否相同。
    思路:
        1. 定义两个变量,表示两只老虎的体重
        2. 使用三元运算符比较这两个变量是否相同,并得到结果.
 */
public class Demo05OperatorTest {
    public static void main(String[] args) {
        //1. 定义两个变量,表示两只老虎的体重
        int weightOne = 180;
        int weightTwo = 200;

        //2. 使用三元运算符比较这两个变量是否相同,并得到结果.
        //boolean flag = weightOne == weightTwo ? true : false;
        //下面写法更简单,==本身结果为true/false
        boolean flag = weightOne == weightTwo;
        System.out.println(flag);
    }
}
package com.itheima.demo03;
/*
    使用Scanner键盘录入整数,步骤【背下来,不需要理解】:
        1. 导包
            import 包名.类名;
            import java.util.Scanner;
            注意:导包操作要写在package和class之间

        2. 创建对象【new出来的都是对象】
            数据类型 对象名 = new 数据类型(...);
            Scanner sc = new Scanner(System.in);

        3. 调用方法,键盘录入整数
            对象名.方法名(...);
            int a = sc.nextInt(); //sc.nextInt()在键盘录入整数,然后把录入的这个数字赋值给了变量a
 */
import java.util.Scanner; //导包

public class Demo02Scanner {
    public static void main(String[] args) {
        //创建对象
        Scanner sc = new Scanner(System.in);
        //在键盘录入之前该出提示
        System.out.println("请你键盘录入一个整数");
        //调用方法,键盘录入整数
        int a = sc.nextInt();
        System.out.println(a);
    }
}

如下rt.jar在lib文件夹里。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class HelloWorld{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int a = sc.nextInt();
        
        System.out.println("请输入你要进行的运算符号(+,-,*,/)“:");
        char b = sc.next().charAt(0);
        
        System.out.println("请在输入一个数:");
        int c = sc.nextInt();
        
        switch (b){
            case '+':
                int sumNum = a + c;
                System.out.println("计算的结果是:" + sumNum);
                break;
            case '-':
                int subNum = a - c;
                System.out.println("计算的结果是:" + subNum);
                break;
            case '*':
                int multNum = a * c;
                System.out.println("计算的结果是:" + multNum);
                break;
            case '/':
                if(c == 0){
                    System.out.println("被除数不能为0");//判断被除数为0的情况
                }else {
                    float diviNum= (float)(a / c);
                    System.out.println("计算的结果为:" + diviNum);
                }
                break;
            default:
                System.out.println("对不起输入有误!");//没有按照正确的格式输入
                break;
        }
    }
}

7.if/switch/for/while/do.while:没有break

在这里插入图片描述
先匹配case,但如下都没匹配上,所以先default。
在这里插入图片描述
如下1月和2月都属于冬季。
在这里插入图片描述
如下发生穿透。
在这里插入图片描述
如下case 0不执行。
在这里插入图片描述
变量不能用for循环。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.一维数组:int[ ] a = { }

8.1 数组的内存分析(静态):数组名=首地址

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.2 数组的内存分析(动态):元素默认值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.3 数组相关算法:求一个长度为10的整型数组的最大元素

在这里插入图片描述
在这里插入图片描述

找最值:array[i] > max

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

平均值:.length

在这里插入图片描述
在这里插入图片描述

反转:最后一位向i反方向移

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下第0位=最后一位,最后一位=第0位,交换。
在这里插入图片描述

复制:=

在这里插入图片描述
如下是Copy_02。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

顺序查找:==

在这里插入图片描述
在这里插入图片描述

二分查找:arr[mid] ==

在这里插入图片描述
在这里插入图片描述

冒泡排序:两两比较,temp交换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

直接排序:min和index,temp

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.属性/方法:if elseif else,成/局变量

/*
声明一个日期类MyDate,包含属性:年、月、日,并在MyDate类中声明几个方法:
1、boolean isLeapYear():判断当前日期的是闰年吗?
2、void set(int y, int m, int d):修改年,月,日为新日期
3、void plus(int y, int m, int d):修改当前日期为加了y年,m月,d天后的日期
 	例如:2019年5月21日,  plus(1,1,1)==>2020年6月22日
 	例如:2019年5月21日,  plus(1,1,20)==>2020年7月11日
*/
class Day07_Test04{
	public static void main(String[] args){
		MyDate my = new MyDate();
		my.year = 2019;
		my.month = 5;
		my.day = 21;	
		//my.plus(1,1,1);
		//my.plus(1,1,20);
		//my.plus(1,30,70);
		System.out.println(my.year + "年" + my.month + "月" + my.day);
	}
}
class MyDate{
	int year;
	int month;
	int day;
	
	boolean isLeapYear(){
		if(year%4==0 && year%100!=0 || year%400==0){
			return true;//如果if条件满足,从这里就把true返回并结束当前方法
		}
		return false;
	}
	//用y,m,d为当前对象的year,month,day属性赋值
	void set(int y, int m, int d){
		year = y;
		month = m;
		day = d;
	}
	//在当前日期的基础上,加上y年,m月,d天
	void plus(int y, int m, int d){
		day += d;
		month += m;
		year += y;
		
		while(true){
			if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10){ //31天
				if(day>31){
					day -= 31;
					month++;
				}
			}else if(month==4 || month==6 || month==9 || month==11){ //30天
				if(day>30){
					day -= 30;
					month++;
				}
			}else if(month==2){ //润年29天,其他28天
				if(year%4==0 && year%100!=0 || year%400==0){
					if(day>29){
						day -= 29;
						month++;
					}
				}else{
					if(day>28){
						day-=28;
						month++;
					}
				}
			}else if(month == 12){ //31天
				if(day>31){
					day-=31;
					month=1;
					year++;
				}
			}else if(month>12){
				while(month>12){
					month -= 12;
					year++;
				}
			}
			
			if(month>=1 && month<=12){
				if(month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12){
					if(day<=31){
						break;
					}
				}else if(month==4 || month==6 || month==9 || month==11){
					if(day<=30){
						break;
					}
				}else if(month==2){
					if(year%4==0 && year%100!=0 || year%400==0){
						if(day<=29){
							break;
						}
					}else{
						if(day<=28){
							break;
						}
					}
				}
			}
		}
	}
}

9.1 属性内存分析:new堆中新开辟

在这里插入图片描述

9.2 方法内存分析:值/引用传递

/*
方法的参数传递机制:(1)形参是基本数据类型:实参赋值给形参的是数据值,形参值的修改不影响实参,因为实参是“copy复制”了一份数据值给形参。
(2)形参是引用数据类型(涉及堆):实参赋值给形参的是对象的地址值,如果形参修改了对象的属性值,那么实参对象的属性值也会修改。
*/

在这里插入图片描述
在这里插入图片描述
如下…方法的…变量。
在这里插入图片描述
如上结果为2.0,增大为原来的两倍。如下0乘2还是0,绿色单独成一块和yuan.radius无关。
在这里插入图片描述
在这里插入图片描述

10.方法重载:内存地址==

class Test03_Overload{
	public static void main(String[] args){
		System.out.println(max(1,4));
		System.out.println(max(1.0,4.0));
		System.out.println(max(1,4,8));
	}

	//写一个方法,可以找2个整数的最大值
	public static int max(int a, int b){
		return a>b ? a : b;
	}
	//方法重载时,不去看返回值类型是否一致,只看方法名和形参列表。
	//如下虽然double返回值类型不一样,但形参一样,不算函数重载
	//public static double max(int a,int b){
	//	return 0.0;
	//}

	//写一个方法,可以找2给小数的最大值,如下算重载
	public static double max(double a, double b){
		return a>b ? a : b;
	}
	
	//写一个方法,可以找3个整数的最大值
	public static int max(int a, int b, int c){
		int max = a > b ? a : b;
		max = max > c ? max : c;
		return max;
	}
}

在同一个类中,两个或者两个以上方法的名称一样,参数列表不一样,和返回值无关,这些称之为方法重载。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.变量分类:方法的参数

/*
变量的分类:1.成员变量:今天讨论的都是非静态的成员变量(类中方法外)。
		    2.局部变量(方法中)

(1)声明的位置不同	

(2)运行时在内存中的位置也不相同
成员变量:堆 (new一个对象,用圆点访问)
局部变量:栈 (方法开辟一段内存)

(3)初始化不同
成员变量:如果没有初始化,有默认值
局部变量:如果没有初始化,就会报错,不能用

(4)生命周期
成员变量:随着对象的创建而分配,随着对象被垃圾回收器回收而结束
局部变量:方法被调用,开始分配,方法执行结束就结束

(5)可用的修饰符
成员变量:有很多修饰符
局部变量:唯一的一个就是final
*/

如下左边的小方框都是方法的变量即局部变量。右边name,age是成员变量,不是常量。string是引用数据类型,红main方法,蓝set方法。
在这里插入图片描述

12.可变参数:[ ]或…

/*
命令行参数:(了解) 给main方法传的实参,叫做命令行参数
格式:java main所在的类名  实参1  实参2 ..例如:java Test04_CommandParam  hello java atgui
*/
class Test04_CommandParam{
	//因为main也是一个有参无返回值的方法,那么如何给main传参数呢?
	public static void main(String[] args){
		//args是形参,是String[]类型,是一个一维数组
		for(int i=0; i<args.length; i++){
			System.out.println("第" +(i+1) +"个参数的值:" + args[i]);
		}
	}
}

在这里插入图片描述
在这里插入图片描述

package com.itheima04.args;
/*
*   可变参数 : variable args 【arguments(args) ,parameter(param)都为参数】
*       语法: 必须三个点
*           类型A... 变量名
*         1. 本质是数组 (不确定长度的数组)
*         2. 调用方法的时候,传参才会确定数组的长度
*         3. 可变参数 可以传入 0个到无穷多个 类型A的变量
*       语法注意点:
*           1. 可变参数只能放在参数列表中
*           2. 参数列表,只能有一个可变参数
*           3. 可以有其他参数,但是可变参数必须放在参数列表最后
*/
public class ArgsDemo {
    public static void main(String[] args) {
        int sum = add(1,2);
        int sum2 = add(1,2,3);
        
        int[] array = {1,2,3,4};
        int sum3 = add(1,array);
        System.out.println(sum3); //10
    }

    private static int add(int i,int... args) {
//        System.out.println(args.length); //传入参数个数
        int sum = 0;
        for (int arg : args) { //数组支持增强for循环
            sum += arg;
        }
        return sum;
    }
}

13.封装:数据抽象

/*
封装的实现,靠权限修饰符来控制可见的范围。
   权限修饰符:类:缺省或public,如果类前面有public,那么必须与源文件名相同
   属性:四种都可以。方法:四种都可以	

属性的封装:大多数情况下,属性都是private。如果属性私有化了,我们会提供get/set方法
    get/set的标准写法:
	public void set属性名(数据类型 形参名){
		属性名 = 形参名;
	}
	public 属性的数据类型 get属性名(){
		return 属性名;
	}

方法的封装:大多数情况下,方法都是public
*/
public class Test10_Encapsulation{
	public static void main(String[] args){		
		Circle c1 = new Circle();  //1、创建对象		 		
		//c1.radius = 1.2;   //错误的
		c1.setRadius(1.2);	//2、为属性赋值	 
		System.out.println("半径:" + c1.getRadius());
	}
}
class Circle{
	private double radius;//仅限与本类中访问	
	//radius属性的set方法,用于在其他类中修改radius的值
	public void setRadius(double r){
		if(r>0){//使得赋值可控
			radius = r;
		}
	}
	//radius属性的get方法,用于在其他类中获取radius的值
	public double getRadius(){
		return radius;
	}	
}

在这里插入图片描述

14.对象数组:先new

/*
数组是用来存一组数,这组数可以是基本数据类型,也可以是引用数据类型。当我们数组中存储了一组对象时,那么我们称为对象数组。	
	int[] arr; 存了一组整数
	char[] arr; 存了一组单字符	
	String[] arr; 存了一组字符串对象
	Student[] arr; 存了一组学生对象
*/
class Test08_ObjectArray{
	public static void main(String[] args){
		//要用一个数组,存储5个圆对象,半径分别为1-5
		//(1)声明一个数组,数组的元素的类型是Circle
		Circle[] arr = new Circle[5];//这个new是创建数组对象		
		//(2)为数组的元素赋值
		for(int i=0; i<arr.length; i++){
			//元素:数组名[下标]
			//arr[i].radius = i+1;//java.lang.NullPointerException			
			arr[i] = new Circle();//创建圆对象
			arr[i].radius = i+1;
		}		
		//(3)遍历数组,打印每一个圆的信息
		for(int i=0; i<arr.length; i++){
			//现在的数组的元素arr[i]就是一个圆对象,既然是圆对象,就可以调用圆的属性和方法
			arr[i].printInfo();
			//System.out.println(arr[i]);
		}
	}
}
class Circle{
	double radius;     	
	double getArea(){
		return 3.14 * radius * radius;
	}	
	void printInfo(){
		System.out.println("半径:" + radius + ",面积:" + getArea());
	}
}

在这里插入图片描述
在这里插入图片描述

15.构造器:不写也有无参构造

 /*
类的第三个组成部分:构造器,也称为构造方法【因为它长的像方法且它编译后是一个实例初始化方法】

1、构造器的作用:(1)构造对象,创建对象,和new一起使用,每次调用它就是在创建新的对象	
(2)可以在创建对象的同时,给属性赋值

2、构造器的特点:(1)所有类都有构造器
(2)如果一个类没有显式声明构造器,那么编译器将会自动生成一个默认的无参构造
(3)如果一个类显式声明了构造器,那么编译器将不会自动生成默认的无参构造了
(4)构造器的名称必须与类名相同
(5)构造器没有返回值类型,也不写void
(6)构造器可以重载

3、构造器的语法结构
	【修饰符】 类名(){		
	}
	【修饰符】 类名(形参列表){		
	}	
	java.util.Scanner input = new java.util.Scanner(System.in);//调用的是有参构造
	int num = input.nextInt();//从键盘输入一个整数	
	
	java.util.Random rand = new java.util.Random();//调用的是无参构造
	int num = rand.nextInt(10);//产生一个[0,10)的整数
*/
class Test12_Constructor{
	public static void main(String[] args){
		//创建对象:类名 对象名 = new 类名();
		//Circle c = new Circle(); //这里Circle()就是构造器		
		Circle c = new Circle(1.2);//1.2给半径赋值,在创建对象的同时给属性赋值用的
		c.printInfo();		
		c.setRadius(2.5);//创建对象之后,修改属性值用的
		c.printInfo();		
		
		Circle c2 = new Circle();//先创建对象,不给半径赋值
		c2.setRadius(3.6);
		c2.printInfo();
	}
}
class Circle{
	private double radius;	
	//double r:构造器的形参列表
	public Circle(double r){//有参构造
		radius = r;//给半径赋值
	}	
	public Circle(){//无参构造		
	}	
	public void printInfo(){
		System.out.println("半径:" + radius);
	}	
	public void setRadius(double r){
		radius = r;
	}	
}

如下去掉return,结果为1。
在这里插入图片描述

/*
 	1、声明一个Employee员工类,包含属性:编号(id)、姓名(name)、薪资(salary)、年龄(age)
 	包含方法:
    (1)void printInfo():可以打印员工的详细信息
    (2)void setInfo(int  i, String n, double s, int a):可以同时给id,name,salary,age赋值
   
 	2、声明一个TestEmployee测试类
 	(1)public static void main(String[] args): 在main方法中,创建Employee[]数组,并创建5个员工对象放到数组中,并为员工对象的属性赋值
 	(2)public static void print(Emplyee[] all):遍历打印员工数组中的每个员工的详细信息,并在main中调用
 	(3)public static void sort(Employee[] all):将all员工数组按照《年龄》从高到低排序,并在main中调用测试
 	(4)public static void addSalary(Employee[] all, double increament):将all员工数组的每一个员工的《工资》增加increament,并在main中调试测试
*/
class Day08_Test05{
	public static void main(String[] args){
		Employee[] all = new Employee[5];
		all[0] = new Employee();
		all[0].setInfo(1,"张三",10000,23);	
			
		all[1] = new Employee();
		all[1].setInfo(2,"李四",12000,23);	
			
		all[2] = new Employee();
		all[2].setInfo(3,"王五",8000,18);
				
		all[3] = new Employee();
		all[3].setInfo(4,"赵六",6000,20);	
			
		all[4] = new Employee();
		all[4].setInfo(5,"钱七",15000,21);		
		print(all);
		
		sort(all);
		System.out.println("------------------------------------------");
		print(all);	
			
		addSalary(all, 200);
		System.out.println("------------------------------------------");
		print(all);
	}
	
	public static void print(Employee[] all){
		for(int i=0; i<all.length; i++){
			all[i].printInfo();
		}
	}
	
	public static void sort(Employee[] all){
		for(int i=1; i<all.length; i++){
			for(int j=0; j<all.length-i; j++){
				//从高到低
				if(all[j].age < all[j+1].age){
					Employee temp = all[j];
					all[j] = all[j+1];
					all[j+1] = temp;
				}
			}
		}
	}
	
	public static void addSalary(Employee[] all, double increament){
		for(int i=0; i<all.length; i++){
			all[i].salary += increament;
		}
	}
}
class Employee{
	int id;
	String name;
	double salary;
	int age;
	
	void printInfo(){
		System.out.println("编号:" + id + ",姓名:" + name + ",薪资:" + salary + ",年龄:" +age);
	}
	void setInfo(int  i, String n, double s, int a){
		id = i;
		name = n;
		salary = s;
		age = a;
	}
}

如下分别是sort年龄从高到低,addSalary增加200薪水。
在这里插入图片描述

16.this/super/继承:多重,匿名对象

方法进栈,类属性(成员变量)进堆。
在这里插入图片描述
如下直接创建类(Demo01)时也创建好了包。
在这里插入图片描述
如下将硬盘上.class文件(class Person…)加载进内存中,p存的是内存地址。
在这里插入图片描述

package com.itheima02.inherit;

public class Demo01 {  // field (字段, 属性)
    public static void main(String[] args) {
        Zi  zi = new Zi();
        zi.name = "张三";
        zi.age = 18;
        zi.kongFu();
    }
}
class Fu{
    String name;
    int age;
    private String Cat; // 私有: 外部不可访问,不能继承
    public Fu(){ // 构造: 方法名必须与类名一致,所以不能继承
    }
    public void kongFu(){
        System.out.println(age +"岁" + name + "正在联系辟邪剑~");
    }
}
class Zi extends Fu{
    public Zi(){
    }
}

在这里插入图片描述

package com.itheima03.filed;
import com.sun.org.apache.xpath.internal.SourceTree;
/*
*  继承后, 子类存在与父类同名的属性:1. 结论: 那么在子类访问中 遵循就近原则。
*   2. 直接访问父类中的属性: 关键字super,父类(超类 super class, 基类)。一般不会出现子父类同名属性。
*/
public class FiledDemo {
    public static void main(String[] args) {
        Zi zi = new Zi();        
        zi.speak(); //子类对象 可以直接调用父类的属性和方法
    }
}
class Fu{
    String name = "张三";
}
class Zi extends Fu{
    String nickName = "大帅哥";
    String name = "李四";
   /* public Zi(String name){ //同名成员和局部变量(构造方法中出现)
        this.name = name;
    }*/    
    public void speak(){  //可以在子类的内部直接调用
        String name = "王五";
        System.out.println("我的局部名字叫:" + name); //王五
        System.out.println("我的成员名字叫:" + this.name); //李四
        System.out.println("我的父类名字叫:" + super.name); //张三
        System.out.println("我的昵称叫:" + nickName); //大帅哥
    }
}
package com.itheima04.method;
/*
*   继承中, 子父类存在相同的方法  -> 方法重写
*       1. 方法重载(overload)
*           一个类中,存在方法名相同,但是参数列表不同(类型,个数,顺序)的方法
*       2. 方法重写(overried)
*           基于继承关系 : 子类中定义与父类完全相同的方法(方法名,参数列表,返回值类型都同)
*           效果 : 子类对象都是直接调用子类重写后的方法
*   注解: @Override(标记)作用: 在源码编译时,检测此方法是否是重写方法,如果不是,就会编译报错。
*/
public class MethodDemo {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.show(); // zi:show
        zi.speak(); // zi:show  zi:speak
    }
}
class Fu{
    public void show(){
        System.out.println("fu:show");
    }
}
class Zi extends Fu{
    public void speak(){
 	   show(); //可以,调用子类重写的方法
       System.out.println("zi:speak");
    }
    @Override //可以不写
    public void show(){
        System.out.println("zi:show");
    }
}

在这里插入图片描述

package com.itheima04.method;

public class PhoneDemo {
    public static void main(String[] args) {
        HuaWei hw = new HuaWei();
        hw.call(); //打电话 来电显示 视频通话
        
        System.out.println("------------------------------");                
        BigBrother bb = new BigBrother();
        bb.call(); //打电话
    }
}
class BigBrother{
    public void call(){
        System.out.println("打电话");//若有10000行
    }
}
class HuaWei extends BigBrother{ // 小技巧: 直接在子类中写方法名,提示重写方法同名方法
    @Override
    public void call() {
        super.call(); 
// 调用父类方法: 保留旧功能。如果直接写成call()就近原则自己调用自己,死循环调用StackOverflowError,不叫递归(递归必须有结束条件)
        //扩展
        System.out.println("来电提示");
        System.out.println("视频通话");
    }
}

16.1 继承中构造方法:子类隐式调用父类空参构造

默认构造函数是编译器隐含提供的一个无参构造函数,仅当类中没有定义任何构造函数时才有效。
在这里插入图片描述
如下super/this不能在普通方法中调用。
在这里插入图片描述
在这里插入图片描述

package com.itheima05.constructor;
/*
*  方法重写:1. 父类中的private方法是不能重写的 (private方法/构造方法不能继承,也就不能重写)
*           2. 在子类中重写的方法权限 不能小于 父类中的方法 (大于或等于 才可以,原因: 多态)
*              private < default(默认,不写) < protected < public
* 
*  继承关系中的构造方法特点 (构造器): 1. 构造方法不能继承
*       2.定理: 子类的构造必须调用父类的构造!!(要么直接调用,要么间接调用),重要!!!!!!!
*           <1> 子类的空参构造,隐式调用父类的空参构造
*           <2> 如果父类没有空参构造, 必须 手动调用其他父类构造
*/
public class Demo01 {
    public static void main(String[] args) {
        new Zi(); //子类构造
    }
}
class Fu{
    String name;
    int  age;
    public Fu(String name,int age){
        this.name = name;
        this.age = age;
    }
}
class Zi extends Fu{
    int number;
	/* 如下方法可以,但不够面向对象,对象有封装性
      public Zi(String name,int age,int number){
        super.name = name;
        super.age = age;
        this.number = number;
    }*/
   public Zi(String name,int age,int number){
       super(name,age); //让父类的构造给自己的属性赋值,尽量不去打扰你的属性,通过方法访问
       this.number = number; //左成员=右局部,类属性初始化
   }
    public Zi(){
       super(null,0);
       System.out.println("子类构造");
    }
    public Zi(String name,int age){
       this(name,age,0); //0是默认值,间接调用父类
    }
}

//11111111111111111111111111111111111111111111111111111111111111111
class F{
    String name;
    public F(String name){
        this.name = name;
    }
}
class Z extends F{
    public Z(){ //父类没有无参构造让子类隐式调用,就手动调用父类有参构造
        super(null); //null指name
    }
}

如下this()调用下面public Zi()无参构造,至少要有一个调用父类。没有一个子类能执行完。
在这里插入图片描述
this相当于python中init即构造函数来实例化类。
在这里插入图片描述
在这里插入图片描述

17.抽象:下定义

package com.itheima08.abstractd;
/*
*   抽象: 1.没有方法体的方法,设置为抽象方法  -> 关键字abstract
*         2.如果一个类拥有抽象方法, 必须声明为抽象类
*/
public class AbstractDemo {
    public static void main(String[] args) {
     Dog d = new Dog();
     d.eat(); //狗吃骨头
    }
}
abstract class Animal{  //父类: 所有子类的共性抽取
    String name;
    abstract void eat();
    abstract void run();
}
/*
*  如下若子类报错: 方案A: 把当前类 继续 声明为抽象类
*         方案B: 重写父类中所有的抽象方法
*/
class Dog extends Animal{
    @Override
    void eat() {
        System.out.println("狗吃骨头");
    }    
	@Override
    public void run() {
        System.out.println("狗在欢快的跑");
    }
}
package com.itheima08.abstractd;
/*
*   抽象的语法细节:1. 拥有抽象方法的类 必须是抽象类,不服气可以方法重写
*       2. 抽象类不一定要拥有抽象方法
*       3. 抽象类不能实例化(不能new对象)(调用方法时没有方法体)
*       4. 抽象类也有构造方法(子类一定调用父类构造)  -> 接口和抽象类 像
*/
public class AbstractDemo02 {
    public static void main(String[] args) {
        B b = new B(); // A的构造
    }
}
abstract class A{
    public A(){
        System.out.println("A的构造");
    }
    abstract void eat(); //强制要求子类重写,如果子类不重写,子类定义为抽象类,又不好创建对象
    public void speak(){
    };
}
class B extends A{
    @Override
    void eat() {
    }
}

work和project:super。

package com.itheima09.example;

public abstract class Employee { //信息太少的员工,abstract不让它实例化,下定义
    private String name;
    private int age;
    public Employee(String name,int age){
        this.name = name;
        this.age = age;
    }
    public abstract  void work();
    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;
    }
}
package com.itheima09.example;

public abstract class Development extends Employee {    
	public Development(String name, int age) { 
        super(name, age);
    }
    @Override
    public void work() {
        System.out.println("正在做研发工作");
    }
    public abstract void project(); //只知道研发项目,不知道研发哪个具体项目
}

如下都是继承Development类。

package com.itheima09.example;

public class JavaEE extends Development {
    public JavaEE(String name, int age) {
        super(name, age);
    }
    @Override
    public void project() {
        System.out.println(getName() + "javaee项目研发中"); //不能直接写name(私有化)
    }
}
package com.itheima09.example;

public class Android extends Development {
    public Android(String name, int age) {
        super(name, age);
    }
    @Override
    public void project() {
        System.out.println("正在研发安卓项目");
    }
}
package com.itheima09.example;

public class Demo {
    public static void main(String[] args) {
        JavaEE ee = new JavaEE("张三", 18);  //Android也一样可实例化
        ee.work();
        ee.project();
    }
}

在这里插入图片描述

18.实例初始化过程:有几个构造器,就会有几个实例初始化方法

package com.atguigu.test01.block;
/*
 * 1、类的成员:
 * (1)属性:成员变量
 * (2)方法:成员方法
 * (3)构造器
 * (4)代码块分为如下:非静态代码块, 静态代码块(后面讲,和static一起说)
 * 
 * 2、非静态代码块
 * (1)声明的格式:
 * 【修饰符】 class 类名{
 * 		{
 * 			非静态代码块;
 * 		}
 * }
 * (2)非静态代码块中的代码什么时候执行? 在“每次”创建对象的时候执行,比构造器早执行。
 * (3)实例初始化过程:创建对象时,为对象进行初始化的操作,下行【1】和【2】按代码先后,反正【3】最后。
 *     【1】为成员变量显式赋值  【2】执行非静态代码块  【3】执行构造器
 * 
 * Java编译器会把这三个部分的代码,合成一个叫做<init>(【形参列表】)(在.class中)实例初始化方法
 * 即编译后的.class字节码信息中,是没有构造器这个概念。 
 */
public class TestBlock {
	public static void main(String[] args) {	
		Demo d1 = new Demo();//调用无参构造,本质上是调用<init>()实例初始化方法
		Demo d2 = new Demo("atguigu");//调用有参构造,本质上是调用<init>(形参列表)实例初始化方法
	}
}

class Demo{
	{
		System.out.println("非静态代码块1");
	}	
	
	private String str = assign();//调用方法,来为str进行显式赋值
	
	public Demo(){
		System.out.println("无参构造");
	}

	public Demo(String str){
		this.str = str;
		System.out.println("有参构造");
	}
	
	{
		System.out.println("非静态代码块2");
	}
	
	public String assign(){
		System.out.println("assign方法");
		return "hello";
	}
}

如下的线上面是d1实例初始化过程,都是构造排最后。
在这里插入图片描述

package com.atguigu.test01.block;

public class TestInit {
	public static void main(String[] args) {
		/*
		 Son s = new Son();
		 父类的无参构造(运行结果)
		 子类的无参构造
		*/		
		/*
		 Son s2 = new Son("atguigu");
		 父类的无参构造
	     子类的有参构造1
		 */		
		Son s3 = new Son("atguigu", 10);
		/*
		   父类的无参构造
		   子类的有参构造1
		   子类的有参构造2
		 */
	}
}
class Father{
	public Father(){
		System.out.println("父类的无参构造");
	}
}
class Son extends Father{
	private String str;
	private int num;	
	public Son(){
		//隐含了super();  子类的构造器中一定会调用父类的构造器,默认调用父类的无参构造
		System.out.println("子类的无参构造");
	}	
	
	public Son(String str){
		//隐含了super()
		this.str = str;
		System.out.println("子类的有参构造1");
	}
	
	public Son(String str,int num){
		this(str); //间接调用父类无参构造
		this.num = num;
		System.out.println("子类的有参构造2");
	}
}
package com.atguigu.test01.block;
/*
 * super()或super(实参列表)之前说的是调用父类的构造器,其实是调用父类对应的实例初始化方法
 * super()或super(实例列表)之前说的是在子类构造器的首行,其实是在子类实例初始化方法的首行
*/
public class TestInit2 {
	public static void main(String[] args) {
		Zi z = new Zi();//312645 //先是super()
	}
}
class Fu{
	private String strFu = assignFu();
	{
		System.out.println("(1)父类的非静态代码块");
	}
	public Fu(){
		System.out.println("(2)父类的无参构造");
	}
	public String assignFu(){
		System.out.println("(3)父类的assignFu()");
		return "fu";
	}
}

//1111111111111111111111111111111111111111111111111111111111111111111111111111
class Zi extends Fu{
	private String strZi = assignZi();
	{
		System.out.println("(4)子类的非静态代码块");
	}
	public Zi(){
		//super()  ==>调用父类的实例初始化方法,而且它在子类实例初始化方法的首行。
		//有extends先调用构造器
		System.out.println("(5)子类的无参构造");
	}	
	public  String assignZi(){
		System.out.println("(6)子类的assignZi()");
		return "zi";
	}
}
package com.atguigu.test01.block;

public class TestInit3 {
	public static void main(String[] args) {
		Er r = new Er();//612645,因为子类重写了assign(),所以3忽略		
//		Ba b = new Ba();  //312
	}
}
class Ba{
	private String str = assign();
	{
		System.out.println("(1)父类的非静态代码块");
	}
	public Ba(){
		System.out.println("(2)父类的无参构造");
	}
	public String assign(){
		System.out.println("(3)父类的assign()");
		return "ba";
	}
}
class Er extends Ba{
	private String str = assign();
	{
		System.out.println("(4)子类的非静态代码块");
	}
	public Er(){
		//super()  ==>调用父类的实例初始化方法,而且它在子类实例初始化方法的首行,有extends先调用构造器
		System.out.println("(5)子类的无参构造");
	}	
	public String assign(){
		System.out.println("(6)子类的assign()");
		return "er";
	}
}
package com.atguigu.homewok.test06;
/*
 * 实例初始化的过程:
 * (1)父类的实例初始化
 * <init>(){
 * 		x = 10;//父类的x
 * 		this.print();//子类的print,因为this代表的是正在创建的子类对象,而子类重写了print,所以是子类的print。System.out.println("Son.x = " + x);//子类的x  没有赋值x=0
		x = 20;//父类的x
 * }
 * 
 * (2)子类的实例初始化
 * <init>(){
 * 		x = 30;//子类的x
 * 		this.print();//子类的print。System.out.println("Son.x = " + x);//子类的x  已经赋值x=30
		x = 40;//子类的x
 * }
 */
public class Test06 {
	public static void main(String[] args) {
		Father f = new Son(); //先父类构造再子类构造
		System.out.println(f.x);//编译时是Father类型,访问Father中的x  x=20(属性看编译时即左类型)
	}
}

class Father{
	int x = 10;
	public Father(){
		this.print();
		x = 20;
	}
	public void print(){
		System.out.println("Father.x = " + x);
	}
}

class Son extends Father{
	int x = 30;
	public Son(){
		this.print();
		x = 40;
	}
	public void print(){
		System.out.println("Son.x = " + x);
	}
}

在这里插入图片描述

package com.atguigu.homewok.test07;
/*
 *(1)Test07类的初始化
 * <clinit>(){
 * 		int x = 5;//局部变量
		x--;//局部变量	 x=4
 * 		Test07.x--;//静态变量   x = -1
 * }
 *
 *(2)执行main方法
 * System.out.println("x=" + x);//静态变量   -1
 * z--;//静态变量   z=-1
 * method();
 * 		y = z++ + ++z;//静态变量 ,加载为准  
 *《1》先加载z的值“-1” //《2》z自增,z=0 《3》z自增 z =1 《4》加载z的值“1” 《5》求和  “-1” + “1” = 0 《6》把0赋值给y   y=0
 * System.out.println("result:" + (z + y + ++z));
 *《1》加载z的值“1”  《2》加载y的值"0" 《3》z自增  z=2 《4》加载z的值“2”  《5》求和  “1” + “0” + “2”
 */
public class Test07 {
	static int x, y, z;//类变量,静态变量,成员变量   默认值0
	static {
		int x = 5;//局部变量
		x--;//局部变量
	}
	static {
		x--;//静态变量
	}
	
	public static void main(String[] args) {
		System.out.println("x=" + x);//静态变量
		z--;//静态变量
		method();
		System.out.println("result:" + (z + y + ++z));//静态变量
	}

	public static void method() {
		y = z++ + ++z;//静态变量
	}
}

在这里插入图片描述

package com.atguigu.homewok.test08;
/*
 * 1、Base b1 = new Base();
 * 父类的实例初始化,和子类无关
 * <init>(){
 * 		method(100);
 * 			System.out.println("base : " + i);  base:100
 * }
 *  
 * 2、Base b2 = new Sub();
 *(1) 父类的实例初始化
 * <init>(){
 * 		method(100);//执行了子类重写的method() //重要!!!
 * 			System.out.println("sub : " + j);  sub:100
 * }
 *(2)子类的实例初始化
 * <init>(){
 * 		super.method(70);
 * 			System.out.println("base : " + i);	base:70
 * }
 */
public class Test08 {
	public static void main(String[] args) {
		Base b1 = new Base();
		Base b2 = new Sub();
	}
}

class Base {
	Base() {
		method(100);
	}
	public void method(int i) {
		System.out.println("base : " + i);
	}
}

class Sub extends Base {
	Sub() {
		super.method(70);
	}
	public void method(int j) {
		System.out.println("sub : " + j);
	}
}

在这里插入图片描述

package com.atguigu.homewok.test09;
// 考了两个内容:final,方法的参数传递机制
public class Test09 {
	public static void main(String[] args) {
		Other o = new Other(); //o.i=0
		new Test09().addOne(o); //i=1
		System.out.println(o.i); //1
	}	
	//o是引用数据类型,实参给形参的是地址值,那么形参修改了属性,实参也会修改
	//o变量的值不能修改,不是说i的值不能修改
	public void addOne(final Other o){
		o.i++;
	}
}
class Other{
	public int i;//默认值0
}
package com.atguigu.homewok.test02.day10;
/*
 * 实例初始化的过程:
 * (1)父类的实例初始化
 * <init>(){
 * 		System.out.print("1");
 * }
 * 
 * (2)子类的实例初始化	
 * <init>(String name){
 * 		System.out.print("3");
 * 		father = new People(name + " F");//创建了一个父类的对象
 * 			调用父类的<init>(String name){
 * 					System.out.print("2");
 * 			}
 * }
 */
public class Test02 {
	public static void main(String[] args) {
		new Child("mike");
	}
}

class People {
	private String name;
	public People() {
		System.out.print("1");
	}
	public People(String name) {
		System.out.print("2");
		this.name = name;
	}
}

class Child extends People {
	People father;
	public Child(String name) {
		//隐含了super(),走了父类的无参构造
		System.out.print("3");
		father = new People(name + " F");
	}
	public Child() {
		System.out.print("4");
	}
}

在这里插入图片描述

package com.atguigu.homewok.test07.day10;
/*
 * new A(new B());
 * (1)new B()
 * <init>(){
 * 		System.out.println("B");
 * }
 * 
 *(2)new A(B的对象即B b)
 * <init>(B b){
 * 		this();
 * 				System.out.println("A");
 * 		System.out.println("AB");
 * }
 */
public class Test07 {
	public static void main(String[] args) {
		new A(new B());
	}
}

class A {
	public A() {
		System.out.println("A");
	}
	public A(B b) {
		this();
		System.out.println("AB");
	}
}

class B {
	public B() {
		System.out.println("B");
	}
}

在这里插入图片描述

package com.atguigu.homewok.test08.day10;
/*
 * (1)父类实例初始化
 * <init>(){
 * 		System.out.println("base");
 * 		method(100); //子类重写了,执行子类的method //System.out.println("sub : " + j); sub:100
 * }
 * 
 * (2)子类实例初始化
 * <init>(){
 * 		System.out.println("sub");   sub
 * 		super.method(70);  //父类的method //System.out.println("base : " + i); base 70
 * }
 */
public class Test08 {
	public static void main(String[] args) {
		Sub s = new Sub();
	}
}

class Base{
	Base(){
		method(100);
	}
	{
		System.out.println("base");
	}
	public void method(int i){
		System.out.println("base : " + i);
	}
}

class Sub extends Base{
	Sub(){
		//隐含了:super()
		super.method(70); //注意super.
	}
	{
		System.out.println("sub");
	}
	public void method(int j){
		System.out.println("sub : " + j);
	}
}

在这里插入图片描述

18.1 实例初始化和类初始化结合:先类(静态)后实

package com.atguigu.test04;

public class TestInit {
	public static void main(String[] args) {
		Demo d = new Demo();//2631745
	}
}
class Demo{
	{
		System.out.println("(1)Demo的非静态代码块1");
	}
	static{
		System.out.println("(2)Demo的静态代码块1");
	}
	private static String info = assign();
	private String message = getMessage();
	static{
		System.out.println("(3)Demo的静态代码块2");
	}
	
	{
		System.out.println("(4)Demo的非静态代码块2");
	}
	
	public Demo(){
		System.out.println("(5)无参构造");
	}
	public static String assign(){
		System.out.println("(6)assign()方法");
		return "hello";
	}
	public String getMessage(){
		System.out.println("(7)getMessage()方法");
		return "msg";
	}
}
package com.atguigu.test04;
/*
 * (1)先完成父类的类初始化
 * (2)再完成子类的类初始化
 * (3)父类的实例初始化方法
 * (4)子类的实例初始化方法
 */
public class TestInit2 {
	public static void main(String[] args) {
		DemoZi zi1 = new DemoZi(); //2,6,3/,9,13,10/,1,14,4,5/,8,14,11,12
		System.out.println("-------------------");
		DemoZi zi2 = new DemoZi();
	}
}
class DemoFu{
	{
		System.out.println("(1)Demo的非静态代码块1");
	}
	static{
		System.out.println("(2)Demo的静态代码块1");
	}
	private static String info = assign();
	private String message = getMessage(); //子类重写了
	static{
		System.out.println("(3)Demo的静态代码块2");
	}
	{
		System.out.println("(4)Demo的非静态代码块2");
	}
	public DemoFu(){
		System.out.println("(5)无参构造");
	}
	public static String assign(){
		System.out.println("(6)assign()方法");
		return "hello";
	}
	public String getMessage(){
		System.out.println("(7)getMessage()方法");
		return "msg";
	}
}
class DemoZi extends DemoFu{
	{
		System.out.println("(8)");
	}
	static{
		System.out.println("(9)");
	}
	private static String info = assign();
	private String message = getMessage();
	static{
		System.out.println("(10)");
	}
	{
		System.out.println("(11)");
	}
	public DemoZi(){
		System.out.println("(12)");
	}
	public static String assign(){
		System.out.println("(13)");
		return "hello";
	}
	public String getMessage(){
		System.out.println("(14)getMessage()方法");
		return "msg";
	}
}

19.接口:只有abstract可省

在这里插入图片描述
抽(abstract可省)/默(default不可省)。静(static不可省,方片,类名/接口名.)/常。
在这里插入图片描述
类中只有final修饰要初始化,其他不需要。
在这里插入图片描述

package com.itheima04.constant;
/*
* 接口中的常量:1. 接口中的属性没有变量都是常量(一次赋值,终身不变)。默认用 public static final 修饰
*           2. static (静态) : 可以接口名直接调用
*          3. final (最终):  用final修饰的属性是常量,一次赋值,终身不变 
*         4. 软性规范: 常量名一般大写
*/
public class ConstantDemo {
    public static void main(String[] args) {
        System.out.println(A.I); //1
        System.out.println(Student.K); //2  //类名.调用因为static,不能修改因为final(钉子钉住了)
    	System.out.println(Student.j); //0  //Student.i报错,不是静态不能类名.调用
    } 
}
class Student{ //以下都不报错
    int i; 
    static int j;
    public final static int K = 2;
}
interface A{
    int I = 1;
    public static final int J = 2;
}

19.1 鸟类案例:Flyable相当于父类的一个补丁,因为有的鸟会飞,有的鸟不会飞

在这里插入图片描述

package com.itheima05.bird;

public class BirdDemo {
    public static void main(String[] args) {
        Sparrow sparrow = new Sparrow();
        sparrow.name = "杰克";
        sparrow.eat(); //杰克正在吃东西
        sparrow.fly(); //杰克正在扑腾
        
        Qq qq = new Qq();
        qq.name = "企鹅";
        qq.eat(); //企鹅正在吃东西
    }
}
class Bird{
    String name;
    int age;
	//alt+insert快捷键构造函数,但必须鼠标停在类中
    public Bird(){
    }
    public Bird(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void eat(){
        System.out.println(name + "正在吃东西");
    }
}

//11111111111111111111111111111111111111111111111111111111111111111111111
interface Flyable{
    void fly(); //抽象方法
}
class Sparrow extends Bird implements Flyable{ //子类默认调用父类的空参构造
    @Override
    public void fly() {
        System.out.println(name + "正在扑腾");
    }
}
class Qq extends Bird{
}

如下和上面无关。

public class TestInterfaceDefineAndUse {
	public static void main(String[] args) {
//		Flyable f = new Flyable();//接口不能直接创建对象的
		Flyable[] sky = new Flyable[3]; //存放接口的数组
		//数组的元素类型Flyable类型,是接口类型
		sky[0] = new Bird();//多态引用
		sky[1] = new Plane();
		sky[2] = new Kite();		
		for (int i = 0; i < sky.length; i++) {
			//数组的元素类型Flyable类型,是接口类型
			sky[i].fly();
		}
	}
}
interface Flyable{
//	public static final long MAX_SPEED = 7900000;
	long MAX_SPEED = 7900000;	
//	public abstract void fly();
	void fly();
}
interface Jumpable{
	void jump();
}
class Animal{	
}

//1111111111111111111111111111111111111111111111111111111111111111111
class Bird extends Animal implements Flyable,Jumpable {
	//重写接口的抽象方法,实现接口的抽象方法
	@Override
	public void fly() {
		System.out.println("小鸟振翅高飞");
	}
	@Override
	public void jump() {
		System.out.println("双脚跳");
	}	
}

class Plane implements Flyable{
	@Override
	public void fly() {
		System.out.println("靠发动机带动飞行");
	}	
}
class Kite implements Flyable{
	@Override
	public void fly() {
		System.out.println("靠人放");
	}	
}

//1111111111111111111111111111111111111111111111111111111111111111
interface A{
	void a();
}
interface B{
	void b();
}
interface C extends A,B{
	void c();
}
class Impl implements C{ //必须重写3个方法
	@Override
	public void a() {
	}
	@Override
	public void b() {
	}
	@Override
	public void c() {
	}	
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为接口必须重写抽象方法,吃草吃肉和J无关。
在这里插入图片描述

package com.itheima06.tedian;
/*
*     1. 如果两个父接口存在相同 抽象方法。  解决: 子类随便重写一个即可     
*	  2. 如果两个父接口存在相同 默认方法。   解决: 子类必须重写这个默认方法
*     3. 如果两个父接口存在相同 静态方法, 常量。  子类什么都不用做,直接用 接口名调用
*/
public class Demo02 {
    public static void main(String[] args) {
    	J j = new J();
        j.method(); // 10 20
    }
}
interface H{
    public static final int NUMBER = 10; //常量
    void eat(); //抽象
    default void eat2(){ //默认
        //吃草
    }
    static void eat3(){ //静态
    }
}
interface I{
    public static final int NUMBER = 20; 
    void eat(); 
    default void eat2(){ 
    }
    static void eat3(){ 
    }
}

//111111111111111111111111111111111111111111111111111111111111111111
class J implements H,I{  //H,I 是 J的父接口
    @Override
    public void eat() {
    }
    @Override
    public void eat2() {//不能带上default
        //到底吃什么,子类重写后说了算
    }	
    void method(){
        System.out.println(H.NUMBER); //如下都是static,用接口.调用
        System.out.println(I.NUMBER);
        H.eat3();
        I.eat3();
    }
}

19.2 继承(extends)和实现(implements):extends B,C错

package com.itheima06.tedian;
/*
*   1. 类继承类: 只能单继承,不能多继承  class A extends B { }
*   2. 类实现接口: 可以多实现,没有接口与类之间关系  class A implements B,C...{ }
*   3. 接口继承接口: 可以多继承  interface A extends B,C...{  }
*/
public class Demo03 {
    public static void main(String[] args) {
    }
}
interface M{
    void eat();
}
interface L{
    void run();
}
interface N extends M,L{
}

class O implements N{  //1
    @Override 
    public void eat() {
    }
    @Override
    public void run() {
    }
}

class P implements M,L{  //2同1
    @Override
    public void eat() {
    }
    @Override
    public void run() {
    }
}

在这里插入图片描述

package com.itheima06.tedian;
/*
 *  1. 一个类S 继承类Q, 又实现接口R (而Q和R又有相同的方法)
 *     符合就近原则: 继承类Q中的方法 
 *  2. (而Q和R又有相同的方法 : Q中方法不抽象  R方法抽象)
 *     那么子类不用重写R中抽象方法。原理: 用Q中继承过来的方法来 代替 抽象方法重写
 */
public class Demo04 {
    public static void main(String[] args) {      
        S s = new S();
        s.eat(); //吃草
    }
}
abstract class Q{
    public void eat(){
        System.out.println("吃草");
    }
    public abstract void eat2();
    public void eat3(){  //不抽象,S类中不用重写
    }
}
interface R{
    default void eat(){
        System.out.println("吃肉");
    }
    void eat2();
    void eat3();
}
class S extends Q implements R{
    @Override
    public void eat2() { //必须重写抽象方法
    }
}
/*
   1. 任何一个类(除Object之外), 如果没有显示声明继承哪个,那么直接继承Object
   2. 用类中继承来的同名方法 代替 接口中的抽象方法重写
*/
interface T{
    boolean equals(Object obj);
}
class U implements T{ //class U extends Object implements T //Object有equals方法 
}

20.多态:和属性无关,只说方法

package com.itheima07.duotai;
/*
*     java精髓: 接口和多态。多态:提高代码扩展性(当需求改变的时候,代码改的越少,扩展性越强)
*       1. 含义: 一种行为却展示出多种形态
*       2. 表述: 父类/父接口 引用 指向子类对象。 父类/父接口 引用调用方法,执行的是子类重写的方法
*       3. 多态三要素,必要条件
*           1. 继承 (类继承,接口)
*           2. 重写 (方法重写)
*           3. 向上转型 (父类引用指向子类对象)
*
*    向上转型(默认成立的)
*           1. 前提 : 基于继承关系
*           2. 格式:父类类型  变量/引用 = new 子类类型();
*           3. 含义:子类对象 实际上 都可以说是 父类中一种实例即看到狗就说它是种动物 
*
*    为什么一定需要方法重写? 编译看左边,运行看右边
*       1. 运行的时候,子类对象会运行子类重写的方法,无论左边类型是父类/子类(Animal/Dog)
*       2. 问题: 父类中定义的方法 没有用,那为什么一定要写? 是为了通过编译    
* 		1. 编译看左边
*           java代码   -> .class文件   ->  runtime
*                     编译                运行
*                  (编译器 : 不知道运行阶段的事 即 右边的事不关心)
*       2. 运行看右边:右边的内容是在运行阶段赋值给左边
*/
public class DuotaiDemo {
    public static void main(String[] args) {
//        Dog dog = new Dog(); //这是方法重写不是多态
//        dog.eat();

        //向上转型 : 前提继承。如下a是内存地址/变量/引用 即 父类引用指向子类对象
        Animal a = new Dog(); //多态的表现出来的特征:1.编译类型与运行时类型不一致,2.方法重写
        a.eat();// 一种行为eat,多种形态(什么形态.具体要取决是什么对象)。
        //打印出:狗在吃骨头
    }
}

//11111111111111111111111111111111111111111111111111111111111111111
abstract class Animal{
   public void eat(){
       System.out.println("动物在吃饭");
   }
}
class Dog extends Animal{
    public void eat() {
        System.out.println("狗在吃骨头");
    }
}
class Cat extends Animal{
    public void eat() {
        System.out.println("猫在吃鱼");
    }
}

在这里插入图片描述
如下通过编译了,运行报错(右边true运行时才赋值给左边)。
在这里插入图片描述

20.1 多态弊端:用instanceof避免(两者继承关系)

如下是多态的好处。
在这里插入图片描述
如下不看注释掉的,只需给method(new Dog())传入实参,更简便。
在这里插入图片描述
如上会出现问题:猫, 狗,狼 吃各自的东西。但如果是猫, 猫还会加餐吃 猫粮即add方法(如钻石会员加个特效)。
在这里插入图片描述
如下是强制向下转型弊端:method(new Dog())。
在这里插入图片描述

package com.itheima09.duotai3;
/*
* 多态的弊端:向上转型(默认一定成功,向下转型可能失败)之后, 父类引用无法调用子类 特有 的方法(编译看左边)
* 解决:向下转型 也叫 强制类型转换:子类类型 变量 = (子类类型)父类引用
* 
* 强制类型转换是有可能失败的 : ClassCastException(类转换异常)。失败条件: 对象实际上是A类型,硬要转换成B类型
* 避免: 添加一个类型判断:(boolean result = 变量 instanceof 类型)如果变量刚好是A类型, 返回true
*/
public class DuotaiDemo {
    public static void main(String[] args) {
        // 需求: 让各种动物吃东西(早上让猫吃,晚上让狼吃),多态
       	Animal a = new Cat(); //没用method
      	a.eat(); //猫在吃鱼
      	
     	Wolf w = new Wolf();
        method(w); //狼吃肉
        
        method(new Cat());  //猫在吃鱼  猫加餐吃猫粮
	    method(new Dog());  //狗在吃骨头
    }

//1111111111111111111111111111111111111111111111111111111111111111111111    
    public static void method(Animal a){
        a.eat();        
        boolean result = a instanceof Cat;
        if(result){
            Cat c = (Cat)a; //向下转型
            c.add();
        }
    }
}
abstract class Animal{
    public abstract void eat();
}
class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }
}
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫在吃鱼");
    }
    public void add(){
        System.out.println("猫加餐吃猫粮");
    }
}
class Wolf extends Animal{
    @Override
    public void eat() {
        System.out.println("狼吃肉");
    }
}

20.2 多态应用:USB相当于animal抽象类改为接口,里面connect是抽象方法

如下extend()相当于上面method(),USB usb相当于Animal a,usb.connect()相当于a.eat()
在这里插入图片描述

package com.itheima10.computer;

public class Computer { //主
    void open(){
        System.out.println("电脑开机了");
    }
    void close(){
        System.out.println("电脑关机了");
    }
    void extend(USB usb){//interface USB不能实例化,可以USB usb但不能调用时用new USB()传入,new 子类传入
        usb.connect();
    }
}

//11111111111111111111111111111111111111111111111111111111111111111111111
interface USB{ //补丁 //接口: 标准/规范    
    void connect(); //下定义 : 抽象方法
}
class Mouse implements USB{ // 实现接口: 符合某种标准
    @Override
    public void connect() {
        System.out.println("鼠标连接上了");
    }
}
class Keyboard implements USB{
    @Override
    public void connect() {
        System.out.println("键盘连接上了");
    }
}
package com.itheima10.computer;
import com.itheima10.computer.Computer;

public class TestDemo {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.open();
        computer.close();
        
//如下不能写成Computer m =new Mouse();因为不存在继承关系,不是多态
        Mouse m = new Mouse();
        computer.extend(m);     
           
        Keyboard k = new Keyboard();
        computer.extend(k); // k:USB usb = new Keyboard(); //usb可以实例化,因为Keyboard这个类实现了USB这个接口 
    }
}

在这里插入图片描述

package com.atguigu.test02.polymorphism;
/*
 *  多态的应用:多态数组:数组的元素是父类的类型,实际存储的是子类的对象,用这样的数组就可以统一管理所有子类的对象。
 */
public class TestUse1 {
	public static void main(String[] args) {
		//创建一个数组,可以存储各种图形的对象,包括圆对象,矩形对象,三角形对象...
		//Circle[] yuans = new Circle[3]; //这个数组存圆 //本态数组
		//Rectangle[] jus = new Rectangle[3]; //这个数组存矩形	
			
		Graphic[] all = new Graphic[3];//这个数组就可以存储各种图形的对象
		all[0] = new Circle(1.2); //左边的元素all[0]是Graphic类型,右边是子类圆对象
				
		Graphic g2 = new Rectangle(2, 4); //多态//左边g2是Graphic,右边是矩形对象,如下分开写和上面一样。
		all[1] = g2;
		
		all[2] = new Circle(4.2);
		//遍历所有图形的面积
		for (int i = 0; i < all.length; i++) {
			//执行哪个getArea()方法,要看all[i]中存储的是哪个子类的对象
			System.out.println("面积:" + all[i].getArea());
		}
	}
}

//1111111111111111111111111111111111111111111111111111111111111111111111111111
class Graphic{ //Graphic图形
	public double getArea(){
		return 0.0;//这句话没有什么意义,只是为了保证语法
	}
}
class Circle extends Graphic{
	private double radius;
	public Circle(double radius) {
		this.radius = radius;
	}	
	public double getArea(){ //重写
		return 3.14 * radius * radius;
	}
}
class Rectangle extends Graphic{
	private double length;
	private double width;
	public Rectangle(double length, double width) {
		this.length = length;
		this.width = width;
	}	
	public double getArea(){ //重写
		return length * width;
	}
}

在这里插入图片描述

21.final:final只有get方法

package com.itheima01.finald;
/*
*   final: 不可继承(类)如String类很完美    不可重写(方法)   不可修改(属性)
*   方法重写的出现打破了类的封装性, final修饰方法既保证了封装,又保证了继承
*/
public class Demo01 {
    public static void main(String[] args) {
        C c = new C();
        c.eat(); //不能重写但能继承 //联合声明: ~~
    }
}
class B {
    public final void eat(){ //final 修饰方法可继承,不是类。
        System.out.println("联合声明: ~~");
    }
}
class C extends B{ //C是B的发言人
}

在这里插入图片描述
如下i有默认初始值0,所以若final int j = 0,final写了没意义,主因D类使用时无法给j赋值。
在这里插入图片描述
解决如上问题还有如下构造器方法,但是需要删除有漏洞的有参构造器。
在这里插入图片描述
如下无漏洞的有参构造器。
在这里插入图片描述

/*
* 问题: 解释一下都用final修饰,成员变量不给初始值会编译报错, 而局部变量不给初始值不会报错
*       1. 终级规则: java中的变量在使用时,必须有值!!!
*       2. final修饰的成员变量没有默认值
*       3. 现象归纳:
*           1. final修饰变量 如果可以 直接赋值
*           2. final修饰成员变量 , 可在构造方法中赋值 (如果有多个构造,必须都要赋值,也只会执行其中一个)
*           3. final修饰局部变量, 只要保证使用前有值即可,不用不会报错
*/

22.static:修饰的成员变量不进堆

package com.itheima02.staticd;
/*
* static 修饰:1.属性,2.方法,3.代码块
* static修饰属性
*       1. 可以用类名/接口名 直接访问 !!!
*           问题: 为什么非静态属性必须对象调用? 而静态属性可以类名调用?
*               因为static是属于类的, 随着类的加载而加载, 优先于对象
*           1. 非静态属性在堆里中,属于对象的 (有几个对象,就有几份)
*           2. 静态属性在方法区(类区)中, 属于类的 (在内存只有一份,共享一值)
* 
*       2. 静态属性 也可以 通过对象名来调用(不推荐) : 每个对象实际上都是类的实例
*       3. 静态属性 被该类所有对象所共享 (只有一个对象进行修改,那么其他对象的该静态属性都会随之修改)
*       运用: 非静态属性各自对象私有, 静态属性大家共有
*/
public class StaticDemo01 {
    public static void main(String[] args) {
   /*   A a = new A();
        System.out.println(a.i); // 可以,a为对象
        System.out.println(A.j);*/ //可以,A为类名
       
        A a1 = new A();
        a1.i = 2;
        A a2 = new A();
        System.out.println(a2.i);// 1,不是2

        System.out.println(A.j); //以下这几个都一样都为2
        System.out.println(a1.j);
        System.out.println(a2.j);
        System.out.println("--------------------");

        a1.j = 10;
        System.out.println(a2.j); //10,j静态,改了都改
        a2.j = 20;
        System.out.println(a1.j); //20
        System.out.println(A.j); //20
        System.out.println("--------------------");

        Student s1 = new Student();
        Student s2 = new Student();
        s1.schoolName = "黑马";
        System.out.println(s2.schoolName); //黑马
        Student.schoolName = "白马";
        System.out.println(s1.schoolName); //白马
    }
}
class A{
    int i = 1; //非静态属性
    static int j = 2; //静态属性,不给值也没事,因为static可以使用默认初始值,不是final
}
class Student{
    String name;
    int age;
    int money;
    static String schoolName;
}
package com.itheima02.staticd;
/*
*  static修饰方法:0. static随着类的加载而加载, static内容属于类不会进堆。static修饰的内容加载时会进方法区(静态区/类区),非static修饰的内容加载时会进方法区(非静态区/对象区)。
* 
*     1. static方法 可以通过类名调用
*   问题: 为什么 非静态方法地址 要记录到 堆内存? 
*   原因: 非静态方法 可以访问 非静态属性 , 不同的对象的非静态属性是不一样的
*      不同的对象 非静态方法 执行效果也有所不同,所以涉及对象,进堆
*
*    2. static属于类的,跟对象无关 (static优先于对象加载 : 先来调用后到的)
*        2.1 static方法不能调用非静态的属性和方法(跟对象有关系都不可以)
*        2.2 this 和super关键字都不行
*    只要该类对象, 调用静态方法执行效果都一样!!!
*/
public class StaticDemo02 {
    public static void main(String[] args) {        
        B b1 = new B(); 
        b1.name = "张三";
        B b2 = new B(); //又new了,地址不同
        b2.name = "李四";
        b1.method01(); //张三:method01  com.itheima.demo02.B@4554617c
        b2.method01(); //李四:method01  com.itheima.demo02.B@74a14482
        
        b1.method02(); //static method02
        b2.method02(); //static method02
        B.method02(); //static method02
       
        B b = null; //null指堆是空的,找不到method01()
        //b.method01(); //NullPointerException 空指针异常 空引用
        b.method02(); //static method02,对象是空的也没事,静态方法不进堆
    }
}
class B{
    String name;
    public void method01(){
        System.out.println(name + ":method01");
        System.out.println(this); //com.itheima.demo02.B@4554617c
        //System.out.println(this.name); 
    }
    public static  void method02(){//public和static位置无所谓,只要在返回值前就可以
        System.out.println( "static method02");
    }
}

如下method02静态,this属于对象,所以报错。加上name+"static…"会报错,因为name非静态,定义改为static String name就可以。
在这里插入图片描述

package com.itheima02.staticd;
/*
*   static 修饰属性和方法
*       1. static 属性
*           1. 访问 : 类名.静态属性 (标准)
*                    对象名.静态属性(可以,不推荐)
*           2. 静态属性在内存独一份,该类所有对象共享,其中一个对象改变,其他对象该属性都会改变
*           3. 运用: 类的公共属性设置静态(比如: 一个学校的学生: schoolName)
* 
*       2. static 方法
*            1. 访问 : 类名.静态方法 (标准)
 *                    对象名.静态方法(可以,不推荐)
 *           2. 静态方法 不可以调用 非静态的内容 (类先加载,再创建对象)
 *               静态属于类的,随着类的加载而加载的。补充: 非静态可以调用静态
 *               非静态内容: 属性,方法, this,super...
 *           3. 运用: 只要这个方法跟对象中其他内容无关,都可设计static
 *               好处: 节省内存,调用方便
 */
public class StaticDemo03 { //这类名和main方法无关,只是借用类名调用下main方法,所以main是静态的
//    static int i;
    public static void main(String[] args) { //右击运行时jvm会调用main这个入口方法
        int add = C.add(1, 2); //这行不创建对象,好处节省内存,不用在堆上创建空间
        System.out.println(add); //3
        
//      System.out.println(i); //上面第一行static int i注释放开可以 //0
        method03();

		C c = new C();
        c.method01(); // 1 2 2  //非静态对象名.调用
    }
    private static void method03() { // 默认static,因为main是static
    }
}
class C{
    int field = 1;
    static int sField = 2;    
    public void method01(){
        System.out.println(field);
        System.out.println(sField);
        method02();
    }
    public static void method02(){
//        System.out.println(field); //非静态报错
//        method01(); //非静态报错
        System.out.println(sField);
    }
    public static int add(int a, int b){ //这个方法独立于这个对象之外,设计为静态
        return a + b;
    }
}
package com.itheima02.staticd;
/*
*   需求场景:  安装软件/驱动 只要做一次
*   静态代码块
*   static{
*       // 代码
*   }
*   1. 随着类的加载而执行, 优先于构造, 只执行一次
*   2. 只要类加载就能运行,无需手动调用
*   3. 运用: 数据库 (注册驱动)
*/
public class StaticDemo04 {
    /*
    *   右单击: javac xx.java  -> java xx(ideal帮做)
    *   运行: JVM底层 StaticDemo04.main(args) 【main是静态方法,类名.调用】
    *       1. 类先加载 : static代码块先运行,比main方法更快
    *       2. 轮到static方法
    */
    static{
        System.out.println("xx");
    }
    public static void main(String[] args) {
        D d1 = new D();
        D d2 = new D();
        D d3 = new D();
        System.out.println("yy");
    }
}
class D{
    static{
        System.out.println("随着类的加载而执行,无需手动调用");
        System.out.println("因为类的加载全局只有一次,所以static代码块全局只执行一次");
        System.out.println("类的加载优先于对象创建,static代码块最先执行的");
    }
    public D(){
        System.out.println("D的构造方法");
    }
       //方法需要手动调用
    static void method(){
        System.out.println("静态方法");
    }
}

在这里插入图片描述
如下没有创建对象,没有调用方法,运行依然显示:静态代码块。
在这里插入图片描述
如下因为info是static,所以assign方法也应为static。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

23.四大权限修饰符:记住中间两个本包,ppdp

在这里插入图片描述

package com.itheima03.privilege;
import com.itheima00.question.Fu; 
/*
*  java四大权限修饰符:public > protected > default(不写) > private
*       1. public : 公共的 , 全工程可访问
*       2. protected : 受保护的 , 【本包 + 跨包子类内部】 
*       3. default : 默认, 【本包】   
*       4. private: 私有, 除【本类】内部,其他不可访问
*/
public class FourDemo {
    public static void main(String[] args) {
        Fu fu = new Fu();
        Zi zi = new Zi();
    }
}
class Zi extends Fu{ 
    public void eat(){
        System.out.println(id1);
        System.out.println(id2); //跨包 子类的内部可访问 //import com.itheima00.question.Fu;
    }
}
package com.itheima04.review;
/*  
*  修饰符:static,final,abstract,default
*  修饰符矛盾 (编译报错):
*  1. private 和 abstract 不能共存: abstract方法不重写没有意义,但是private方法又不能被重写 -> 矛盾
*  2. final 和 abstract 不能共存: final修饰的方法不能被重写
*  3. static 和 abstract 不能共存: static方法也不能被重写,因为static方法属于类
*/
public class XiuShiFuDemo {
    public static void main(String[] args) {
    }
}
abstract class A{
    abstract void method01(); //没有{}方法体,前面没有public,只有接口默认有public
    private static void method02(){ //可以,只能在本类里让其他方法调用如下
    }
    static void method03(){ 
        method02();
    }
}

24.String类:字符串常量在Java中不属于基本数据类型, 而是引用/类类型。Java程序中所有字符串如"abc"都可被看作是实现java.lang.String类的实例

1.字符串常量:它属于对象,但是它不是像之前的对象通过new的方式在中开辟空间,而是存储在字符串常量池中。说明:jdk1.7之前字符串常量池是位于方法区中的,而jdk1.7之后是位于中的。

位于堆中和之前new空间不冲突,常量池是一个单独的空间。字符串常量池中保存的就是所有的字符串数据。只要书写了双引号,不管双引号中间是什么数据,这些数据都会立刻在字符串常量池中保存,并且一直存在,不会被改变。所有在Java程序中使用双引号引用起来的数据都是一个对象。

2.字符串不变:字符串的值在创建后不能被更改。String类中描述的是所有字符串常量,一旦书写完成,它就是一个固定值,这个数据不能改变。

String s3="def";
s3="efg";
System.out.println(s3);
// 内存中有"def","efg"两个对象,s3从指向"def",改变指向,指向了"efg"。

String对象是不可变的,所以它们可以被共享。

String s1="abc"; //定义字符串对象
//int i=3;在栈中开辟空间名称叫做i,存值为3
String s2="abc";
//System.out.println(s1); //abc  //打印的不是内存地址名,是abc常量的值
System.out.println(s1==s2);//这里比较的是内存地址名是否相等 //true

如下string str 是方法中引用类型的局部变量,所以在左边栈中。
在这里插入图片描述
如下main中第一行:JVM会在内部的String pool中查找有没有字符串常量"hello",没有的话创建"hello"对象。
第二行:JVM在String pool中查找,有则返回"hello"的地址,这里虽然没创建对象,但str1并不等于str2,因为引用的地址不一样(str1指向堆内存地址,str2指向字符串池地址)
第三行:JVM同样在String pool中查找,有字符串常量"hello"则不再创建。由于使用了new,JVM又在堆中创建一个"hello"对象。
在这里插入图片描述

24.1 使用:new String(…)

构造方法:用双引号本身就可得到一个字符串对象。String类提供了大量的构造函数,目的是可以帮助我们将其他的数据变成字符串对象。只要使用String类的构造函数创建的对象,那么这个对象就会在中出现。而在创建出的字符串对象中的字符数据保存在常量池

// 无参构造  // java.lang.String
String str = new String();//构造函数

// 通过字符数组构造,将参数的字符数组转换为String类的对象
char chars[] = {'a', 'b', 'c'};     
String str2 = new String(chars);

// 通过字节数组构造,将参数的字节数组转换为String类的对象
byte bytes[] = { 97, 98, 99 };     
String str3 = new String(bytes);

24.2 判断:equals函数是用来比较两个对象是否相等

public class String_Demo01 {
    public static void main(String[] args) {
        // 创建字符串对象
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "HELLO";
        // boolean equals(Object obj):比较字符串的内容是否相同
        System.out.println(s1.equals(s2)); // true
        System.out.println(s1.equals(s3)); // false

        //boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写
        System.out.println(s1.equalsIgnoreCase(s2)); // true
        System.out.println(s1.equalsIgnoreCase(s3)); // true
    }
}

如果想比较两个字符串相等,我们不应该使用 == (恒等符号),因为 == 是用来比较具体常量数值的。而由于字符串是对象,所以我们应该使用String类中的equals函数对两个字符串进行比较。

24.3 比较:able to重要,or e

package com.atguigu.test05;
/*
 * java.util.Comparator:定制比较,定制顺序,是对自然比较的补充
 * 		int compare(Object o1, Object o2)://接口的抽象方法(要重写)
 * 				o1与o2比较,o1>o2,返回正整数
 * 				o1与o2比较,o1<o2,返回负整数
 * 				o1与o2比较,o1=o2,返回0
 * java.lang.Comparable:自然比较,自然顺序,核心默认不用导包。
 * 		int compareTo(Object obj)  // 接口的抽象方法(要重写)
 * 				this与obj对象比较,this > obj,返回正整数
 * 				this与obj对象比较,this < obj,返回负整数
 * 				this与obj对象比较,this = obj,返回0
 */
public class TestComparable {
	public static void main(String[] args) {
		Student s1 = new Student("杨洪强", 24, 89);
		Student s2 = new Student("苏海波", 23, 100);		
		//按成绩比较,不用第三个对象了
		if(s1.compareTo(s2)>0){
			System.out.println("s1 > s2成绩");
		}else if(s1.compareTo(s2)<0){
			System.out.println("s1 < s2成绩");
		}else{
			System.out.println("s1 = s2成绩");
		}		
	}
}
class Student implements Comparable{  //希望学生对象本身就具备比较大小的能力。
	private String name;
	private int age;
	private int score;
	public Student(String name, int age, int score) {
		super();
		this.name = name;
		this.age = age;
		this.score = score;
	}
	public Student() {
		super();
	}
	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 int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
	}
	@Override
	public int compareTo(Object obj) {	
		Student other = (Student) obj; //this与obj比较,this和obj都是学生对象
		//例如:对于学生对象来说,最常用的是按成绩排名,那么我就可以把自然顺序定位成绩升序
     /*	if(this.score > other.score){
			return 1;
		}else if(this.score < other.score){
			return -1;
		}
		return 0;*/		
		return this.score - other.score;
	}
}

在这里插入图片描述

package com.atguigu.test05;
import java.util.Arrays;
/*
 * Arrays的sort方法有两种:(1)void sort(Object[] arr):
 * 根据元素的 自然顺序 对指定对象数组按升序进行排序。数组中的所有元素都必须实现 Comparable 接口
 * (2)void sort(Object[] arr, Comparator c):
 * 根据“指定比较器”产生的顺序对指定对象数组进行排序。数组中的所有元素都必须是通过“指定比较器”可相互比较
 */
public class TestArrays {
	public static void main(String[] args) {
		Student[] all = new Student[5];
		all[0] = new Student("杨洪强", 24, 89);
		all[1] = new Student("苏海波", 23, 100);
		all[2] = new Student("张三",23,88);
		all[3] = new Student("李四",24,44);
		all[4] = new Student("王五",25,45);		
		//如果我们的学生类Student,实现了java.lang.Comparable接口,
		//能不能按照自然排序的规则进行排序呢?
		//Arrays中有这样的方法:public static void sort(Object[] a)		
		Arrays.sort(all);
		//这里面排序过程中,调用了元素本身的compareTo()方法
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}
}

如下按成绩升序,因为Student类本身实现了Comparable接口重写了compareTo方法。
在这里插入图片描述
在这里插入图片描述
如上结果为:[Alice,chai,hello,Hi,Java]

24.4 获取:.charAt,.indexOf

package com.itheima.demo01;
import java.lang.String;

public class HelloWorld {
    public static void main(String[] args) {
        // String concat (String str):将指定的字符串连接到该字符串的末尾.
        String s = "helloworld";
        String s2 = s.concat("**hello itheima");
        System.out.println(s2);// helloworld**hello itheima

        // char charAt(int index):获取指定索引处的字符
        System.out.println(s.charAt(0)); // h
        System.out.println(s.charAt(1)); // e

        // int indexOf(String str):获取str在字符串对象中第一次出现的索引,没有返回-1
        System.out.println(s.indexOf("l")); //2
        System.out.println(s.indexOf("owo")); //4
        System.out.println(s.indexOf("ak")); //-1

        // String substring(int start):从start开始截取字符串到字符串结尾
        System.out.println(s.substring(0)); // helloworld
        System.out.println(s.substring(5)); // world

        // String substring(int start,int end):从start到end截取字符串。含start,不含end。
        System.out.println(s.substring(0, s.length())); // helloworld
        System.out.println(s.substring(3,8)); // lowor,不含8即l
    }
}

24.5 转换:.toCharArray,.getBytes,.replace

package com.itheima.demo01;
import java.lang.String;

class String_Demo03 {
    public static void main(String[] args) {
        String s = "abcde";
        char[] chs = s.toCharArray(); // 把字符串转换为字符数组
        for(int x = 0; x < chs.length; x++) {
            System.out.println(chs[x]);  // a b c d e
        }
        byte[] bytes = s.getBytes(); //把字符串转换为字节数组
        for(int x = 0; x < bytes.length; x++) {
            System.out.println(bytes[x]); // 97 98 99 100 101
        }
        String str = "itcast itheima";
        String replace = str.replace("it", "IT");
        System.out.println(replace); // ITcast ITheima
    }
}

24.6 分割:.split

public class String_Demo03 {
    public static void main(String[] args) {
        String s = "aa,bb,cc";
        String[] strArray = s.split(","); // ["aa","bb","cc"],字符串对象拆为字符串数组
        for(int x = 0; x < strArray.length; x++) {
          	System.out.println(strArray[x]); // aa bb cc
        }
    }
}

24.7 模拟用户登录:.nextLine,.equals

package com.itheima.demo01;
import java.util.Scanner;
// 需求:已知用户名和密码,用程序实现模拟用户登录,一共给3次机会,登陆后给出相应提示。
class StringTest01 {
    public static void main(String[] args) {
        //已知用户名和密码,定义两个字符串表示即可
        String username = "itheima";
        String password = "czbk";
        //用循环实现多次机会,这里的次数明确,采用for循环实现,并在登录成功的时候,使用break结束循环
        for(int i=0; i<3; i++) {
            //键盘录入要登录的用户名和密码,用 Scanner 实现
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String name = sc.nextLine();
            System.out.println("请输入密码:");
            String pwd = sc.nextLine();
            //拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。字符串的内容比较,用equals() 方法实现
            if (name.equals(username) && pwd.equals(password)) {
                System.out.println("登录成功");
                break;
            } else {
                if(2-i == 0) {
                    System.out.println("你的账户被锁定,请与管理员联系");
                } else {
                    //2,1,0
                    //i为0,1,2
                    System.out.println("登录失败,你还有" + (2 - i) + "次机会");
                }
            }
        }
    }
}

在这里插入图片描述

class CodeDemo {
    public static void main(String[] args) throws IOException {
        String username = "ta";
        String password = "123";

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = sc.nextLine();        
        if(name.length() == 0){
            System.out.println("登录失败");
            return;
        }

        System.out.println("请输入密码:");
        String pwd = sc.nextLine();        
        if(pwd.length() == 0){
            System.out.println("登录失败");
        }
        
        if (name.equals(username) && pwd.equals(password)){
            System.out.println("登录成功");
        } else {
                System.out.println("登录失败");
    }
}}

24.8 遍历字符串:.charAt

public class StringTest02 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String line = sc.nextLine();     
           
        for(int i=0; i<line.length(); i++) {
            System.out.println(line.charAt(i)); //空字符也遍历
        }
    }
}

24.9 统计字符个数:&&

public class StringTest2 {
    public static void main(String[] args) {
        //键盘录入一个字符串数据,统计字符串大小写字母及数字字符个数
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串数据:");
        String s = sc.nextLine();
        //定义三个统计变量,初始化值都是0
        int bigCount = 0;
        int smallCount = 0;
        int numberCount = 0;
        //遍历字符串,得到每一个字符
        for(int x=0; x<s.length(); x++) {
            char ch = s.charAt(x);
            //拿字符进行判断
            if(ch>='A'&&ch<='Z') {
              	bigCount++;
            }else if(ch>='a'&&ch<='z') {
              	smallCount++;
            }else if(ch>='0'&&ch<='9') {
              	numberCount++;
            }else {
              	System.out.println("该字符"+ch+"非法");
            }
        }
        System.out.println("大写字符:"+bigCount+"个");
        System.out.println("小写字符:"+smallCount+"个");
        System.out.println("数字字符:"+numberCount+"个");
    }
}

24.10 字符串拼接:+

public class StringTest1 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        String s = arrayToString(arr);
        System.out.println("s:" + s); //s:[1#2#3]
    }
    /*
     * 写方法实现把数组中的元素按照指定的格式拼接成一个字符串
     * 两个明确:返回值类型:String。 参数列表:int[] arr
     */
    public static String arrayToString(int[] arr) {
        //String s = new String("[");
        String s="[";
        // 遍历数组,并拼接字符串
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
              	s = s+arr[x]+"]";
            } else {
              	s = s+arr[x]+"#";
            }
        }
        return s;
    }
}

24.11 字符串反转:i- -

public class StringTest05 {
    public static void main(String[] args) {
        //键盘录入一个字符串,用 Scanner 实现
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String line = sc.nextLine();
        
        String s = reverse(line); //调用方法,用一个变量接收结果
        System.out.println("s:" + s); //输出结果
    }
    // 两个明确:返回值类型:String。参数:String s  
    public static String reverse(String s) {
        //在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回
        String ss = "";
        for(int i=s.length()-1; i>=0; i--) {
            ss += s.charAt(i);
        }
        return ss;
    }
}

24.12 空字符串判断:.intern()

/*
 * (1)常量 + 常量 在常量池
 * (2)变量 +常量 在堆
 * (3)变量 + 变量 在堆
 * (4)xx.intern():在常量池
 * 
 * 空字符串:(1)""
 *          (2)new String()
 * 			(3)new String("")
 * 
 * 四种判空方式:(1)if(str != null && str.length() == 0)
 * 				(2)if(str != null && str.equals("")){
 * 				(3)if("".equals(str))  推荐
 * 				(4)if(str!=null && str.isEmpty())
 * /

25.StringBuilder类:线程不安全但速度快于stringbuffer(线程安全即每个方法上都加synchronized,效率低,抛弃)

25.1 构造方法:new StringBuilder(" ")

StringBuilder又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容。String类(内容是不可变的),StringBuilder类(内容和长度是可变的,将任意数据都转成字符串进行存储)。

public class StringBuilderDemo {
    public static void main(String[] args) {
        StringBuilder sb1 = new StringBuilder();
        System.out.println(sb1); // (空白)
        
        //使用带参构造 public StringBuilder(String str)
        StringBuilder sb2 = new StringBuilder("itcast");
        System.out.println(sb2); // itcast
    }
}

25.2 append方法:StringBuilder已经覆盖重写了Object当中的toString方法

append方法具有多种重载形式,可以接收任意类型的参数。任何数据作为参数都会将对应的字符串内容添加到StringBuilder中。

public class Demo02StringBuilder {
	public static void main(String[] args) {
		StringBuilder builder = new StringBuilder(); //创建对象
		StringBuilder builder2 = builder.append("hello");
		System.out.println("builder:"+builder);  //builder:hello
		System.out.println("builder2:"+builder2); //builder2:hello
		System.out.println(builder == builder2); //true
	    // 可以添加 任何类型
		builder.append("hello");
		builder.append("world");
		builder.append(true);
		builder.append(100);
		// 在我们开发中,会遇到调用一个方法后,返回一个对象的情况。然后使用返回的对象继续调用方法。
        // 这种时候,我们就可以把代码现在一起,如append方法一样,代码如下
		builder.append("hello").append("world").append(true).append(100); //链式编程
		System.out.println("builder:"+builder); //builder:hellohelloworldtrue100helloworldtrue100
	}
}

25.3 toString方法:StringBuilder对象将会转换为不可变的String对象

public class Demo16StringBuilder {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");
        String str = sb.toString();
        System.out.println(str); // HelloWorldJava
    }
}

25.4 reverse方法:.reverse()

public class Demo16StringBuilder {
    public static void main(String[] args) { 
	//public StringBuilder reverse():返回相反的字符序列
 	 StringBuilder sb = new StringBuilder("Hello").append("World").append("Java");
   	 sb.reverse();
   	 System.out.println("sb:" + sb); //sb:avaJdlroWolleH
   }
}

25.5 StringBuilder和String相互转换:toString()

public class StringBuilderDemo02 {
    public static void main(String[] args) {        
        //111111111111111111111StringBuilder转换为String
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        //String s = sb; //这个是错误的做法        
        String s = sb.toString(); 
        System.out.println(s); //hello
        
        //111111111111111111String转换为StringBuilder
        String s = "hello";
        //StringBuilder sb = s; //这个是错误的做法
        StringBuilder sb = new StringBuilder(s);//public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder
        System.out.println(sb); //hello
    }
}

25.6 字符串拼接:定义一个方法将int[] arr = {1,2,3}输出为:[1, 2, 3]

/*
        1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
        2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
          返回值类型 String,参数列表 int[] arr
        3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
        4:调用方法,用一个变量接收结果
        5:输出结果
 */
public class StringBuilderTest01 {
    public static void main(String[] args) {        
        int[] arr = {1, 2, 3};//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
        System.out.println(arr); //[I@14ae5a5
        String s = arrayToString(arr);
        System.out.println("s:" + s); //s:[1, 2, 3]
    }
    
    // 两个明确:返回值类型:String   参数:int[] arr
    public static String arrayToString(int[] arr) {
        //在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for(int i=0; i<arr.length; i++) {
            if(i == arr.length-1) {
                sb.append(arr[i]);
            } else {
                sb.append(arr[i]).append(", ");
            }
        }
        sb.append("]");
        String s = sb.toString();
        return  s;
    }
}

25.7 字符串反转:返回值类型:String , 参数:String s

public class StringBuilderTest02 {
    public static void main(String[] args) {        
        Scanner sc = new Scanner(System.in);  
        System.out.println("请输入一个字符串:");
        String line = sc.nextLine();
        String s = myReverse(line);
        System.out.println("s:" + s);
    }

    public static String myReverse(String s) {
        //在方法中用StringBuilder实现字符串的反转,并把结果转成String返回
        //String --- StringBuilder --- reverse() --- String
//        StringBuilder sb = new StringBuilder(s);
//        sb.reverse();
//        String ss = sb.toString();
//        return ss;
     return new StringBuilder(s).reverse().toString();
    }
}

26.ArrayList类:ArrayList list = new ArrayList()

26.1 引入—对象数组:基本数据类型变量只保存基本数据类型,不能保存对象。引用数据类型变量是可保存对象,但只能保存一个对象

package cn.itcast.sh.demo;

public class Student {
	String name;
	int age;	
	public Student(String name, int age) { //定义构造函数给属性初始化值
		this.name = name;
		this.age = age;
	}	
	public String getName() { //给属性生成get和set方法
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
package cn.itcast.sh.demo;

public class ArrayDemo {
	public static void main(String[] args) {		
		Student[] arr=new Student[3]; //创建Student类型的数组		
		Student s1=new Student("heixuanfeng",19); //创建Student类的对象
		Student s2=new Student("bandao",18);
		Student s3=new Student("zhujiao",20);		
		arr[0]=s1; //将学生对象存储到数组中
		arr[1]=s2;
		arr[2]=s3;
		for (int i = 0; i < arr.length; i++) {			
			Student s=arr[i]; //通过数组名和下标取出Student类的数组中的数据 arr[i]
			System.out.println(s.getName()+"====="+s.getAge());
		}
	}
}

目前只学习了2种存储数据的容器:变量 、数组集合容器可解决上面用数组重复代码太多。
集合与数组区别:变,只对,不。
1)长度
数组:需要固定长度。
集合:长度可以改变,可以根据保存的数据进行扩容。
2)存储内容
数组:可以存储基本类型数据,还可以存储引用类型的数据。
集合:只能存储引用类型的数据,也就是说集合只能存储类的对象。
3)存储类型
数组:只能存储相同类型的数据。
集合:可以存储不同类型的数据。

26.2 ArrayList类使用:public ArrayList() 构造一个内容为空的集合

java.util.ArrayList <E><E> 表示一种指定的数据类型,叫做泛型。E 取自Element(元素)的首字母。在出现E 的地方,我们使用一种引用数据类型将其替换即可,表示我们将存储哪种引用类型的元素。

ArrayList<String>ArrayList<Student>

JDK 7后,右侧泛型的尖括号之内可以留空,但是<>仍然要写。简化格式:

ArrayList<String> list = new ArrayList<>();

成员方法: public boolean add(E e) : 将指定的元素添加到此集合的尾部。参数 E e ,在构造ArrayList对象时,<E>指定了什么数据类型,那么add(E e)方法中只能添加什么数据类型的对象。

//需求:使用ArrayList类,存储三个字符串元素
public class Test02StudentArrayList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(); //创建集合对象
        String s1 = "曹操";
        String s2 = "刘备";
        String s3 = "孙权";        
        System.out.println(list); //[] //打印ArrayList集合
        list.add(s1);
        list.add(s2);
        list.add(s3);
        System.out.println(list); //[曹操, 刘备, 孙权]
    }
}

26.3 常用方法和遍历:对于元素的操作:增、删、查

public class Demo01ArrayListMethod {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("java");
        //public E get(int index):返回指定索引处的元素
        System.out.println("get:"+list.get(0));  //get:hello
        System.out.println("get:"+list.get(1));  //get:world
        System.out.println("get:"+list.get(2));  //get:java
       
        //public int size():返回集合中的元素的个数
        System.out.println("size:"+list.size());  //size:3
        
        //public E remove(int index):删除指定索引处的元素,返回被删除的元素
        System.out.println("remove:"+list.remove(0)); //remove:hello
        
        for(int i = 0; i < list.size(); i++){
        	System.out.println(list.get(i));  //world java
        }
    }
}

27.Object类:对象都需重写

package com.itheima00.question;

public class Demo01 {
    public static void main(String[] args) {
//        C c = new C();
//        c.method02(); // 可以 //static,final修饰的方法都是可以被继承,但不能重写
//        c.method01(); // 错误 //interface静态方法不能被继承,但是class静态方法可以被继承

        B b = new C(); //向上转型,静态和对象无关,属于类的。所以面向对象三大特性和静态无关
		// B b = null;这样写下行也一样,因为和对象无关
        b.method02(); //b method02,不是c method02 (多态), 静态 和 多态 冲突了
    }
}

//111111111111111111111111111111111111111111111111111111111111111111111111111
interface A{
    static void method01(){ //接口中静态方法不能继承,肯定不能重写
    }
}

class B{
    static int i;
    static void method02(){//类中静态方法可以继承,但不能重写(原因: 静态方法属于类的->重写就多态冲突了,如上b.method02();)
        System.out.println("b method02");
    }
}

class C extends B implements A{
    static void method04(){
        System.out.println("c method02");
    }
    void method03(){ //如下都可以,但注意权限问题
        super.method02();
        System.out.println(i);
    }
}

27.1 toString方法:Object中的tostring方法: 对象类型包名类名 + 内存地址

在这里插入图片描述

package com.itheima01.object;
import java.util.ArrayList;
/*
*   Object类 : 所有类除Object本身之外(包括数组)的父类是Object
*   1.  String toString()  返回该对象的字符串表示。
*   2.  boolean equals(Object obj)  指示其他某个对象是否与此对象“相等”。
*  
*   toString方法:
*       1. 结论: 如果直接打印对象,调用这个对象的toString方法
 *       println(String s) : s会被直接打印
 *       println(Object obj) 源码
 *           (obj == null) ? "null" : obj.toString(); 判空 : 避免空指针异常   
		2. 运用:
 *          1. 打印对象内存地址是没有意义, 想要打印对象的属性值 (方便测试)
 *          2. 解决: 这个类重写toString方法
 */
public class ObjectDemo01 {
    public static void main(String[] args) {
//        method01(); 

//        Person p = new Person();
        Person p = new Person("zs",18);
        System.out.println(p); //com.itheima01.object.Person@1540e19d  类型包名类名+ 内存地址
        System.out.println(p.toString()); //同上 //类中重写了toString方法后,p和p.toString()两个都打印出:Person{name='zs',age=18}

        ArrayList<String> list = new ArrayList<>();
        list.add("zs");
        list.add("ls");
        list.add("ww"); //打印引用类型,如果打印的不是内存地址,说明重写了toString
        System.out.println(list.toString()); // [zs,ls,ww]
    }

    public static void method01(){
        int[] array = {1,2,3};
        System.out.println(array.length); //3
        
        String json = array.toString();
        boolean result = array instanceof Object; //验证数组的父类是不是Object
        System.out.println(result); //true
    }  
}

//111111111111111111111111111111111111111111111111111111111111111111
class Person{
    String name;
    int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

   /* @Override
    public String toString() {
//        return super.toString();
        String msg = "name:" + name + ",age=" + age;
        return msg;
    }*/
 
   //快捷键: alt + insert -> toString 效果如下
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在这里插入图片描述

27.2 equals方法:Object类中的equals方法是==比较内存地址

package com.itheima01.object;
import java.util.Objects;
/*
*   == : java只有值传递,所以==不管是比较基本数据类型还是引用数据类型变量,本质比较的都是值,只是引用数据 类型变量存的值是对象地址
* 
*  	  1. 比较内存地址已经有== , equals这样设计没有意义的
*     2. 想要比较两个对象的属性(包括身份证号)是否完全一致 , 实际推断为是同一对象
*	   (实际含义和java内存含义不一样,虽然各自new内存不一样)
*	
*     解决: 重写equals (两个对象逐一比较每个属性,如果两个对象每个属性都相同,返回true,否则返回false)
*     快捷键:  alt + insert -> equals and hashcode。  equals最主要运用: 哈希表
*/
public class ObjectDemo02 { 
    public static void main(String[] args) {
        Student s1 = new Student("zs", 18);
        Student s2 = new Student("zs", 18);
        System.out.println(s1 == s2);//false:引用类型比较的是内存地址(new出来的内存地址肯定不一样)
        System.out.println(s1.equals(s2)); // false同上,比较的是内存地址,如下重写equals()后为true
    }
}

//1111111111111111111111111111111111111111111111111111111111111111111
class Student{
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /*
        this : s1
        obj : s2
            name ,age -> Student
    */
   /* @Override
    public boolean equals(Object obj) {
        boolean result = obj instanceof Student; //如果是学生类型才继续往下走
        //boolean result = this.getClass() == obj.getClass();//源码中这样写,同上        
        if (!result){ //如果你传入不是student类型, 两个绝不一样,直接return false
            return false; //result为false时,!result为true进入if内return false
        }    
            
        Student s2 = (Student) obj; //向下转型: 调用子类特有属性和方法
        boolean result2 = this.name.equals(s2.name);        
        if(!result2){
            return false;
        }        
        return this.age == s2.age;
    }*/

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true //因为a为String,String中的equals方法是被重写过(比较对象的值)
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

27.3 hashCode方法和equals方法:两个对象hashCode方法返回值相同,那么这两个是否equals?或者两个对象equals,那么hashCode方法返回值是否相同?

在这里插入图片描述
两个方法没有任何联系,因为我们可随意重写这两个方法如上,但是重写这两个方法时应该满足下面3个规范:1.对于同一个对象,没有任何属性变化:则多次求hashCode返回值应该是相同的,多次和另一个对象equals比较,返回值也应相同。如下random随机不稳定不符合规范。2.equals源码决定。3.hashmap存储结构决定,如下第二张图不符合第3个规范。
在这里插入图片描述

为什么要有如上这样的规范?牵扯到一系列hash存储

如下以hashmap为例,在hashmap中通过hashcode计算得到出的值就是数组的下标,例如下标=1,就在1这个桶中找对于元素,1这个桶可能存储的是链表或红黑树,假如是链表,就要在这个链式存储中挨个查找是否是我们想要的元素,挨个查找的时候我们需要equals方法对比每个节点的key和我们需要找的key是否equals。

所以如果hashcode值不稳定,那么每次查找时就打到不同桶里面。如果两个对象equals但hashcode不相等就会导致两次求index下标时求得不同下标。
在这里插入图片描述

28.基本类型包装类:基本类型字节数,缓存池

package com.itheima00.question;
/*
  I love java
    me 2
*/
public class ToStringTest {
    static int i = 1;
    public static void main(String args[]) {
        System.out.println("love " + new ToStringTest());                
        // string + object.toString() = string //解释上行,先走toString()打印出"I" //终极规则:string + object = string
        //  love + java  //因为new ToStringTest()返回toString()(下面有写)即"java "
        
		ToStringTest a = new ToStringTest();
        a.i++; // 2 (静态变量i被该类所有对象所共享)
        System.out.println("me " + ToStringTest.i); //类名.i
    }	  

    public String toString() {
        System.out.print("I ");
        return "java ";
    }
}

如下三个工具类有个特点即方法都静态。
在这里插入图片描述
在这里插入图片描述

package com.itheima01.pack;
import java.util.Scanner;
/*
    场景: 控制台/网页 输入的所有内容 对java程序都是字符串
        面向对象: 解决问题,找到对象,然后调用方法来解决问题
                 我/猫  打开  门
                 打开行为 属于 门
                 
*   基本类型包装类
*       1. 需求: 类型转换 : String - > int
*       2. 问题: int 基本类型 (没有属性和方法即没有打开行为),预定义在jvm虚拟机中,连包都没有
*       3. Integer 引用类型,这样可以面向对象设置一些方法parseInt(),将类型转换方法设置到Integer中  
*   
*      基本: byte short int       long float double  char     boolean
*      引用: Byte Short Integer   Long Float Double Character  Boolean (只有int,char不对应)
*      目的: 提供 string 转化成相应基本类型的方法。Integer:static int parseInt(String str) : 将字符串解析成int
*/
public class PackDemo {
    public static void main(String[] args) {
        // method01();
        String str = "100";
        int count = Integer.parseInt(str);//Integer是类即引用类型,parseInt静态方法,参数是字符串,返回int
        // long l = Long.parseLong(str); // parse解析
        System.out.println(count + 1); //101
    }

    private static void method01() {
        System.out.println("请输入你的余额:");
        Scanner sc = new Scanner(System.in);        
//    String str = sc.next();   
//    int s = Integer.parseInt(str); //String->int ,别的类型转为我自己int类型,方法设在int上
        int s = sc.nextInt(); //nextInt()底层就是上面两行
        System.out.println(s + 1);//101
    }
}
package com.itheima01.pack;
/*
*   JDK1.5特性: 自动拆箱 : 在运算过程, Integer -> int
*               自动装箱 : 在赋值过程, int -> Integer
*/
public class PackDemo02 {
    public static void main(String[] args) {
//        method01();
        Integer i1 = new Integer(200);
        Integer i2 = new Integer(200);
        System.out.println(i1 == i2);//false  new出来:比的是地址
        System.out.println(i1.equals(i2)); //true,Integer重写了equals

        Integer i3 = 200; // 自动装箱 int ->Integer(Integer是引用数据类型有地址)
        Integer i4 = 200; // 同上,这样i4可以调用toString,compareTo,intValue(很少用,用自动拆箱)等方法
        System.out.println(i3 == i4); //false
        System.out.println(i3.equals(i4)); //true 

        /*
        *   Integer内部缓存池: cache
        *           -128 ~ 127(byte取值范围) 最常用(6种数据类型都包含这范围)
        *      1. 如果创建一个Integer对象,那么先去缓存池中看看,有没有这个对象
        *      2. 如果没有,就创建这个对象。如果有, 就直接返回这个对象
        */
        Integer i5 = 100; // 0x0001 缓存池
        Integer i6 = 100; // 0x0001,i6.valueof点进源码可看见  
        System.out.println(i5 == i6);//true  i5和i6的地址是一样
        System.out.println(i5.equals(i6));//true
    }

    private static void method01() {
		//Integer i = new Integer(200); //Integer作为一个引用类型应该要去new
        Integer i = 200;// 自动装箱,等于上行,200基本类型自动变为对象即引用类型
        int y = i + 1; // 自动拆箱
        System.out.println(y);//201
    }
}

在这里插入图片描述

Integer i = 10;  //装箱
int n = i;   //拆箱

在这里插入图片描述

29.集合:单/双例,Arrays.toString(array)

package com.itheima02.container;
import java.util.ArrayList;
// java容器:1. 数组  2. 集合(变,只对,不)
public class ContainerDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3};
        Person[] array2 = {new Person(),new Person()};
        String[] array3 = {"abc","bcd"};
        Object[] array4 = {"abc",new Person()}; //多态: 向上转型,都转为Object类型
        
        ArrayList<Integer> list = new ArrayList<>(); //ArrayList<Integer>泛型里不可写<int>基本数据类型
        list.add(1);
        list.add(2); // 自动装箱成引用数据类型
    }
}
class Person{
}  

在这里插入图片描述
在这里插入图片描述

package com.itheima03.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/*
  collection(东西收集在一起就是集合)常用方法 (不带索引),以下方法是所有集合都具备
		1. add
			1. 添加元素,返回值boolean,成功为true
			2. list中元素可重复,故恒为true。set中元素不可重复,有可能为false
		2. clear
			1. 清空集合中的所有元素。集合容器本身不会改变,继续使用
		3. remove
			1. 移除集合中的单个实例(参数obj),移除成功返回true
		4. isEmpty
			1. 判断当前集合的元素个数是否为0
		5. contains
			1. 包含某个元素,如果有返回true,区分大小写
		6. size
			1. 获取大小
		7. toArray
			1. 集合中的元素,变成数组。集合存储的数据类型不确定,返回的数组只能是Object
*/
public class CollectionDemo {
    public static void main(String[] args) {
        // method01();  
		//如下把Collection改为ArrayList,则coll.set就会有ArrayList特有的方法,Collection没有
        Collection<String> coll = new ArrayList<>();//Collection是接口,不能实例化,所以只能创建子类对象
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");
        //将集合中所有的元素放到数组中,数组有索引
        Object[] objects = coll.toArray();
        for (int i = 0; i < objects.length; i++) {
            Object element = objects[i];
            System.out.println(element);
        }
    }

    private static void method01() {
   //如下行编译看左边: 父类无法调用子类特有的方法(可调用子类重写的方法)。所以把学习的方法限制于Collection集合内,不会用到ArrayList特有的方法
        Collection<String> coll = new ArrayList<>(); //ArrayList改为HashSet,则若加add两个张三则报错
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");

        boolean result = coll.add("马六"); //添加成功返回true,失败为false(基本没用)
        System.out.println(result);
        System.out.println(coll);//[张三,李四...]引用类型打印不是内存地址必然重写了toString方法

		//coll.clear(); //清空集合中所有的元素
		//System.out.println(coll); //[] 空篮子
		//System.out.println(coll == null); // false 篮子还在

        boolean result2 = coll.remove("马六"); //移除成功返回true(基本没用)
        System.out.println(result2);
        System.out.println(coll);
        System.out.println(coll.size()); // 3
        System.out.println(coll.isEmpty()); //false

        //如果集合中包含某个元素,就返回true
        boolean result3 = coll.contains("李四");
        System.out.println(result3);
    }
}

hasNext()返回true就调用next(),迭代器不断运行直到返回false。
在这里插入图片描述

package com.itheima04.iterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
*   遍历: 全部经历
*   迭代: 相同的动作不断执行。版本迭代:开发 -> 测试 -> 上线 1.0。开发 -> 测试 -> 上线 2.0 ...
* 
*   迭代器 : 不断循环的机器  iterator
*       1. boolean hasNext(); 判断是否有下一个元素,如果有,就返回true
*       2. 元素 next();  向后移动一位,并获取当前元素
* 
*   Collection方法,如下E是泛型返回值
*       Iterator<E> iterator() : 返回在此collection的元素上进行迭代的迭代器。
*   以前for循环基于索引,Collection没有索引,但有迭代器好用
*/
public class IteratorDemo {
    public static void main(String[] args) {
//        method01();
        Collection<String> coll = new ArrayList<>();
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");
        Iterator<String> it = coll.iterator();
        while(it.hasNext()){ //while取代下面的几次if循环
            String name = it.next();
            System.out.println(name);
        }
    }

    private static void method01() {
        Collection<String> coll = new ArrayList<>();
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");
        //获取collection集合的迭代器(相当于指针)
        Iterator<String> it = coll.iterator();
        //第一次迭代
        if (it.hasNext()){
            String name = it.next(); 
            System.out.println(name); //张三
        }
        //第二次迭代
        if (it.hasNext()){
            String name = it.next(); 
            System.out.println(name);//李四
        }
        //第三次迭代
        if (it.hasNext()){
            String name = it.next();
            System.out.println(name); //王五
        }
        //第四次迭代,it.hasNext()返回false
        if (it.hasNext()){
            String name = it.next();
            System.out.println(name);
        }
    }
}

s1地址先赋给s2,s2地址后又改变了。
在这里插入图片描述
如下相当于如上。
在这里插入图片描述

package com.itheima05.foreach;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
/*
*   增强for循环:
*       1. 前置
*           1. 普通for循环 : fori快捷键
*                for (int i = 0; i < 10; i++) {
                    list.set(i,"马六"); //可以修改
                }
            2. 语法糖(syntax sugar) : 原理相同,但是更为简练的语法

        2. for...each 快捷键array.for
            1. 集合 : 作为迭代器的语法糖
                collecition支持增强for循环
                语法:
                    for(元素类型 变量名 : 被遍历的集合){
                    }
                代价: 只适合用来查 (不适合用来修改集合内容)
            2. 数组 : 作为普通for循环的语法糖
*/
public class ForeachDemo {
    public static void main(String[] args) {
		// method01();
        int[] array = {1, 2, 3};
       /* for (int i = 0; i < array.length; i++) {
            int element = array[i];
            element = 10;
            System.out.println(element); //10
            
            array[i] = 10;
            System.out.println(array.toString()); //[I@14ae5a5
            System.out.println(Arrays.toString(array)); // [10, 2, 3],[10, 10, 3],[10, 10, 10]
        }
        System.out.println(Arrays.toString(array)); //[10, 10, 10] */

        for (int element : array) {        //1
            System.out.println(element);   //2
        }                                  //3                                           
        System.out.println(Arrays.toString(array)); //[1,2,3]
    }

    private static void method01() {
        Collection<String> coll = new ArrayList<>();
        coll.add("张三");
        coll.add("李四");
        coll.add("王五");
/*      Iterator<String> it = coll.iterator();
        while(it.hasNext()){
            String name = it.next(); //这行相当于get方法
            name = "马六";
            System.out.println(name); //马六 马六 马六
        }
        System.out.println(coll); //依然还是[张三,李四,王五] */ 
 
		//下面代码称为上面代码语法糖,匿名内部类也是语法糖,将定义类和创建对象合二为一。
        for(String name : coll){ //name会被coll里面的每一个元素循环赋值
            //System.out.println(name);
            name = "马六";
        }
        System.out.println(coll); //依然还是[张三,李四,王五]
    }
}

30.泛型:泛型类/接口/方法,运行看右边

在这里插入图片描述
如下不用泛型。
在这里插入图片描述
如下没有泛型存在安全问题,泛型就和overwrite注解一样,要不要无所谓,要就检查。
在这里插入图片描述
在这里插入图片描述

/*
*   1. 为什么要使用泛型?
*       1. 一般的需求, 一个集合都是用来同一种类型的数据 , 早期是没有泛型的, 意味着集合可以存任意引用类型
*       2. 这样就带来一个问题: 但凡需要用来子类特有方法, 集合类型为Object,都需要向下转型(强转)
*           -> 风险: 类型转换异常 (运行的时候)
*       3. 泛型: 给集合设置泛型, 那么这个集合就会在编译时候发现运行时期才发现的问题
*           先编译 后运行。泛型: 安全预警机制, 不是强制使用, 一般都会用
*
*   2. java里的泛型 是 伪泛型 :java泛型只存在编译时期(泛型擦除), 不存在运行时期
*/

在这里插入图片描述
如下ArrayList < Object > 类型是ArrayList < String > 的父类吗?不是,因为放动物(Object)笼子不能说是放狗(String)笼子的爸爸,本质都是笼子(ArrayList),但可以说动物是狗的父类。

package com.itheima06.generic;
import java.util.ArrayList;

public class GenericClassDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(100); 
        Integer integer = list.get(0); //0为int index        
		
		//如上add,get只能是Integer,原因如下:
        //对mc来说, 在创建对象时, T=String
        MyClass<String> mc = new MyClass<>();
        mc.add("abc");    
            
		//对mc2来说, 在创建对象时, T=Integer
        MyClass<Integer> mc2 = new MyClass<>();
        mc2.add(1);
    }
}
/*
*   泛型类: 1. class 类名<泛型变量>{ }
*           泛型变量 一般为单个大写字母
*         2. 泛型T 变量 , 只能赋值引用类型 String,Integer...
*         3. 创建对象的时候,对T 进行赋值
*         4. 某个泛型类对象 T赋值为String,那么这个对象中所有的T=String
*/    
class MyClass<T>{ 
    public void add(T str){ //str随便写 
    }
}
package com.itheima06.generic;
import java.util.ArrayList;
import java.util.Properties;
/*
*   泛型接口: interface 接口名<泛型变量>{  }
*   类实现泛型接口:1.继续向下传递泛型  2.直接对泛型进行赋值,不再向下传递
*/
public class GenericInterfaceDemo {
    public static void main(String[] args) {
        new Properties(); //ctrl+左键进去看源码 //Properties类是Properties文件和程序的中间桥梁,不论是从properties文件读信息还是写信息到properties文件都要经由Properties类
    }
}
interface MyInter<Q>{
    void add(Q q);
}
class MyClass01<Q> implements MyInter<Q>{ //继续向下传递泛型 //eg: ArrayList类
    @Override
    public void add(Q q) { //一个类实现接口必须重新给方法
    }
}
class MyClass02 implements MyInter<String>{ //Q赋值为String //eg: Property类
    @Override
    public void add(String s) {
    }
}
package com.itheima06.generic;
import java.util.ArrayList;
/*
*   泛型方法: 修饰符  <泛型变量> 返回值 方法名(参数列表){
*             }
*            1. 泛型变量在调用此方法的时候进行赋值
*            2. 泛型变量只可本方法内部
*   需求: 请你设计一个方法 既能接收list1,又能接收list2
*/
public class GenericMethodDemo {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();
        MyClass03.method00(list1); // P = String
        MyClass03.method00(list2); // P = Integer
    }
}
class MyClass03{
    public static <P>void method00(ArrayList<P> list){ //写成ArrayList<Object> list不行,蓝子间没继承关系。//ArrayList<Object>类型不是ArrayList<Integer>类型的父类,运行擦除泛型可以通过但在编译一开始就不能通过。
    }
}

31.泛型通配符:Fu,Zi,Sun是类/数据类型,extends

由于list是object,导致Fu fu报红。但不应该为Fu fu报红,应该addAll(list)报红,所以红色横线用泛型通配符
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.itheima06.generic;
import java.util.ArrayList;
/*
*   泛型通配符 : ?(表示一个范围)
*       1. ? extends Fu : Fu及其子类 (上限)
*       2. ? super  XX : XX及其父类 (下限)
*/
public class GenericSymbolDemo {
    public static void main(String[] args) {
        ArrayList<Fu> fuList = new ArrayList<>();
        ArrayList<Zi> ziList = new ArrayList<>();
        ArrayList<Sun> sunList = new ArrayList<>();
        ArrayList<Object> objList = new ArrayList<>();
        addAll(fuList);
        addAll(ziList);
        addAll(sunList);
       //addAll(objList); //编译不通过,放不进
    }
    /*
    *   方法: 内部有个内部有个bigList, 想要把参数(集合)中的所有元素都吸纳
    *           内部有个bigList  :  ArrayList<Fu> : 吸纳 : Fu 及其子类 的元素类型集合
    */
    private static void addAll(ArrayList<? extends Fu> list) {
        ArrayList<Fu> bigList = new ArrayList<>();
//        bigList.add(new Fu());
//        bigList.add(new Zi()); //向上转型
//        bigList.add(new Sun()); //向上转型
        for (Fu fu : list) {
            bigList.add(fu);
        }
    }
}
class Fu{
}
class Zi extends Fu{
}
class Sun extends Zi{
}
public class TestGeneric {	
	@Test
	public void test1(){		
		ArrayList list = new ArrayList();  //存本组学员的姓名,String对象
		list.add("张三");
		list.add("李四");
		list.add("王五");
		list.add(1);		
		for (Object object : list) { //使用时,不知道我这里面是String类型,统统按照Object
			//每次使用元素时,可能需要强转,很麻烦,好比每次打开瓶子,你需要闻一下
			String name = (String) object;//强转有风险
			System.out.println("名字的长度:" + name.length());
		}
	}
}
package com.atguigu.test02;
import java.util.ArrayList;
import org.junit.Test;
//泛型的好处:(1)安全(2)避免类型转换
public class TestGood {
	@Test
	public void test1(){
		ArrayList<String> list = new ArrayList<String>();
		list.add("张三");
		list.add("李四");
		list.add("王五");
//		list.add(1);//编译报错,因为我告诉ArrayList,我的元素类型是String,所以Integer对象进不去		
		//此时不需要用Object处理了,因为它知道里面的元素是String
		for (String name : list) {
			System.out.println("名字的字数:" +name.length());
		}
	}
}
package com.atguigu.test03;
import java.util.ArrayList;
import java.util.Iterator;
//把本组学员的姓名,存储到ArrayList集合中,并且指定泛型,并且要使用foreach和Iterator分别迭代,也要正确指定泛型
public class TestExer1 {
	public static void main(String[] args) {		
		ArrayList<String> list = new ArrayList<String>(); //姓名,泛型指定为String	
		list.add("杨洪强");
		list.add("苏海波");
		list.add("甄玉禄");
		
		System.out.println("foreach迭代");
		for (String name : list) {
			System.out.println(name);
		}
		
		System.out.println("Iterator迭代");		
		//Iterator<E>这个E代表你要迭代的集合的元素类型
		Iterator<String> iterator = list.iterator();
		while(iterator.hasNext()){
			String name = iterator.next();
			System.out.println(name);
		}
	}
}

在这里插入图片描述

package com.atguigu.test03;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
/*
 * 把本组学员的组长姓名作为key,组员的姓名作为value,多个组员用ArrayList装起来,
放到HashMap中,正确指定泛型,并且遍历。当如果出现泛型的嵌套,那么从外到内分析
 */
public class TestExer2 {
	public static void main(String[] args) {
//HashMap<K,V>:K代表key的类型,V代表value的类型
//组长姓名作为key,说明K是String。组员的姓名作为value,多个组员用ArrayList装起来,说明V是ArrayList类型
//因为ArrayList也是泛型类,ArrayList中装的是组员的姓名,所以是String类型
		HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();	
			
		ArrayList<String> group1 = new ArrayList<String>();
		group1.add("杨洪强");
		group1.add("苏海波");		
		map.put("杨洪强", group1); //组长:杨洪强
		
		ArrayList<String> group8 = new ArrayList<String>();
		group8.add("崔志恒");
		group8.add("甄玉禄");
		group8.add("杜冠军");		
		map.put("崔志恒", group8); //组长:崔志恒
		
		System.out.println("遍历所有的组长:");
		Set<String> keySet = map.keySet();
		for (String zuZhang : keySet) {
			System.out.println(zuZhang);
		}
		
		System.out.println("遍历所有的学员:");
		Collection<ArrayList<String>> values = map.values();
		for (ArrayList<String> group : values) {
			System.out.println(group);
		}
		
		System.out.println("遍历每一组的情况:");
		Set<Entry<String, ArrayList<String>>> entrySet = map.entrySet();
		for (Entry<String, ArrayList<String>> entry : entrySet) {
			System.out.println(entry);
		}
	}
}

在这里插入图片描述

32.内部类:.class文件,局部内部类(定义在一个方法里的类,只能当前方法内使用,其他方法不能使用)

package com.itheima05.innerclass;
/*
*   1. 定义在一个类A内部的另外一个类B, 那么A称之为外部类, B称之为内部类
*        内部类: 访问受限(要通过外部来访问内部)
* 
*   2. 成员内部类: 定义一个类成员位置的类 (少见)
*        1. 语法:外部类名.内部类名(声明) 变量名 = 外部类对象.new 内部类();
*        2. 编译:多了一个:OuterClass$InnerClass.class
* 
*   3. 
*/
public class InnerDemo { //有.class文件
    public static void main(String[] args) {
          class MethodClass{ //定义在main方法里称为局部内部类  
              int methodField;
              void method(){
              }
          }                   
        MethodClass mc = new MethodClass(); //上面的类
        mc.methodField = 1;
        mc.method();
    }

    public static void method01(){
        OuterClass oc = new OuterClass(); //main方法外面即下面的类
        oc.outerField = 1;  //属性
        oc.outerMethod();  //方法

        OuterClass.InnerClass ic = oc.new InnerClass(); //main方法外面即下面的类
        ic.innerFiled = 2;
        ic.innerMethod();	        
		// MethodClass mc = new MethodClass(); //错误,不能访问
    }
}

class OuterClass{ //外部类 //有.class文件
    int outerField; //成员
    void outerMethod(){ 
    }    
    class InnerClass{ //成员内部类 //有.class文件
        int innerFiled;
        void innerMethod(){
        }
    }
}

在这里插入图片描述

33.匿名内部类:=接口实现类,打印对象

在这里插入图片描述

package com.itheima05.innerclass;
/*
*     1. 匿名内部类 属于 方法/局部内部类 的一种
*     2. 匿名内部类 没有 类名
*     3. 目的 : 简化代码编写
*         new 父类/父接口() {  //class body 即类体
*              如果有抽象方法,必须重写
*          }
*        创建出来的是父类/父接口的子类对象
*        原理:  定义类+创建对象  合二为一
*/
public class InnerDemo02 {
    public static void main(String[] args) {
        Dog twoHa = new Dog(); //Animal twoHa = new Dog();也可以即多态
        voice(twoHa); //汪汪叫
        
//11111111111111111111111111111111111111111111111111111111111111111111111111111	
        //InnerDemo02$Wolf.class //第一个内部类有名字Wolf   
		class Wolf implements Animal{ //以前这类写在main方法外 //定义类
            @Override
            public void shout() {
                System.out.println("嗷嗷叫");
            }
        }
        Wolf greyTai = new Wolf();  //创建对象
        voice(greyTai); //嗷嗷叫
        
//111111111111111111111111111111111111111111111111111111111111111111111111111111111
        /*
        * 类名如dog,wolf其实在某些场景下一定都不重要,重要的类体(重写shout方法)
        * 语法: 多了个类体,但是把类名隐藏掉了叫匿名
        * 省略: 1. 以前:  定义类  然后 创建对象
        *       2. 现在: 创建对象+定义类  合二为一
        */
		// Animal a = new Animal(); //接口不能实例化,如下加方法体        
        // 父接口 变量 = 父接口子类对象 (向上转型)
        Animal a = new Animal(){ //多了一个大括号,InnerDemo02$1.class 第二个内部类也是第一个匿名内部类用1
            @Override
            public void shout() {
                System.out.println("嘎嘎叫"); 
            }
        };
        voice(a); //嘎嘎叫
        
//111111111111111111111111111111111111111111111111111111111111111111111111111111111
       // InnerDemo02$2.class  //第三个内部类也是第二个匿名内部类用2
       Animal b = new Dog(){ //这样写也可以,同上
            @Override
            public void shout() {
                System.out.println("呱呱叫");
            }
        };
        b.shout(); // 呱呱叫
        
//1111111111111111111111111111111111111111111111111111111111111111111111111111111
        //匿名内部类的匿名对象,最简洁  //InnerDemo02$3.class
       voice(new Animal() {
           @Override
           public void shout() {
               System.out.println("喵喵叫"); // 喵喵叫
           }
       });
    }	    
    private static void voice(Animal a) { //Animal接口, 接口不能实例化
        a.shout();
    }
}

//111111111111111111111111111111111111111111111111111111111111111111111111111
interface Animal{ //一般不用abstract Animal
    void shout(); //叫
}
class Dog implements Animal{ //多态要写,匿名内部类不用
    @Override
    public void shout() {
        System.out.println("汪汪叫");
    }
}

在这里插入图片描述
如下这个类对象就用一次,没必要取个名字,如果取名字还要单独的.java文件。
在这里插入图片描述

33.1 练习:接口的匿名内部类,没有子类名

子类特有方法不是子类重写方法,如下2解决。
在这里插入图片描述

package com.atguigu.test10;
/*
(1)声明一个抽象类Father,包含抽象方法:public abstract void method();
(2)用匿名内部类继承Father,并重写抽象方法,打印“hello 孩子"。并调用子类对象的method方法
*/
public class TestExer3 {
	public static void main(String[] args) {
		/*new Father(){
			public void method(){
				System.out.println("hello 孩子");
			}
		}.method();*/
		
		// 上下一样
		Father f = new Father(){
			public void method(){
				System.out.println("hello 孩子");
			}
		};
		f.method(); //hello 孩子
	}
}
abstract class Father{
	public abstract void method();
}

接口、抽象类可理解成是模糊不定的东西,要使用它的特质必须要实例化且实例化不能直接通过new。如下代码不同于普通的实例化对象,而是通过new一个实现接口的匿名内部类Runnable,使用{}具体实现接口。
在这里插入图片描述

package com.atguigu.test10;
import java.util.Arrays;
import java.util.Comparator;

public class TestExer4 {
	@SuppressWarnings("all")
	public static void main(String[] args) {
		//(2)在测试类中创建Employee数组
		Employee[] all = new Employee[3];
		all[0] = new Employee(2, "张三", 10000);
		all[1] = new Employee(1, "李四", 30000);
		all[2] = new Employee(3, "王五", 20000);	
 
	//(3)分别调用Arrays.sort(数组,Comparator),用匿名内部类实现按照编号升序排列,接口一定要重写方法
		Arrays.sort(all, new Comparator(){
			@Override
			public int compare(Object o1, Object o2) {
				Employee e1 = (Employee) o1;
				Employee e2 = (Employee) o2;
				return e1.getId() - e2.getId();
			}			
		});
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
 
  // (4)分别调用Arrays.sort(数组,Comparator),用匿名内部类实现按照薪资升序排列
		Arrays.sort(all , new Comparator() {
			@Override
			public int compare(Object o1, Object o2) {
				Employee e1 = (Employee) o1;
				Employee e2 = (Employee) o2;				
				if(e1.getSalary() > e2.getSalary()){
					return 1;
				}else if(e1.getSalary() < e2.getSalary()){
					return -1;
				}
				return 0;
			}
		});
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}
}

//(1)声明一个员工类Employee,有属性:编号、姓名、薪资
class Employee{
	private int id;
	private String name;
	private double salary;
	public Employee(int id, String name, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
	}
	public Employee() {
		super();
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
	}	
}

在这里插入图片描述

34.人工挑苹果:只一个接口CompareAble

在这里插入图片描述

package com.atguigu.homework.test04;

public class Apple {
	private double size;
	private String color;
	public Apple(double size, String color) {
		super();
		this.size = size;
		this.color = color;
	}
	public Apple() {
		super();
	}
	public double getSize() {
		return size;
	}
	public void setSize(double size) {
		this.size = size;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	@Override
	public String toString() {
		return size + "-" + color;
	}	
}
package com.atguigu.homework.test04;

public interface CompareAble {
	//定义默认方法compare,挑选较大苹果。
	public default void compare(Apple a1, Apple a2){
		if(a1.getSize() > a2.getSize()){
			System.out.println(a1);
		}else{
			System.out.println(a2); 
		}
	}
}
package com.atguigu.homework.test04;

public class CompareBig implements CompareAble{//CompareAble接口有默认方法就是挑较大苹果
}
package com.atguigu.homework.test04;

public class CompareColor implements CompareAble{ //挑红色
	public void compare(Apple a1, Apple a2){
		if("红色".equals(a1.getColor())){
			System.out.println(a1);
		}
		if("红色".equals(a2.getColor())){
			System.out.println(a2);
		}
	}
}
package com.atguigu.homework.test04;

public class Worker { //工人类挑选苹果
	public void pickApple(CompareAble c,Apple a1,Apple a2){
		c.compare(a1, a2);
	}
}
package com.atguigu.homework.test04;

public class Test04 {
	public static void main(String[] args) {		
		Apple a1 = new Apple(5.0, "青色");
		Apple a2 = new Apple(3.0, "红色");
		Worker w = new Worker();
		
		CompareBig cb = new CompareBig();
		w.pickApple(cb, a1, a2); //工人挑大苹果
			
		CompareColor cc = new CompareColor();
		w.pickApple(cc, a1, a2); //工人挑红苹果
	}
}

在这里插入图片描述
将上面改为匿名内部类实现接口来代替CompareBig和CompareColor就不用单独写两个实现类了。自己定义的,不是able to。如下第一行就是比较大小。
在这里插入图片描述

35.员工类接口:implements Comparator

package com.atguigu.test06.exer;
/*
(1)声明一个员工类Employee,有属性:编号、姓名、年龄、薪资
(2)让Employee员工类实现java.lang.Comparable接口,重写抽象方法,按照编号从小到大排序
*/
public class Employee implements Comparable{	
	private int id;
	private String name;
	private int age;
	private double salary;
	public Employee(int id, String name, int age, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
	}
	public Employee() {
		super();
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	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 double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
	}	
	//重写抽象方法,按照编号从小到大排序
	@Override
	public int compareTo(Object o) {
		return this.id - ((Employee)o).id;
	}	
}
package com.atguigu.test06.exer;
import java.util.Comparator;
/*
 * (4)声明SalaryComparator类,实现java.util.Comparator接口,
		重写抽象方法,按照薪资从高到低排序
 */
public class SalaryComparator implements Comparator {
	@Override
	public int compare(Object o1, Object o2) {
		Employee e1 = (Employee) o1;
		Employee e2 = (Employee) o2;		
		if(e1.getSalary() > e2.getSalary()){
			return -1;
		}else if(e1.getSalary() < e2.getSalary()){
			return 1;
		}
		return 0;
	}
}
package com.atguigu.test06.exer;
import java.util.Arrays;
/*	
(3)在测试类中创建Employee[]数组,调用java.util.Arrays的sort方法进行排序,遍历结果。
	 用SalaryComparator对象重新对Employee[]数组进行排序,遍历结果。
*/
public class TestExer2 {
	public static void main(String[] args) {
		Employee[] all = new Employee[3];
		all[0] = new Employee(2, "王小二", 22, 20000);
		all[1] = new Employee(3, "张三", 23, 13000);
		all[2] = new Employee(1, "李四", 24, 8000);
				
		//调用java.util.Arrays的sort方法进行排序,遍历结果
		Arrays.sort(all);		
		for (int i = 0; i < all.length; i++) { //按编号id从小到大排序
			System.out.println(all[i]);
		}
		System.out.println("-----------------------------");
				
		//再次调用java.util.Arrays的sort方法进行排序,遍历结果
		Arrays.sort(all, new SalaryComparator());
		for (int i = 0; i < all.length; i++) {
			System.out.println(all[i]);
		}
	}
}

在这里插入图片描述

36.斗地主:双重for,Collections.shuffle,list.get(i)

在这里插入图片描述

package com.itheima00.poker;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class PokerDemo {
    public static void main(String[] args) {
        //1. 准备一副牌
        String[] colors = {"♠","♥","♣","♦"};
        String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        ArrayList<String> list = new ArrayList<>(); //集合收集牌
        for (String color : colors) {
            for (String number : numbers) {
                String poker = color + number;
//                System.out.println(poker);
                list.add(poker);
            }
        }
        list.add("小☺");
        list.add("大☺");
        //System.out.println(list);

        //2. 洗牌: 随机产生次数10 , 再随机交换两个元素位置
        Collections.shuffle(list); // Arrays / Collections / Objects 工具类 : 静态方法
        //System.out.println(list);

        //3. 发牌:模拟三个玩家+底牌
        ArrayList<String> p1 = new ArrayList<>();
        ArrayList<String> p2 = new ArrayList<>();
        ArrayList<String> p3 = new ArrayList<>();
        ArrayList<String> dp = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) { //遍历这副牌,不能用增强for循环,因为增强for循环无索引。第0张发给谁,要用索引取模。所以用普通for循环。	
            String poker = list.get(i); //取当前牌,第一次取就是第0张牌
            int mod = i % 3;
            if(i < 3){ //先发三张底牌,不然最后会忘记留底牌
                dp.add(poker);
            }else if(mod == 0){
                p1.add(poker);
            }else if(mod == 1){
                p2.add(poker);
            }else if(mod == 2){
                p3.add(poker);
            }
        }
        
        //4.看牌
        lookPoker(p1); 
        lookPoker(p2);
        lookPoker(p3);
        lookPoker(dp);
    }
    private static void lookPoker(ArrayList<String> list) {
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String poker = it.next();
            System.out.print(poker+"\t"); //同一个人不换行打印
        }
        System.out.println(); //不同人换行
    }
}

1.堆栈/队列/数组/链表:数据结构即计算机组织管理数据的方式,堆栈指的是内存图中的栈,不是堆

在这里插入图片描述
在这里插入图片描述
如下查询慢:知道张三在哪,不能马上知道王五在哪,挨个查。如下增删虽然不用整个动(如删除李四,只需要将箭头指向王五就行),但是还是要先查找到再删除,效率还是慢。但是直接删除张三或马六头尾元素快。
在这里插入图片描述

2.红黑树:二查,二查平,二查平1倍

二叉树(二):每个节点最多两个子节点。查找树(查):左小右大(二分法)。平衡树(平):左右尽量相等(一边的节点层次不会超过另一边的两倍)。

二叉搜索树BST(二查):插入或查询一节点时,树的每一行只需要和这一行的一个节点比较(因为左小右大),复杂度完全依赖树深度。树的行数即高度=logn【n为节点总数,2的树行数次方为n】,BST读和写的复杂度都为logn。

有序数组:查找时用二分查找法(和BST像),时间复杂度也为logn。有序数组查询最差情况logn,而当BST为单边时(最差情况),BST查询和插入都为o(n)。为什么很多情况下用BST,而不是有序数组二分查找?因为有序数组查找用二分查找logn,但是插入(不是查)要移动,插入时间复杂度为o(n)。
在这里插入图片描述
BST很少在语言内部数据结构存储里用(因为下面直线情况),自平衡二叉树AVL(二查平)BST(二查)的继承优化:左子树和右子树都是平衡二叉树,而且左子树和右子树深度之差绝对值不会超过1(左旋和右旋),AVL读和写的复杂度最差情况都为O(logn)。
在这里插入图片描述
AVL平衡左右子树相差1,这个条件很苛刻,导致很多情况下都不满足这个平衡条件,需要旋转变换,变换的话需要浪费时间。红黑树(二平查1倍)平衡条件更加宽松些左右深度差一倍即> = 节点数相同,< = 节点数差一倍(因为红节点的子节点必须为黑即黑红相间)。叶子节点(最后一个)和null节点都为黑节点

这样宽松条件导致我们在插入节点时候变化更少的,所以红黑树写的性能会高一些,所以treemap/hashmap底层采用红黑树(BST会变直线,AVL左右只能差1)。
在这里插入图片描述
如下是红黑树的插入变色流程:最上面根节点必须为黑,插入节点(为叶子节点)必为红节点(看插入节点的父节点和父节点的兄弟节点即叔节点)。null节点算叶子节点即黑节点,当前插入的003是爷爷节点001的右右。
在这里插入图片描述
如下左旋+变色。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
先序(先根):根左右
中序:投影
后序左右根(从下到上)
在这里插入图片描述

3.List子接口:集合,IndexOutOfBoundsException

在这里插入图片描述

package com.itheima01.list;
import java.util.ArrayList;
import java.util.List;
/*
    Collection子接口:List
	1. List的特点:重索序
		1. 有先后顺序:元素存储的顺序和取出的顺序相同
		2. 具有整数索引,就是下标
		3. 允许重复元素
	 
	2. List的方法(带索引)(List特有的,共有的在Collection讲过)
		1. add(int index, E element) :往索引位置添加一个元素
			1. Java中的 三个越界异常
			 	1. IndexOutOfBoundsException  集合
			 	2. ArrayIndexOutOfBoundsException  数组
			 	3. StringIndexOutOfBoundsException 字符串越界
		2. get(int index):获取指定索引的元素
		3. remove(int index):移除指定索引的元素
		4. set(int index, E element) :修改指定索引的元素值
*/
public class ListDemo {
    public static void main(String[] args) {
//        add();
        List<String> list = new ArrayList<>();
        list.add("周楠");
        list.add("王凤枝");
        list.add("王凯");
        String s = list.get(2);
        System.out.println(s); //王凯
        
        list.remove(2);
        System.out.println(list); //[周楠, 王凤枝]
        
        list.set(1,"昌老师");
        System.out.println(list); //[周楠, 昌老师]
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111
    private static void add() {
        List<String> list = new ArrayList<>();
        list.add("周楠");
        list.add("王凤枝");
        list.add("王凯");
        /*
            add(int index, element)
                往指定索引位添加元素
                index = list.size()
                IndexOutOfBoundsException: : 索引越界异常
        */
        list.add(3,"田锁"); //不越界,4越界
        System.out.println(list);

        String[] array = {};
 //System.out.println(array[0]); //ArrayIndexOutOfBoundsException : 数组索引越界

        String str = "abc";  // 字符串底层也是数组
 // char c = str.charAt(3); //索引0,1,2 
 // System.out.println(c);  //StringIndexOutOfBoundsException:字符串索引越界
    }
}

4.ArrayList的扩容原理:Stringbuild默认长度=16,扩容2倍

ArrayList底层是存Object数组,扩容新建一个长度为原来1.5倍新数组(空)。
在这里插入图片描述
如下10进制的4就是2进制的0100(8421),3/2=1,ArrayList.java源码中出现左右移(二进制右移一位相当于十进制/2)
在这里插入图片描述

package com.itheima01.list;
import java.util.ArrayList;
/*
*   ArrayList: 数组
*       1. 最常用: 适合 查询需求比较多的场景
*       2. 原理: ArrayList扩容原理
*               ArrayList底层是数组,数组长度不可变,为什么ArrayList又可变呢? 因为数据迁移
*/
public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("xx");
        System.out.println(3 >> 1); // 1 //除2取整
        System.out.println(4 >> 1); // 2
        System.out.println(10 >> 1); // 5
        System.out.println(3 << 2); //12 //3*2*2,左移2位
    }
}

1. ArrayList底层是数组,默认长度为10,扩容系数1.5即下次15,ArrayList查询复杂度为o(1)。LinkedList底层双向链表,好处不用进行扩容,一直往后追加,坏处是要找第n个元素时间复杂度是o(n)。JDK -> JVM -> glibc(系统调用的封装)->Linux内核

2. HashMap底层也是数组,数组大小必须是2的幂次方倍【确保数组中的每一个位置发生hash冲突的概率相同】。LinkedHashMap底层和HashMap一样,只不过每个元素有一个指针指向下一个插入的元素,有序了。TreeMap底层红黑树实现,特点是按照key进行排序。HashTable线程安全(读写整个数组结构加了syn修饰即加了锁)(HashMap线程不安全,两者底层存储结构一样)。锁住整个结构代价大,所以出现了concurrent HashMap,只锁住数组的一个桶。HashSet将HashMap的value设为null。
在这里插入图片描述

5.LinkedList:push堆栈

package com.itheima01.list;
import java.util.LinkedList;
/*
    LinkedList特点
		1. 底层数据结构: 双向链表
		2. 查询速度慢,增删快(增删需求多而且增删首尾用LinkedList)
 		3. 特有方法(不能使用多态,父类不能调子类特有方法)
 			1. addFirst 元素添加在链表开头
	 		2. addLast(add相同) 元素添加在链表结尾
	 		3. getFirst 获取链表开头
	 		4. getLast  获取链表结尾
	 		5. removeFirst 移除并返回链表开头
	 	    6. removeLast 移除并返回链表结尾
            //下面两个不需要掌握
	 	    7. pop 从此列表所表示的堆栈处弹出一个元素(最顶部元素弹出,removeFirst)
	 		8. push 将元素推入此列表所表示的堆栈(元素存储到集合顶部,addFirst)
*/
public class LinkedListDemo {
    public static void main(String[] args) {
//        method01();
        LinkedList<String> list = new LinkedList<>();
        list.add("张三"); // 是链表,不是按堆栈结构添加元素
        list.add("李四");
        list.add("王五");
        
        // 链表 -> 堆栈 ,张三在栈顶
//        String pop = list.pop(); // 弹栈: 栈顶元素()
//        String removeFirst = list.removeFirst();//效果同上
//        System.out.println(pop);
        list.push("王二"); //栈顶添加,效果等同于add
        System.out.println(list);
    }

    private static void method01() {
        LinkedList<String> list = new LinkedList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.addFirst("王二");
        list.addLast("马六");
        System.out.println(list);
        
        String first = list.getFirst();
        String last = list.getLast();
        System.out.println(first + ","  + last);
        System.out.println(list);
        
        list.removeFirst();
        list.removeLast();
        System.out.println(list);
    }
}

6.set子接口:单例=keySet

package com.itheima02.set;
import java.util.HashSet;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("张三");
        set.add("李四");
        boolean result = set.add("王五");
        System.out.println(result); //true 
        
        boolean result2 = set.add("王五");
        System.out.println(result2); //false //元素不可重复
        System.out.println(set);//[李四,张三,王五] //存取不保证顺序
    }
}

7.Object类的hashcode方法:对象的真正的内存地址(无限种)->哈希码 (43亿不到的可能)。极端下多个明文 -> 同一密文 (哈希碰撞)。打印对象,.toString(),.hashCode()

package com.itheima03.hash;
/*
*    Object类有一个方法: int hashCode() : 返回该对象的哈希码值。
*               1. 原理: 将对象的真正的内存地址(明文) 进行 哈希算法 加密之后产生的 哈希码值(密文)
*               2. 加密 :
*                       明文 : 大家都看的懂东西                          I love you
*                       密文 : 明文经过加密算法变成密文                   J mpwf zpv
*                    加密算法: 数学  (凯撒加密: 字母按字母表右移动一位)
*    破解: 频率分析法 (e i -> d h),截获大量数据进行大数据分析e,i出现频率最高,密文中出现最多的是d,h
*
*                    哈希算法: 公开
*                        基本保证  一个明文  -> 一个密文   不同明文不同的密文
*                        告诉你算法,告诉你密文, 算不出明文
*                       
*              3. 源码: public native int hashCode();  本地方法
*                       native(本地关键字) 修饰的方法没有java方法体 (方法实现在JVM底层, 用C语言写的)
*                       返回值 int (43亿不到的可能)
*/
public class HashcodeDemo {
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println(p); //com.itheima03.hash.Person@14ae5a5
        // return getClass().getName() + "@" + Integer.toHexString(hashCode());
        System.out.println(p.toString());//com.itheima03.hash.Person@14ae5a5    
               
        // 上面两个打印结果都一样       
        // 如下内存地址: 16进制哈希码值14ae5a5 和下面10进制相等
        System.out.println(p.hashCode()); // 10进制: 21685669
    }
}
class Person{
}

8.String类的hashcode方法:a97,碰撞

String s1 = “abc”,如下h就是hash值(只看最后一个h),b是98,c是99。
在这里插入图片描述

package com.itheima03.hash;
// String类重写了Object的hashcode方法 (31算法)
public class StringHashCodeDemo {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "acD";
        String s3 = "重地";
        String s4 = "通话";
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354 //和上面哈希碰撞
        System.out.println(s3.hashCode()); //1179395
        System.out.println(s4.hashCode()); //1179395
    }
}

9.哈希表(HashSet)原理:元素不重复

hashcode(密文)为HashSet(HashSet底层数据结构是hash表)做铺垫。如下三个abc字符串都为96354。问题:HashSet如何判定这个元素是否跟已存在的元素是重复即如下[重地,通话,abc,acD]?Set不存重复元素。S3因为是new出来的,和S1,S2明文即真正的内存地址不一样。

下面S1,S4,S5,S6都是不重复元素。竖:暗文或暗文%16同(因为数组长度为16),equal不一样。横:明文和暗文和equal都不一样。HashSet是效率最高的set且元素不重复,同一链表(竖)hashcode一样,但是链表如果太长查询慢,所以假如同一hash值(hashcode)碰撞了8次,链表重构为红黑树

同一链表上都hash碰撞,数组的第一个位置余数=0,第二个位置余数=1。。。16的容量为什么到16*0.75=12就扩容了?再哈希rehash(余数重新算)这段时间内,16没满,我还有的用,如果rehash非常快就不用提前。
在这里插入图片描述

package com.itheima02.set;
import java.util.HashSet;
import java.util.Objects;
/*
*  HashSet: 判定重复元素:(明文地址【内】,hash值【外】,equals【名字】)。
*   内同-》重复不插,     内不同 外不同 默认e不同-》横插,       内不同 外同 e不同-》竖插 
*
*  person类父类的Object: 1. hashcode:明文内存地址加密得到密文hash值
*(不同明文产生不同密文,刘亦菲明文即两个内存地址不一样,密文hash值基本不会相同,万一碰撞了,还有下面2进 行保障)
*           2. equals   == 比较真正内存地址
*
*      需求: 两个对象就算地址不同, 但是所有属性一一相同, 就认为是同一元素
*      解决: 重写hashcode和equals方法 -> 类中的所有属性,重写规范见文章:https://blog.csdn.net/weixin_43435675/article/details/112604089
*/
public class HashSetDemo02 {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        set.add(new Person("高圆圆",18));
        set.add(new Person("刘亦菲",19));
        set.add(new Person("刘亦菲",19));//Person类继承Object类,new新地址
        System.out.println(set); 
    }
}
class Person{
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) { //alt+insert选equals()and hashCode() //每个属性一一比对
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false; 
        Person person = (Person) o;  //o是外部传入,转成person
        return age == person.age &&
                Objects.equals(name, person.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age); //工具类Objects.java中hash方法中hashCode方法就是31算法,也是逐一遍历
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

没有重写Person类的hashcode和equals方法。
在这里插入图片描述
如下重写…如下就是hash表的应用:元素不重复,效率高。
在这里插入图片描述

10.linkedHashset和Hashset区别:A a = new A(){},coll.iterator().hasNext()

package com.itheima00.question;
import java.util.HashSet;
import java.util.LinkedHashSet;
/*
*   Set: 不保证 存入和取出顺序一致
*       HashSet : 无序
*       LinkedHashSet : 多个另一个链表, 来记录存入的顺序,有序即取出有序,所以效率变低(少用)
*/
public class Demo01 {
    public static void main(String[] args) {
        HashSet<String> set = new LinkedHashSet<>(); //向上转型
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("马六");
        System.out.println(set); //打印出有序的,LinkedHashSet不同于HashSet 
    }
}
package com.itheima00.question;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo02 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<String>(); //Collection是接口
        coll.add("张三");
        coll.add("张三2");
        coll.add("张三3");                
       // Iterator接口类型 变量 = 其实现类对象 (多态的向上转型)
       /* Iterator<String> it = coll.iterator(); //Collection即coll是接口,接口调用方法执行子类ArrayList重写的iterator()
        while(it.hasNext()){
            String name = it.next();
            System.out.println(name); //张三 张三2 张三3
        }*/

//        while(coll.iterator().hasNext()){ //不能这样把it换了链式编程,原因如下图
//            String name = coll.iterator().next();
//            System.out.println(name);
//        }
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    public static void method01(){
        MyClass mc = new MyClass();
        A a = mc.test(); //右边返回必然是A接口实现类对象即向上转型,不需要new        
        //上行等同于Iterator<String> it = coll.iterator(); 不一定需要看到new  
             
        A a2 = new A() { //java中对象不一定看到new才放心   //new一个实现接口的匿名内部类A,使用{}具体实现接口         
            @Override
            public void show() {
            }
        } ;
    }
}
interface A{
    void show();
}
class MyClass{
    public A test(){ //返回A接口,不写void
//        A a = new A(){}; //匿名内部类
//        return a;

        return new A() { //下面等同于上面两行,return A接口的子类对象
            @Override
            public void show() {
            }
        };
    }
}

在这里插入图片描述

11.Map:Map和Collection是并列关系,Map.Entry < Integer,String > 是数据类型

在这里插入图片描述

package com.itheima01.map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/*
    Map中的方法
	1. Map<K,V> <泛型>: K 表示作为键的类型,V表示值的类型
		2. put: 存储键值对
			1. 键值对存储到集合中 V put (K,V)
			2. 如果存储了相同的键,覆盖原有的值
			3. 返回值:一般返回null,如果存储了重复的键,返回被覆盖之前的值
		3. get:通过键,取出键对应的值
			1. V get(K),传递键,返回对应的值
		 	2. 如果集合中没有这个键,返回null
		4. remove:移除键值对
		 	1. V remove(K),传递键,移除这个键值对
		 	2. 返回值:移除之前的值(无此键,则返回null)
		5. keySet: 将集合中所有的键,存储到Set集合中
		6. entrySet:获取到Map集合中所有的键值对存入Set接中
		7. size:获取map集合的大小
*   Map:
*       1. key不可以重复
*       2. value可以重复
*       如果key存在,那么新value覆盖旧value
*/
public class MapDemo {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(2,"李四");
        map.put(3,"王五");
        map.put(4,"王五");
        map.put(3,"马六"); //覆盖王五
        System.out.println(map);//{1=张三,2=李四,3=马六,4=王五}
        String name = map.get(5); //null,不是越界异常,无索引
        String name = map.get(3); //从key获取value
        System.out.println(name);//马六
        //根据key删除key-value
        map.remove(3);
        System.out.println(map);
        System.out.println(map.size()); //3,几个k
    }
}

如下key不可重复,所以放到set集合(单例)。如下两种遍历方式都涉及set:
在这里插入图片描述

package com.itheima01.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
public class MapLoopDemo01 { //loop循环
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(2,"李四");
        map.put(3,"王五");        
        Set<Integer> keySet = map.keySet();  //1.把key这一列取出来放到set集合中        
        for (Integer key : keySet) {  //2.遍历这个set集合,取出每个key。keySet.for回车            
            String value = map.get(key);  //3. 根据key获取value
            System.out.println(key + "->" + value);
        }
    }
}

在这里插入图片描述

package com.itheima01.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapLoopDemo02 {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"张三");
        map.put(2,"李四");
        map.put(3,"王五");
        Set<Map.Entry<Integer,String>> entrySet = map.entrySet(); // 1. 把map转化成 Set<Entry> set
        for(Map.Entry<Integer,String> entry : entrySet){ // 2. 遍历这样的set, 取出每个entry
   //Entry是Map的内部接口,Map有很多Entry,Entry相当于Map属性一样。Map.是接口名直接调用
   //如果import java.util.Map.Entry,则Map.Entry可换成Entry            
            Integer key = entry.getKey(); //3. 从这个键值对中,取键,再取值
            String value = entry.getValue();
            System.out.println(key + "--" + value);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

package com.itheima03.impl;
import java.util.*;
/*
*   HashMap是最常用的map实现类,因为快。
*       1. key不可以重复,但是value可以重复
*       2. key如何判定重复? 先判断hashcode ,再判断equals
*           Object: hashcode 和 equals 跟对象真正地址有关
*           重写了hashcode 和 equals,张三山东 覆盖 张三山西  新覆盖旧
*/
public class HashMapDemo {
    public static void main(String[] args) {
//        method01();
//        method02(); //较method01交换了k和v

        new LinkedHashSet<>(); //点进源码,底层是LinkedHashMap
        new TreeSet<>(); //TreeMap
        new HashSet<>(); //HashMap
        
        //如下有序存取
        LinkedHashMap<Person,String> map = new LinkedHashMap<>();
        map.put(new Person("张三",18),"山西");
        map.put(new Person("吴彦祖",20),"福州");
        map.put(new Person("李四",19),"广东");
//        map.put(new Person("张三",18),"山东");
        Set<Person> keySet = map.keySet();
        for (Person key : keySet) {
            String value = map.get(key);
            System.out.println(key + "---" + value);
        }
    }

    private static void method02() {
        HashMap<Person,String> map = new HashMap<>();
        map.put(new Person("张三",18),"山西");  //key=Person 自定义类型
        map.put(new Person("吴彦祖",20),"福州");
        map.put(new Person("李四",19),"广东");
        map.put(new Person("张三",18),"山东"); //new出来地址不同
        Set<Person> keySet = map.keySet();
        for (Person key : keySet) {
            String value = map.get(key);
            System.out.println(key + "---" + value);
        }
       // HashSet<Object> set = new HashSet<>(); //点进HashSet看源码
//HashSet【collection接口】的底层是HashMap【Map接口】 ,只不过hashset只使用了HashMap key这一列,value这一列不用
    }

    private static void method01() {        
        HashMap<String, Person> map = new HashMap<>();
        map.put("1号",new Person("张三",18)); //value=Person 自定义类型
        map.put("2号",new Person("李四",19));
        map.put("3号",new Person("李四",19));
        map.put("1号",new Person("王五",20)); 
        //System.out.println(map);
        Set<Map.Entry<String,Person>> entrySet =  map.entrySet();
        for (Map.Entry<String, Person> entry : entrySet) {
            String key = entry.getKey();
            Person value = entry.getValue();
            System.out.println(key + "-" + value);
        }
    }
}

class Person{
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

在这里插入图片描述
在这里插入图片描述
如下吴彦祖应该在第二个,存取无序,解决:HashMap换成LinkedHashMap。
在这里插入图片描述

12.内部接口:除了Inner访问受限于Outer,这两各自独立

package com.itheima02.inner;
import java.lang.reflect.Field;
import java.util.Date;
import com.itheima02.inner.Outer.Inner;
/*
* inner class : 访问受限, 受限于外部类
* 有两个包是不用导入:1. java.lang (String,Object)
*                     2. 当前类所在的包
* 1和2的子包都要导(如内部接口就在当前包的子包下)
*/
public class InnerDemo {
    public static void main(String[] args) {
//        new Date()
        new String("");
        new Object();
//        new Field(); //java.lang包的子包,要导包
    }
}

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
interface Outer{
    //public static final //因为Outer是接口,所以不能实例化,只能接口.。所以final让I变为常量,static让I可用接口名.直接调用
    int I = 1;
    //public abstract
    void outerMethod();
    
    //new外部类对象不需要new内部类对象,同理实现Outer接口不需要实现Inner接口
    //public static //外部接口不能创建实例来调用,所以接口名调用,所以静态。上面Map.Entry即外接口.内接口(Entry是Map的内接口)
    interface Inner{ 
        void innerMethod();
    }
}
class A implements Outer{ //不需要实现Inner
    @Override
    public void outerMethod() {
    }
}
class B implements Outer.Inner{
    @Override
    public void innerMethod() {
    }
}
class C implements Outer,Inner{//上面导过包了,Inner不用写成Outer.Inner
    @Override
    public void outerMethod() {
    }
    @Override
    public void innerMethod() {
    }
}

13.统计字符出现个数:.containsKey(.charAt)

统计字符串中:大小写字母及数字字符个数:https://blog.csdn.net/weixin_43435675/article/details/107434867

package com.itheima03.impl;
import java.util.HashMap;
/*
*  需求: 计算一个字符串中每个字符出现次数。
*       0. 弄一个Map : 记录 字符=次数 (就像画正字选票)
*                          char   int
*       1. 遍历这个字符串,取出每个字符
*       2. 判断Map中是否存在这个字符-> boolean containsKey(Object key)  如果此映射包含指定键的映射关系,则返回 true。
*       3. 有: 在对应的次数+1 。没有 : 字符char=1 存进去
*/
public class CountDemo {
    public static void main(String[] args) {
        String str = "abcaba";         
        HashMap<Character, Integer> map = new HashMap<>();//泛型不接收基本类型,所以char写成Character,int的包装类Integer
        for(int i=0; i<str.length();i++){
            char c = str.charAt(i); //相应索引访问到相应字符
            boolean result = map.containsKey(c);  //一开始map为空,下面依次写进去
                                
            if(result){ // 存在,次数value+1
                Integer value = map.get(c); //c是key即char
//                value = value + 1;
//                map.put(c,value);

//                value++;
//                map.put(c,value);

//                int count = ++value;
//                map.put(c,count);
                map.put(c,++value); //不能写成map.put(c,value++);
            }else{ // 不存在, 存入c=1
                map.put(c,1);
            }
        }
        System.out.println(map);
    }
}

在这里插入图片描述

14.斗地主:list.addAll(set)

package com.itheima04.Poker;
import java.util.ArrayList;
import java.util.Collections;
// 写一个规则: 2 > A > K > Q > J  ...(不行,组合方式太多2也要>K)  //上次写的没有排序 //黑红梅方
public class SortDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>(); //重索序
        list.add(3);
        list.add(5);
        list.add(4);
        list.add(1);
        list.add(2);
        System.out.println(list); //[3,5,4,1,2],有序
        Collections.sort(list);
        System.out.println(list);//[1,2,3,4,5]
    }
}

15发给第一个,13发给第二个。。。
在这里插入图片描述

package com.itheima04.Poker;
import java.util.*;

class PokerDemo {
    public static void main(String[] args) {        
        HashMap<Integer, String> map = new HashMap<>(); //key=编号, value=牌面
        String[] colors = {"♠","♥","♣","♦"};
        String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        int index=0;
        for (String number : numbers) {//数字写外面,外一次内一周,数字3和4种花拼接,并index标号依次从0对应到3,好按标号排序。            
            for (String color : colors) {
                String poker = color + number;
                map.put(index,poker);
                index++;
            }
        }
//        System.out.println(map); //{0=黑桃3,1=红心3,2=梅花3,...}
        map.put(52,"小☺");
        map.put(53,"大☺");        
        Set<Integer> set = map.keySet(); //0-53
        ArrayList<Integer> list = new ArrayList<>();
        list.addAll(set); //将set集合中每个元素都放进list中
        //下面等同于上面 
        /*for (int i = 0; i < 54; i++) {  //0-53编号放进去
            list.add(i);
        }*/
        
        //洗牌
        Collections.shuffle(list); //只能洗list集合
        //发牌
        ArrayList<Integer> p1 = new ArrayList<>();
        ArrayList<Integer> p2 = new ArrayList<>();
        ArrayList<Integer> p3 = new ArrayList<>();
        ArrayList<Integer> dp = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) { //list里全是编号
            Integer number = list.get(i);
            int mod = i % 3;
            if(i < 3){
                dp.add(number);
            }else if(mod == 1){
                p1.add(number);
            }else if(mod == 2){
                p2.add(number);
            }else if(mod == 0){
                p3.add(number);
            }
        }
        //排序(Integer:从小到大)
        Collections.sort(p1);
        Collections.sort(p2);
        Collections.sort(p3);
        Collections.sort(dp);
//        lookPoker(map,p1); //因为list即p里都是编号,所以还需要map
//        lookPoker(map,p2);
//        lookPoker(map,p3);
//        lookPoker(map,dp);
        lookPoker(map,p1,p2,p3,dp);
    }
    
    private static void lookPoker(HashMap<Integer, String> map, ArrayList<Integer>... lists) { //lists为数组名
        for (ArrayList<Integer> list : lists) {
            for (Integer number : list) {               
                String poker = map.get(number);  //从map中根据number 取出 poker
                System.out.print(poker + "\t");
            }
            System.out.println();
        }
    }
//    private static void lookPoker(HashMap<Integer,String> map,ArrayList<Integer> list){
//        for(Integer number : list){
//            String poker = map.get(number);
//            System.out.print(poker+"\t");
//        }
//        System.out.println();
//    }
}

在这里插入图片描述

15.Collections类和TreeSet:return o1-o2是升序

package com.itheima05.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
  Arrays数组工具类, Objects对象工具类(命名规则最后+s)
  - java.utils.Collections是集合工具类,用来对集合进行操作。 常用方法如下: 
- public static void shuffle(List<?> list):打乱集合顺序。
- public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
- public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。
*/
public class CollectionsDemo01 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>(); //Integer源码实现了Comparable接口        
        Collections.addAll(list,5,3,2,4,1);  //System.out.println(list); //[3,4,5,1,2]
  //      Collections.sort(list); // 默认: 升序
  

// 如下第二个参数类型是Comparator接口,必须传入接口实现类对象:new Comparator...后面全是匿名内部类
        Collections.sort(list, new Comparator<Integer>() { // 自定义升降序规则 , 任何排序都是两两比较    
            @Override
            public int compare(Integer o1, Integer o2) {
//                return o1 - o2;//升序: 从小到大
                return o2 - o1;//降序: 从大到小
            }
        });
        System.out.println(list);
    }
}

15.1 自定义MyCollections类来模拟完成addAll()和sort()方法

package com.itheima05.collections;
import java.util.ArrayList;
import java.util.Comparator;

public class MyCollections { 
    // 1. addAll方法
    public static void addAll(ArrayList<Integer> list, Integer... args){
        for (Integer arg : args) {
            list.add(arg);
        }
    }
    
    //2. sort方法: 这里采用冒泡排序。collections底层实际是Timsort排序。
   //注意: 第二个参数是接口,必须传入接口实现类(这将形成多态: 父接口引用调用方法执行的是子类重写方法)
    public static void sort(ArrayList<Integer> list, Comparator<Integer> comparator) {
        int temp;
        for (int i = 0; i < list.size() - 1; i++) {
            for (int j = 0; j < list.size() - i - 1; j++) {                
                int result = comparator.compare(list.get(j + 1), list.get(j));//j+1和j相邻比较,父类接口调用方法执行子类重写的方法即MyCollections.sort(list, new Comparator<Integer>() {子类重写的方法})。
                if(result < 0){ //子类重写方法中rerurn o1-o2保证result<0即o1后小,rerurn o2-o1保证result<0即o1后大。
                    temp = list.get(j);  //交换
                    list.set(j, list.get(j + 1));
                    list.set(j+1,temp);
                }
            }
        }
    }
}
package com.itheima05.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class CollectionsDemo02 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,5,3,2,4,1);
        MyCollections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        System.out.println(list);
    }
}
package com.itheima05.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.TreeSet;

public class CollectionsDemo03 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>(); //ArrayList底层就是数组,数组和集合差不多。
        list.add(new Student("张三",20));
        list.add(new Student("李四",18));
        list.add(new Student("王五",22));
      /* Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.age - o2.age; //按年龄升序
            }
        });
        System.out.println(list);*/

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
    // sort(list) : 这个方法要求集合元素类型需要实现 Comparable接口 (Integer已实现,自定义类型必须手动实现)
//      Collections.sort(list); //如果就写class Student不实现Comparable接口,这行会报错
//      System.out.println(list);

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111           
        TreeSet<Student> set = new TreeSet<>(); //TreeSet判定元素重复的原理:compare方法 : 两数相减=0(不是hashcode和equals)    
        //TreeSet底层红黑树(红黑树就是排序,左小右大),和哈希表无关,和Collections.sort一样必须实现Comparable接口
        //Set重点是hashset,TreeSet底层和比较器完全一样,TreeSet具备排序功能但效率不如hashset。TreeMap的key和TreeSet底层一样
        set.add(new Student("张三",20));
        set.add(new Student("李四",18));
        set.add(new Student("王五",22));
        set.add(new Student("马六",22)); //添不进去,因为compareTo比较的是age,不重复
        System.out.println(set);
    }
}

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
class Student implements Comparable<Student>{
    String name;
    int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }   
    @Override
    public int compareTo(Student o) {
        return this.age - o.age; //升序,// this = o1,o = o2  
    }
}

在这里插入图片描述

16.错误和异常区别:Arrays.toString(array)

package com.itheima01.throwable;
import java.util.Arrays;
//错误(Error) : 从程序角度 只能避开,不能解决。 异常(Exception) : 从程序角度 可以解决的问题
public class ThrowableDemo {
    public static void main(String[] args) {   
        // int[] array = new int[3];
        //System.out.println(array); //[I@6d6f6e28
        //System.out.println(array.toString()); //[I@6d6f6e28
        //System.out.println(Arrays.toString(array)); //[0, 0, 0]   

// int[] array = new int[2_000_000_000]; //20亿撑不住,内存条不够
// System.out.println(Arrays.toString(array)); //java.lang.OutOfMemoryError: Java heap(堆) space //OOM :内存溢出【错误】
        int[] array = {};
        System.out.println(array[1]); //java.lang.ArrayIndexOutOfBoundsException【异常】
    }
}

在这里插入图片描述

package com.itheima02.jvm;
import java.util.ArrayList;
/*
*  throw 关键字(全小写): 1. 效果等同于return,后续代码不再执行
*       2. throw + Throwable对象(只能跟异常对象);  return 返回值;
*       3. 运用: 我们一般不使用, JDK方法的设计者使用 (抛出异常: api设计者 和 使用者交流方式)
*/
public class ThrowDemo {
    public static void main(String[] args) {
//        new ArrayList<String>(-1); //IllegalArgumentException
        int[] array = {0,1};
        int element = getElement(array);
        System.out.println(element);
    }

    private static int getElement(int[] array) {
        int index = 2;
        if(index > array.length - 1){ //>2-1
            //访问了数组不存在的索引
//          ArrayIndexOutOfBoundsException e = new ArrayIndexOutOfBoundsException("you are a stupid bird,you access a wrong index:" + index);
//          throw e; //抛出异常,下面代码不会执行。抛出去之后也没人处理	
		
            throw  new ArrayIndexOutOfBoundsException(index); //这一行等同上两行            
			//throw new Throwable(""); //也可以,因为是编译异常,声明getElement方法后要加throws Throwable
        }
        int element = array[index]; //上面有throw,这里两行都不执行
        return element;
    }
}

17.编译和运行异常:SimpleDateFormat

在这里插入图片描述

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        String str = "1996-01-01";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf); //java.text.SimpleDateFormat@f67a0200
        
//  sdf.parse(str); //解析异常ParseException也叫编译异常,和IOException并列关系,main声明需抛出。
        Date parse = sdf.parse(str); //加上Date parse不报错
        System.out.println(parse); //Mon Jan 01 00:00:00 CST 1996

//   FileOutputStream fos = new FileOutputStream(""); //FileNotFoundException是IOException子类
//   fos.write(97); //IOException是最经典的编译异常

//111111111111111111111111111111111111111111111以下都为RuntimeException的子类
//       1.  NullPointerException  空指针
        String s = null;
//        System.out.println(s.length());

// 		2. IndexOutOfBoundsException  索引越界
        int[] array = {};
//        System.out.println(array[1]);

        // 3. ClassCastException  类转换
        // 4. IllegalArgumentException 非法参数
        new ArrayList<String>(-1);
    }
}

18.处理异常:方法声明抛出

在这里插入图片描述

package com.itheima03.throwsd;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class ThrowsDemo {
    public static void main(String[] args) throws IOException {
        method01(); //表哥又抛出去叫大哥(jvm,因为main方法调用者是jvm),jvm出错又打印终止
    } 
    /*
    *  throws 关键字
    *    1. 用在方法声明上: 修饰符 返回值类型 方法名(参数列表) throws 异常类型(A)
    *    2. 这是处理异常的一种方式: 声明将异常抛出给调用者处理(假手与人)
    *    3. 注意: 这里的异常类型A 必须跟方法里要抛出的异常B一致, 或者A是B的父类 (向上转型)
    * 
    *    语法: throws 异常1,异常2{ }
    *    运用: 我们可以在某一方法的设计上先声明抛出异常,可以方法的调用处进行处理
    *    切记有有一环节必须处理, 不然到JVM中, 出现异常就崩溃。如果明知不会错的异常,直接throws。
    */
    private static void method01() throws IOException { //交给表哥 
        FileOutputStream fos = new FileOutputStream("a.txt");
        fos.write(97);
    }
}
package com.itheima04.trycatch;

public class TrycatchDemo {
    public static void main(String[] args) {
        int[] array = {0,1};
        try{
            int element = array[2];
            System.out.println(element);
        }catch (Exception e){
         //catch关键字监视try中代码块,我们程序自己把异常处理了,所以不会传给JVM,程序不会终止。
            e.printStackTrace();//打印异常信息: 打印栈中追溯,案发地点在方法栈中。jvm不会打印了,我们自己手动打印。这行注释了,下面红字不会打印,但“出现异常..继续运行...”都会打印出。
            System.out.println("出现异常,并被捕获了");
        }
        System.out.println("程序继续执行");
    }
}

在这里插入图片描述

package com.itheima04.trycatch;
import java.util.Scanner;
/*
*   try...catch运用: 1. 如果代码都是由我们自己编写的,我们一般都不会出现异常
*        2. 有些代码需要用户参与编写 (交互: 我们程序输出,用户输入)
*思想: 我们预知代码可能运行结果(如果了包含了异常, 提前try...cath并给出提示或者解决方案)
*/
public class TryCatchDemo02 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个被除数:");
        int a = sc.nextInt();        
        System.out.println("请输入一个除数:");
        int b = sc.nextInt();        
        try {            
            int result = a/b; //java.lang.ArithmeticException: / by zero  算术异常
            System.out.println(result);
        }catch (Exception e){
            System.out.println("你个傻鸟,除数不能为0");
        }
        System.out.println("软件继续让你玩");
    }
}
package com.itheima04.trycatch;
/*
      try{
       }catch (NullPointerException e){
           //1. 如果出现了空指针,应该提示...
       }catch (IndexOutOfBoundsException e2){
           //2. 如果出现了索引越界, 应该提示...
       }
       
执行顺序:如果try中代码发生异常, 那么多个catch会从上到下逐一尝试捕获, 如果被A捕获了,后续的catch不再执行。
注意: 1. 前面catch中的异常类型不能是后面catch中的异常类型的父类或者相同 (因为这样的话,后续catch执行不到没有意义)  2. 后面catch中的异常类型可以是前面的父类。
*/
public class TryCatchCatchDemo {
    public static void main(String[] args) {
       try{
           method01(2);
       }catch (NullPointerException e){
           System.out.println("发生了空指针异常");
       }catch (IndexOutOfBoundsException e2){
           System.out.println("发生了索引越界异常");
       }
        System.out.println("代码继续执行");
    }
    
    //模拟: 这段代码可能有两个异常(一段代码里面不论可能有多少个异常,一次运行最多抛出一个异常)
    private static void method01(int a) {
        if(a == 1){
            throw new NullPointerException("空指针"); //throw天生与其他代码互斥,一旦发生throw,其他代码不再运行
        }else if(a == 2){
            throw new IndexOutOfBoundsException("越界异常");
        }else{
            System.out.println("什么事都没发生");
        }
    }
}

在这里插入图片描述

19.finally关键字:catch相当于else if,finally相当于else,return

package com.itheima04.trycatch;
/*
        try{
        }catch (Exception e){
        }finally {
           // 无论如何,一定最后执行。 作用: (IO流)释放资源
        }
*/
public class FinallyDemo {
    public static void main(String[] args) {
//        method();
       int number =  method2();  //运行 :3
        System.out.println(number);  //1
    }	

//111111111111111111111111111111111111111111111111111111111111111111111 
    private static int method2() {
        int i = 1;
        try{
//          System.exit(0); //拔电源阻止finally
            return i;  
 //一般return后续代码不会执行了,但finally会抢夺try...catch中的return执行权,finally会先执行,执行完又回到return 
 //return 安全机制: 把i的值给记录下来了1 ,所以return 1 
        }catch (Exception e){ //没有异常,i永远不会=2
            i = 2;
        }finally {
            i = 3;
            System.out.println("运行 :" + i);
        }
        return i; //不执行,因为try catch finally有return了
    }

//11111111111111111111111111111111111111111111111111111111111111111111
    private static void method() {
        try{
            int i = 4/0;
            System.out.println(i);
        }catch (NullPointerException e){
            System.out.println("异常发生了");
        }finally {
            System.out.println("无论如何一定执行");
        }
        System.out.println("程序继续执行");
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

20.自定义异常:extends

package com.itheima05.custom;
/*
*   JavaBean : 标准类 (封装)
*       1. private属性
*       2. public get set方法
*       3. public 空参构造,不声明构造会有一个空参构造。 写满参构造就得写空参构造。
*   封装:  1. private属性 为了不对外直接暴露 -> 安全
*          2. public get set方法【方法跟属性最大不同, 方法可以加条件判断(健壮性校验)】
*   继承: 自定义异常
*/
public class Student {
    private String name;
    private int age;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        if(age < 0){
//            throw new IllegalArgumentException("你个傻鸟,age没有负数");
            throw new NoAgeException("你个傻鸟,age没有负数"); //不报错,因为下面有定义class NoAgeException extends 。。。
        }
        this.age = age;
    }
}
package com.itheima05.custom;
/*
* 自定义异常: IllegalArgumentException : 非法参数异常
* NoAgeException : 非法年龄异常(框架: 很多JDK没有的异常,自定义)
*/
public class CustomDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
//        s.age = -18; // 非法访问,安全隐患,所以private int age;
        s.setAge(-18); //在方法里加安全机制
        System.out.println(s);
    }
}
class NoAgeException extends IllegalArgumentException{
    public NoAgeException(String msg){
        super(msg); //调用IllegalArgumentException,Ill..又调用自己的super。。
    }
}
package com.itheima06.notice;
import java.io.IOException;

public class NoticeDemo {
    public static void main(String[] args) throws IOException {       
        Fu fu = new Zi();  //编译看左边fu(上行已经抛出编译异常throws IOException), 运行看右边Zi(下面已经抛出运行异常throws RuntimeException)
        fu.method();
    }
}
class Fu{
    void method() {
    }
}
class Zi extends Fu{
    @Override
    void method() throws RuntimeException{ //运行异常 不报错 
    }
}
package com.atguigu.test01.review;
// 编写代码演示栈内存溢出 StackOverflowError(递归导致内存溢出)
public class TestError1 {
	public static void main(String[] args) {
		Son s = new Son();
		s.test(); //自己调用自己,不调用父类test()方法。java.lang.StackOverflowError
	}
}
class Father{
	public void test(){
		System.out.println("父类的");
	}
}
class Son extends Father{
	public void test(){ 
	    //调用父类的test();要用super.test()
		test();
		System.out.println("子类的");
	}
}
package com.atguigu.test01.review;
import java.util.ArrayList;
// 请编写代码演示OOM:OutOfMemoryError
public class TestError2 {
	public static void main(String[] args) {
		//1、答案一:创建一个超级大数组,
		//数组的长度的类型是int,Integer是int类型的一个包装类,Integer.MAX_VALUE是2的31次方-1
//		int[] arr = new int[Integer.MAX_VALUE];		

		//2、答案二:不断的创建对象
		ArrayList list = new ArrayList();//容器,用来装对象
		while(true){
			list.add(new Object());
		}
	}
}
public class TestFinallyNoReturn2 {
	public static void main(String[] args) {
		int num = getNum(4);
		System.out.println(num);//0,不是30
	}
	
	public static int getNum(int a){
		int result = 10;
		try{
			System.out.println(a/0); //直接跳到catch
			if(a > 0){
				result = 20;
				return result;
			}else if(a < 0){
				result = -20;
				return result;
			}else{
				return result;
			}
		}catch(Exception e){
			System.out.println("exception");
			result = 0;
			return result;
		}finally{
			result = 30;
			System.out.println("finally");
//			return result;//如果有这句,最后一行结果就变成30
		}
	}
}

在这里插入图片描述
在这里插入图片描述

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农编程录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值