Java
编译Java源程序文件将产生相应的字节码文件,这些字节码文件的扩展名为.class。
一个Java文件中可以定义多个class类,且一个类是public修饰,且public修饰的类名必须成为代码文件名,
1. cmd
<1> win+R
<2> 输入cmd
<3> 常见cmd命令
打开目录菜单:win+E
盘符名称+冒号
作用:盘符切换
举例:E:回车,表示切换到E盘
dir
作用:查看当前路径下的内容
cd目录
作用:进入单级目录
举例:cd itheima
cd..
作用回退到上一级目录
cd 目录1\目录2\ ..
作用:进入多级目录
举例:cd itheima\JavaSE
cd\
作用:回退到盘符目录
cls
作用:清屏
exit
作用:退出命令提示符窗口
2. JDK
即java的开发工具包,包括:
JVM 虚拟机:java程序运行的地方
核心类库: java已经写好的东西,可直接使用
开发工具:javac , java , jdb , jhat
3. JRE
即java的运行环境,包括:JVM ,核心类库 ,运行工具
JDK 包含了 JRE , JRE 包含了 JVM
4. 注释
单行注释 //
多行注释 /* */
文档注释 /** */
5. 关键字
关键字全部小写
(1)class
用于(创建 \ 定义)一个类(类是Java最基本的组成单元)
public class HelloWord{ }
类名 类的范围
6. 字面量
即数据在程序中的书写格式
(1)类型
整数类型、小数类型、字符串类型(用双引号括起来的内容)、字符类型(用单引号括起来的内容,内容只能有一个)、布尔类型(表真假,只有true和false)、空类型(特殊值null,但需要以字符串的形式)
(2)特殊字符
\t
在打印的时候,把前面字符串的长度补齐到8,或者是8的整数倍。最少补一个空格,最多补八个空格
7. 变量
定义:在程序的执行过程中,其值有可能发生改变的量。
数据类型 变量名 = 数据值
例如:
int a=10; System.out.println(a);
变量名不可重复定义,一条语句中可以定义多个变量,变量在使用前一定要赋值
对象的成员变量的默认值规则:
数据类型 明细 默认值
byte,short,int,long 0
基本类型 float,double 0.0
boolean false
引用类型 类,接口,数组,String null
8. 计算机的存储规则
(1)数据:文本(包含数字,字母,汉字),图片,声音
在计算机中,任何数据都是以二进制的形式来存储的
(2)不同进制在代码中的表现形式
二进制:由0和1组成,代码中以0b开头
十进制:由0-9组成,前面不加任何前缀
八进制:由0-7组成,代码中以0开头
十六进制:由0-9还有a-f组成,代码中以0x组成
(3)任意进制转十进制
例如:十六进制转十进制
a b c
10*16^2 + 10 *16^1 + 10 *16^0
二进制转十进制(8421快速转换法)
1 1 1 1 1 1 1 1
128 64 32 16 8 4 2 1
例如:二进制1101
1 1 0 1
8+4+1=13 转十进制后,结果为13
(4)十进制转其他进制
除基取余法
不断地除以基数(几进制,基数就是几)得到余数,直到商为0,再将余数到这拼起来即可
(5)图片数据
分辨率,像素,三原色(计算机中的颜色采用光学三原色,分别为红绿蓝,即RGB,可以写成十进制形式255,也可以写成十六进制FF)
9. 运算符
(1)算术运算符
“ + ”操作的三种情况:
① 数字相加
数字进行运算时,数据类型不同时,需转换成相同的,才能运算。
类型转换的分类
<1>隐式转换
取值范围小的数值------>取值范围大的数值
byte short char 三种类型的数据在运算时都会直接先提升为int,然后再进行运算
byte--->short--->int--->long--->float--->double(取值范围大)
<2>强制转换
取值范围大的数值------>取值范围小的数值
例如:int a=30;byte b=(byte)a;
在 Java 中两个byte相加,会自动提升为int,所以要强制转换
但是这些类型都有取值范围,如果超过,就用相加和减去最大值,但是不兼容类型,会导致转换有损失
内存占用
byte , boolean 1 short ,char 2 int,float 4 long,double 8
另:如果要定义long类型的变量,在数据值的后面需要加一个L作为后缀,L可以是大写的,也可以是小写的,但建议是大写
float同理要加F作为后缀
② 当“+”操作中出现字符串时,“+”变成了字符串连接符,会将前后的数据进行拼接,并产生一个新的字符串。
例如:
“123”+123 答案:“123123”
③连续进行“+”操作时,从左至右逐个执行。
例如:
1+99+“年黑马” 答案:”100年黑马“
例如:System.oout.println(1+2+"abc"+2+1) 答案:“3abc21”
② 字符相加
当字符+字符或字符+数字时,会把字符通过ASCLL码表查询到对应的数字再进行计算
(2)逻辑运算符
& 逻辑与(且) 并且,两边真才为真
| 逻辑或 或者,两边都为假,结果才是假
^ 逻辑异或 相同为false,不同为true
! 逻辑非 取反
无论左边真假,都要进行后面
短路逻辑运算符
也就是说,当左边的表达式能确定最终的结果,那么右边就不会参与运行了
&& 短路与 结果和&相同,但是有短路效果
|| 短路或 结果和|相同,但是有短路效果
()优先于所有
(3)其他运算符
<< 左移 向左移动,低位补0
》 右移 向右移动,高位补0或1
》> 无符号右移 向右移动,高位补0
10. 原码 反码 补码
原码:十进制数据的二进制表现形式,最左边是符号,0为正,1为负
反码:正数的补码反码是其本身,负数的反码是符号位保持不变,其余位取反,弊端:如果结果跨零,跟实际结果会有1的偏差
补码:正数的补码是其本身,负数的补码是在其反码的基础上+1,另外:补码还能多记录一个特殊的值-128,该数据在1个字节下没有原码和反码,计算机的存储和计算都是以补码的形式进行的
11. 循环
switch
case 1 ->{ } 可省略break
continue
结束本次循环,继续下次循环
break
结束整个循环
试题:猜数字
生成随机数:包头不包尾
int number=r.nextInt(10);
package com.itheima.test; import java.util.Random; public class helloWord { public static void main(String[] args) { Random r=new Random(); int number=r.nextInt(100); System.out.println(number); } }
如果包头也包尾,且头为任意数,可用:
例如生成任意数7~15,让这个头减去任意数,从0开始 //0~8
尾巴+1 //0~9 最终再加上第一步减去的数
package com.itheima.test; import java.util.Random; public class helloWord { public static void main(String[] args) { Random r=new Random(); int number=r.nextInt(100)+1;//1~~100 System.out.println(number); } }
完整代码:
package com.itheima.test; import java.util.Random; import java.util.Scanner; public class helloWord { public static void main(String[] args) { int count=0; Random r=new Random(); int number=r.nextInt(100)+1;//1~~100 Scanner sc=new Scanner(System.in); while(true) { System.out.println("请输入你要猜的数字"); int number2 = sc.nextInt(); count++; if(count==5)//保底机制 { System.out.println("猜中了"); break; } if (number2 > number) { System.out.println("猜大了"); } else if (number2 < number) { System.out.println("猜小了"); } else if (number2 == number) { System.out.println("猜中了"); break; } } } }
12. 数组
定义:用来存储同种数据类型的多个值(不同类型可以隐式强制转换)
格式一:数据类型 [ ] 数组名=new int[ ]{元素1,元素2,元素3...};
范例: int [ ] array 可省略new int[]
格式二: 数据类型 数组名 [ ]
范例: int array [ ]
在长度很多或未知的情况下,可用 for ( int i = 0 ; i < arr . length ;i++ )
或者可用 arr.fori 自动生成
动态初始化:数据类型[ ]数组名 =new 数据类型[ 数组的长度 ]
字符串用 String,如果没有定义,则默认初始化值,如下:
整数类型:默认为0
小数类型:默认0.0
字符类型:默认‘ \u0000 ’,但以空格表现
布尔类型:默认false
引用数据类型:默认 null
数组动态初始化和静态初始化的区别:
动态初始化
手动指定长度,由系统给出默认初始化值(只明确元素个数,不明确具体数值)
静态初始化
手动确定数组元素,系统会根据元素个数,计算出数组的长度(需求中已经明确了要操作的具体数值,直接静态初始化)
System.out.println(max);换行 System.out.print(max+‘ ’);一行 System.out.println();不打印,只换行
试题:交换数据
package com.itheima.test; public class helloWord { public static void main(String[] args) { int []a={1,2,3,4,5}; for(int i=0;i<a.length;i++){ System.out.print(a[i]+" "); } System.out.println(); for (int i = 0, j = a.length - 1; i < j; i++,j--) { int temp=a[i]; a[i]=a[j]; a[j]=temp; } for(int i=0;i<a.length;i++){ System.out.print(a[i]+" "); } } }
试题:打乱数据
package com.itheima.test; import java.util.Random; public class helloWord { public static void main(String[] args) { int []a={1,2,3,4,5}; Random r=new Random(); for(int i=0;i<a.length;i++) { int ra = r.nextInt(a.length); int temp = a[i]; a[i] = a[ra]; a[ra] = temp; } for(int i=0;i<a.length;i++){ System.out.print(a[i]+" "); } } }
13. 数组的内存图
Java内存分配:
栈:方法运行时使用的内存,比如main方法运行。
( 栈内存:开始执行会进栈,代码执行完毕会出栈 )
堆:存储对象或数组,new来创建的,都存储在堆内存。
(堆内存:new出来的东西会在这块内存中开辟空间并产生地址 )
方法区:存储可以运行的class文件。
本地方法栈:JVM在使用操作系统功能的时候使用,与程序员的开发无关
寄存器:给CPU使用,与程序员的开发无关
sout 查找元素
当两个数组指向同一个小空间时,其中一个数组对小空间的值发生了改变,那么其他数组再次访问的时候都是修改后的值。
14. 方法
方法是程序中最小的执行单元
重复的代码,具有独立功能的代码可以抽取到方法中
好处:提高代码的复用性,可维护性
(1)方法定义:把代码打包在一起
(2)方法调用:方法定义后并不是直接运行,需要手动调用才能执行
格式: 范例:
public static void 方法名(){ public static void playGame{
方法体(就是打包起来的代码) 七个打印语句
} }
调用: 方法名() 必须先定义后调用
直接调用(不打印返回值),赋值调用(将结果赋值个另一个变量),输出调用(System.out.println(getSum(10,20))
)
方法与方法之间是平级的,不能相互嵌套,方法编写顺序和执行顺序无关
方法返回值为void,表示该方法没有返回值,return可省略不写,若要写,则后面不能跟具体数值;return语句下面不能编写代码,因为永远编写不到,属于无效代码
(1) 方法的重载
在同一个类中,定义了多个重名的方法,这些同名的方法具有同种功能,但每个方法具有不同的参数类型或参数个数,这些同名的方法,就构成了重载关系。
参数不同:个数不同,类型不同,顺序不同
基本数据类型:整数,浮点数,布尔,字符 变量中存储的是数据
引用数据类型:数组 变量中存储的是地址值
传递基本数据类型时,传递的是真实的数据,形参的改变不影响实参的值
传递引用数据类型时,传递的是地址值,形参的改变影响实参的值
package com.itheima.test; public class helloWord { public static void main(String[] args) { int number=100; number=change(number); System.out.println(number); } public static int change(int number) { number=200; return number; } }但是将change的值返回并赋给number,就会改变
输入
package com.itheima.test; import java.util.Scanner; public class helloWord { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int month=sc.nextInt(); System.out.println("请输入当前座位 0头等舱 1经济舱"); int seat=sc.nextInt(); if(month>=5){ if(seat==1){} } } }
ctrl+alt+m 抽取
试题:验证码
package com.itheima.test; import java.util.Random; import java.util.Scanner; public class helloWord { public static void main(String[] args) { char[]chs=new char[52]; for(int i=0;i<chs.length;i++){ if(i<=25) { chs[i]=(char)('a'+i); }else{ chs[i]=(char)('A'+i-26); } } String result=""; Random r=new Random(); for(int i=0;i<4;i++){ int randomIndex=r.nextInt(chs.length); result+=chs[randomIndex]; } int number=r.nextInt(10); result+=number; System.out.println(result); } }
15. 类
类名 对象名 = new 类名( );
Phone p = new Phone( );
public class Student{
// 属性(成员变量)
String name;
double height;
// 行为(方法)
public void study ( ){
}
public void sleep ( ){ }
}
this ( 就近原则,本质:代表方法调用者的地址 )
public class Student { private int age; public void method(){ int age=10; System.out.println(age); // 10 System.out.println(this.age);这个指的是 private int age中的age // 0 } }
String
java.lang.String类代表字符串,(所以使用的时候不需要导包)Java程序中的所有字符串文字(例如“abc”)都为此类的对象。
字符串的内容是不会改变的,它的对象在创建后不能被更改。
创建String对象的两种方式:
(1)直接赋值
String name="hsjnxjk"
(2)new
构造方法 说明
public String( ) 创建空白字符,不含任何内容
public String( String original ) 根据传入的字符串,创建字符串对象
public String( char[ ] chs ) 根据字符数组,创建字符串对象
public String( byte[ ] chs) 根据字节数组,创建字符串对象
String s2=new String(); 表示“”,无内容
Systrm.out.println("@"+s2+"!")
byte[] bytes={97,97,99,100};
String s5=new String(bytes);
System.out.println(s5);
//打印的是abcd
String s1="abc";
String s2="abc"
//当时用双引号直接赋值时,系统会检查该字符串在串池中(字符串在串池中存储的是地址)是否存在,不存在:创建新的,存在则复用
String s1=new String("abc");
//记录堆里面的地址值
String s2="abc";
//记录串池中的地址值
System.out.println(s1==s2);
字符串比较
boolean equals方法(要比较的字符串) 完全一样结果才是true,否则为false
boolean equalslgnoreCase(要比较的字符串) 忽略大小写的比较
例如
boolean result=s1.equals(s2);
试题:登陆账号
package com.itheima.stringdemo; import java.util.Scanner; public class helloWord { public static void main(String[] args) { String rightusername="zheng"; String rightpassword="123456"; Scanner sc=new Scanner(System.in); for (int i=0;i<3;i++) { System.out.println("请输入用户名"); String username=sc.next(); System.out.println("请输入密码"); String password=sc.next(); if(username.equals(rightusername) && password.equals(rightpassword)){ System.out.println("用户登陆成功"); break; }else{ if (i==2) { System.out.println("账户"+username+"被锁定,请联系客服"); }else{ System.out.println("用户登陆失败,用户名或密码失败,您还剩下"+(2-i)+"次机会"); } } } } }
试题:统计字符串个数
public char charAt(int index):根据索引返回字符
public int length():返回字符串的长度
数组的长度:数组名.length
字符串的长度:字符串对象.length()
package com.itheima.stringdemo; import java.util.Scanner; public class helloWord { public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("请输入一个字符"); String str=sc.next(); int bigcount=0; int smallcount=0; int numbercount=0; for (int i = 0; i < str.length(); i++) { char c=str.charAt(i); if(c>='a' && c<='z'){ smallcount++; }else if(c>='A' && c<='Z'){ bigcount++; }else if(c>='0' && c<='9'){ numbercount++; } } System.out.println("小写字母有"+smallcount+"个"); System.out.println("大写字母有"+bigcount+"个"); System.out.println("数字字母有"+numbercount+"个"); } }
试题:抽奖
package com.itheima.stringdemo; import java.util.Random; public class helloWord { public static void main(String[] args) { int[] arr={398,29,889,6782,382}; Random r=new Random(); for(int i=0;i<arr.length;i++){ int randomIndex=r.nextInt(arr.length); int temp=arr[i]; arr[i]=arr[randomIndex]; arr[randomIndex]=temp; } for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
试题:屏蔽手机号
String substring(int beginlndex,int endlndex) 截取
注意:包头不包尾,包左不包右,只有返回值才是截取的小串
String substring(iny beginlndex) 截取到末尾
package com.itheima.stringdemo; public class helloWord { public static void main(String[] args) { String phoneNumber = "13678745677"; String start = phoneNumber.substring(0, 3);//前3位 String end = phoneNumber.substring(7); String result=start+"****"+end; System.out.println(result); } }
试题:替换敏感词
String replace(旧值,新词) 替换
注意:只有返回值才是替换之后的结果
package com.itheima.stringdemo; public class helloWord { public static void main(String[] args) { String word="wndjmlskl"; String[] arr={"mlskl"}; for(int i=0;i<arr.length;i++) { word=word.replace(arr[i],"***"); } System.out.println(word); } }
16. StringBuilder
可以看作是一个容器,创建之后内容是可变的
作用:提高字符串的操作效率
构造方法:
方法名 说明
public StringBulider() 创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象
常用方法:
public StringBuilder append(任意类型) 添加数据,并返回对象本身
public StringBuilder reverse() 反转容器中的内容
public int length() 返回长度(字符出现的个数)
public String toString() 通过toString()就可以把StringBuilder转换为String
(2)链式编程
当在调用一个方法时,不需要用变量接受他的结果,可以继续调用其他方法,例如字符串拼接append
package com.itheima.stringdemo; import java.util.Scanner; public class helloWord { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("Enter a word"); String str = sc.next(); String result = new StringBuilder().append(str).reverse().toString();//反转键盘录入的字符串 if(str.equals(result)){ System.out.println("当前字符串是对称的"); }else{ System.out.println("不是的"); } } }
17. StringJoiner
构造方法:
方法名 说明
public StringJoiner(间隔符号) 创建一个StringJoiner对象,指定拼接时的间隔符号
public StringJoiner(间隔符号,开始符号,结束符号) 创建一个StringJoiner对象,指定拼接时的间隔符号,开始符号,结束符号
成员方法:
方法名 说明
public StringJoiner add(添加的内容) 添加数据本身,并返回对象本身
public int length() 返回长度(字符出现的个数)
public String toString() 返回一个字符串(该字符串就是拼接之后结果)
package com.itheima.stringdemo; import java.util.Scanner; import java.util.StringJoiner; public class helloWord { public static void main(String[] args) { StringJoiner sj=new StringJoiner("+"); sj.add("123").add("456"); System.out.println(sj); } }
delimiter 间隔符号 prefix 开始符号 suffix 结束符号
package com.itheima.stringdemo; import java.util.Scanner; import java.util.StringJoiner; public class helloWord { public static void main(String[] args) { StringJoiner sj=new StringJoiner(",","[","]"); sj.add("123").add("456").add("789"); System.out.println(sj); int len=sj.length(); System.out.println(len);//长度为所有字符串的长度,包括空格 String str=sj.toString();//将其变成字符串 System.out.println(str); } }
18.字符串原理
(1)字符串存储的内存原理
直接赋值会复用字符串常量池中的,new出来不会复用,而是开辟一个新空间
(2)==比较的是什么
基本数据类型比较数据值,引用数据类型比较地址值
(3)字符串拼接底层原理
拼接是没有变量,都是字符串,触发字符串的优化机制,在编译时就已经是最终结果
字符串拼接时有变量参与,在内存中创建了很多对象,浪费空间和时间
(4)StringBuilder提高效率原理图
所有要拼接的内容都往StringBuilder中放,不会创建很多无用的空间,节约内存
(5)StringBuilder源码分析
默认会创建一个长度为16的字节数组,添加的内容小于16,直接存,添加的内容大于16会扩容(原来的容量*2+2),如果扩容后还不够,以实际长度为准
试题:罗马数字写法
package com.itheima.test; import java.util.Scanner; public class helloWord{ public static void main(String[] args){ Scanner sc=new Scanner(System.in);; String str; while(true){ System.out.println("请输入字符串"); str = sc.nextLine(); boolean flag=checkStr(str); if(flag){ break; }else{ System.out.println("不符合规则,请重新操作"); continue; } } StringBuilder sb=new StringBuilder(); for (int i = 0; i < str.length(); i++) { char c=str.charAt(i); int number=c-'0'; String s=change(number); sb.append(s); } System.out.println(sb); } public static String change(int number){ String[] arr={"","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ"}; return arr[number]; } public static boolean checkStr(String str){ if(str.length()>9){ return false; } for (int i = 0; i < str.length(); i++) { char c=str.charAt(i); if(c>'9'||c<'0'){ return false; } } return true; } }
试题:调整字符串的内容并比较
法一: package com.itheima.test; import java.util.Scanner; import static java.util.Collections.rotate; public class helloWord { public static void main(String[] args) { String strA="abcde"; String strB="cAb"; boolean result=check(strA, strB); System.out.println(result); } public static boolean check(String strA,String strB){ for (int i = 0; i < strA.length(); i++) { strA=rotate(strA); if(strA.equals(strB)){ return true; } } return false; } public static String rotate(String str) { char first=str.charAt(0); String end=str.substring(1); return end+first; } }
法二: package com.itheima.test; import java.util.Scanner; import static java.util.Collections.rotate; public class helloWord { public static void main(String[] args) { String strA="abcde"; String strB="cAb"; boolean result=check(strA, strB); System.out.println(result); } public static boolean check(String strA,String strB){ for (int i = 0; i < strA.length(); i++) { strA=rotate(strA); if(strA.equals(strB)){ return true; } } return false; } public static String rotate(String str) { char[]arr=str.toCharArray(); char first=arr[0]; for (int i = 1; i < arr.length; i++) { arr[i-1]=arr[i]; } arr[arr.length-1]=first; String result=new String(); return result; } }
19.集合
泛型:限定集合中存储数据的类型(只能支持引用数据类型)
//如果我们没有给集合指定类型,默认所有的数据类型都是Object类型,此时我们可以往集合添加任意的数据类型,但是我们在获取数据时,无法使用其特有行为 //泛型中不能写数据类型,向指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型,如果不写泛型,类型默认是Object //泛型方法不确定时,1.使用类名后面定义的泛型;2.在方法上申明定义自己的泛型 //泛型接口:修饰符 interface 接口名<类型>
ArrayList<String> list=new ArrayList<>( );//打印对象不是地址值,而是集合中存储数据内容,在展示时会拿[]把所有的数据进行包裹
<String> : 表示集合里面存储数据的类型
ArrayList成员方法:
方法名 说明
增 boolean add(E e) 添加元素,返回值表示是否添加成功
删 boolean remove(E e) 删除指定元素,返回值表示是否删除成功
E remove(int index) 删除指定索引的元素,返回被删除的元素
改 E set(int index,E e) 修改指定索引下的元素,返回原来的元素
查 E get(int index) 获取指定索引的元素
int size() 集合的长度,也就是集合中元素的个数
E是数据类型,e是创建对象
package com.itheima.test; import java.util.ArrayList; import java.util.Scanner; import static java.util.Collections.rotate; public class helloWord { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); //添加 list.add("hello"); list.add("world"); list.add("aaa"); list.add("aaa"); list.add("bbb"); list.add("ccc"); //删除一 boolean result2=list.remove("ddd"); System.out.println(result2); //删除二 String str=list.remove(2); System.out.println(str); //修改 String result3= list.set(3,"ddd"); System.out.println(result3); //查询 String s=list.get(3); System.out.println(s); System.out.println(list); //遍历 for (int i = 0; i < list.size(); i++) { String str1=list.get(i); System.out.println(str1); } } }
ArrayList集合底层原理:
1.利用空参创建的集合,在底层创建一个默认长度为0的数组
2.添加第一个元素时,底层会创建一个新的长度为10的数组
3.存满时,会扩容1.5倍
4.如果一次添加多个元素,1.5倍还放不下,则会创建数组的长度以实际为准
基本数据类型对应的包装类
byte Byte
short Short
char Character
int Interger
long Long
float Float
double Double
boolean Boolean
------------------------------------------------------------------------------------------------集合体系结构
Collection 单列结合,一次只能添加一个(单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用,里面定义的是共性的方法,因此不能通过索引删除,只能通过元素的对象删除,底层是依赖equals方法进行判断是否存在,如果集合中存储的是自定义对象,也想通过contains方法来判断是否存在,则一定要重写equals方法)
Map 双列结合,一次可添加多个
List系列集合:添加的元素是有序(存取顺序一致),可重复,有索引//添加数据,方法永远返回true Set系列集合:添加到元素是无序,不重复(集合元素),无索引(不能通过索引获取元素)//如果添加的数据不存在,返回true,如果已经存在,返回false
迭代器不依赖索引,在java中的类是lterator,迭代器是集合专用的遍历方式,it.next()相当于指针
细节:1.报错NoSuchEleementException;2.迭代器遍历完毕,指针不会复位;3.循环中只能用一次next方法;4.迭代器遍历时,不能用集合的方法进行增加或删除
增强for遍历:
增强for
Iterator<String> it=list.iterator(); while(it.hasNext()){ String str=it.next(); System.out.println(str); }
//删除元素(删的是索引上的元素)
原因:因为在调用方法时,如果方法出现了重载现象,优先调用实参跟形参类型一样的那个方法 list.remove
或者手动装箱(把基本数据类型的1变成Integer类型)
Integer i=Integer.valueOf(1);list.remove(i);
List<String> list =new ArrayList<>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); 1.迭代器 Iterator<String> it=list.iterator(); while(it.hasNext()){ String str=it.next(); sout(str); } 2.增强for for(String s: list){ sout(str); } 3.Lambda表达式 list.forEach(s->Sout(s)); 4.列表迭代器 ListItetor<String> it=list.listInterator(); while(it.hasnext()){ String str=it.next(); if("bbb".equals(str)){ it.add("qqq"); } sout }
试题:打印学生信息
法一: package com.itheima.test; import java.util.ArrayList; public class test4 { public static void main(String[] args) { ArrayList<com.itheima.test.Student> list=new ArrayList<>(); com.itheima.test.Student s1=new com.itheima.test.Student("zhangsan",29); com.itheima.test.Student s2=new com.itheima.test.Student("lisi",31); list.add(s1); list.add(s2); for (int i = 0; i < list.size(); i++) { com.itheima.test.Student stu= list.get(i); System.out.println(stu.getName()+","+stu.getAge()); } } }
package com.itheima.test; public class Student { private String name; private int age; public Student(){ } public Student(String name, int age) { this.name = name; this.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) { this.age = age; } }
ArrayList<Student> list=new ArrayList<>() //此时还未存入,长度为0
试题:查看id是否存在
package com.itheima.test; import java.util.ArrayList; public class test6 { public static void main(String[] args) { ArrayList<com.itheima.test.test5> list = new ArrayList<com.itheima.test.test5>(); com.itheima.test.test5 s1=new com.itheima.test.test5("jadjja","kdww","134"); com.itheima.test.test5 s2=new com.itheima.test.test5("jredja","kffe","13498"); list.add(s1); list.add(s2); boolean flag=contains(list,"jadjja"); System.out.println(flag); } public static boolean contains(ArrayList<com.itheima.test.test5> list, String id) { for (int i = 0; i < list.size(); i++) { if (list.get(i).getId().equals(id)) { return true; } } return false; } }
法二:返回数字
package com.itheima.test; import java.util.ArrayList; public class test6 { public static void main(String[] args) { ArrayList<com.itheima.test.test5> list = new ArrayList<com.itheima.test.test5>(); com.itheima.test.test5 u1=new com.itheima.test.test5("jadjja","kdww","134"); com.itheima.test.test5 u2=new com.itheima.test.test5("jredja","kffe","13498"); list.add(u1); list.add(u2); int index=getIndex(list,"jredja"); System.out.println(index); } public static int getIndex(ArrayList<com.itheima.test.test5> list, String id) { for (int i = 0; i < list.size(); i++) { com.itheima.test.test5 u=list.get(i); String uid=u.getId(); if (uid.equals(id)) { return i; } } return -1; } }
试题:返回多个数据
package com.itheima.test; import java.util.ArrayList; public class test6 { public static void main(String[] args) { ArrayList<com.itheima.test.Phone>list=new ArrayList<>(); com.itheima.test.Phone p1=new com.itheima.test.Phone("小米",1000); com.itheima.test.Phone p2=new com.itheima.test.Phone("苹果",8000); com.itheima.test.Phone p3=new com.itheima.test.Phone("锤子",2999); list.add(p1); list.add(p2); list.add(p3); ArrayList<com.itheima.test.Phone> phoneIn=getPhone(list); for (int i = 0; i < phoneIn.size(); i++) { com.itheima.test.Phone phone=phoneIn.get(i); System.out.println(phone.getBrand()+","+phone.getPrice()); } } public static ArrayList<com.itheima.test.Phone> getPhone(ArrayList<com.itheima.test.Phone> list) { ArrayList<com.itheima.test.Phone>resultList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { com.itheima.test.Phone p=list.get(i); int price=p.getPrice(); if(price<3000){ resultList.add(p); } } return resultList; } }
试题:学生管理系统
import java.util.ArrayList; import java.util.Scanner; public class student { public static void main(String[] args) { private static final String ADD_STUDENR="1"; private static final String DELETE_STUDENT="2"; private static final String UPDATE_STUDENT="3"; private static final String QU_STUDENT="4"; private static final String EXIT="5"; ArrayList<studentdask>list=new ArrayList<>(); loop: while (true) { System.out.println("------------欢迎来到学生管理系统------------"); System.out.println("1.添加学生信息"); System.out.println("2.删除学生"); System.out.println("3.修改学生信息"); System.out.println("4.查询学生信息"); System.out.println("5.退出"); Scanner sc = new Scanner(System.in); String choice = sc.next(); switch (choice) { case ADD_STUDENR -> addstudent(list); case DELETE_STUDENT -> DELETE_STUDENT(list); case UPDATE_STUDENT -> updatestudent(list); case QU_STUDENT -> qustudent(list); case EXIT->{ System.out.println("已退出"); break loop;//指定跳出这个循环或者System.exit(0)停止虚拟机运行 } default -> System.out.println("没有这个选项"); } } } //添加学生信息 public static void addstudent(ArrayList<studentdask>list){ studentdask s=new studentdask(); Scanner sc=new Scanner(System.in); String id=null; while(true) { System.out.println("请输入学生的id"); id = sc.next(); boolean flag = contains(list, id); if (flag) { System.out.println("id已录入,请重新录入"); } else { s.setId(id); break; } } System.out.println("请输入学生的姓名"); String name = sc.next(); s.setName(name); System.out.println("请输入学生的年龄"); int age = sc.nextInt(); s.setAge(age); System.out.println("请输入学生的家庭住址"); String address=sc.next(); s.setAddress(address); list.add(s); System.out.println("添加成功"); } //删除学生信息 public static void deletestudent(ArrayList<studentdask>list){ Scanner sc = new Scanner(System.in); System.out.println("请输入要删除的id"); String id = sc.next(); int index=getIndex(list,id); if(index>=0){ list.remove(index); System.out.println("id为"+id+"的学生删除成功"); }else{ System.out.println("id不存在,删除失败"); } } //修改学生信息 public static void updatestudent(ArrayList<studentdask>list){ Scanner sc = new Scanner(System.in); System.out.println("请输入要修改的学生的id"); String id = sc.next(); int index=getIndex(list,id); if(index==-1){ System.out.println("要修改的id:"+id+"不存在,请重新输入"); return; } studentdask stu=list.get(index); System.out.println("请输入要修改的学生姓名"); String newname=sc.next(); stu.setName(newname); System.out.println("请输入要修改的学生年龄"); int newAge=sc.nextInt(); stu.setAge(newAge); System.out.println("请输入要修改的学生家庭住址"); String newadress=sc.next(); stu.setAddress(newadress); System.out.println("学生信息修改成功"); } //查询学生信息 public static void qustudent(ArrayList<studentdask>list){ if(list.size()==0){ System.out.println("当前无学生信息,请添加后再查询"); return; } System.out.println("id\t\t姓名\t年龄\t家庭住址"); for (int i = 0; i < list.size(); i++) { studentdask stu=list.get(i); System.out.println(stu.getId()+"\t"+stu.getName()+"\t"+stu.getAge()+"\t"+stu.getAddress()); } } public static boolean contains(ArrayList<studentdask>list,String id){ // for (int i = 0; i < list.size(); i++) { // studentdask stu=list.get(i); // String sid=stu.getId(); // if(sid.equals(id)){ // return true; // } // } // return false; return getIndex(list,id)>=0; } public static int getIndex(ArrayList<studentdask>list,String id){ for (int i = 0; i < list.size(); i++) { studentdask stu=list.get(i); String sid=stu.getId(); if(sid.equals(id)){ return i; } } return -1; } }
public class studentdask { private String id; private String name; private int age; private String address; public studentdask(){ } public studentdask(String id, String name, int age, String address) { this.id=id; this.name=name; this.age=age; this.address=address; } public String getId() { return id; } public void setId(String 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 String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
二:
import java.util.ArrayList; import java.util.Random; import java.util.Scanner; public class App { public static void main(String[] args) { ArrayList<User> list=new ArrayList<>(); Scanner sc=new Scanner(System.in); while (true) { System.out.println("欢迎来到学生管理系统"); System.out.println("请选择以下操作:1.登录 2.注册 3.忘记密码"); String choose=sc.next(); switch(choose){ case "1"->login(list); case "2"->register(list); case "3"->forgetPassword(list); case "4"->{ System.out.println("退出"); System.out.println("感谢您的使用。再见"); System.exit(0); } default -> System.out.println("没有这个选项"); } } } private static void forgetPassword(ArrayList<User> list) { Scanner sc=new Scanner(System.in); System.out.println("请输入用户名"); String username=sc.next(); boolean flag=contains(list,username); if(!flag){ System.out.println("当前用户"+username+"未注册,请先注册"); return; } System.out.println("请输入身份证号码"); String personID=sc.next(); System.out.println("请输入手机号码"); String phoneNumber=sc.next(); int index=findIndex(list,username); User user=list.get(index); if(!(user.getPassword().equalsIgnoreCase(personID)&&user.getPhoneNumber().equals(phoneNumber))){ System.out.println("身份证号码或手机号码输入有误,不能修改密码"); return; } String password; while (true) { System.out.println("请输入新的密码"); password = sc.next(); System.out.println("请再次输入新的密码"); String againPassword=sc.next(); if(password.equals(againPassword)){ System.out.println("两次密码输入一致"); }else{ System.out.println("两次密码输入不一致,请重新操作"); continue; } user.setPassword(password); System.out.println("密码修改成功"); } } private static int findIndex(ArrayList<User> list, String username) { for (int i = 0; i < list.size(); i++) { User user=list.get(i); if(username.equals(user.getUsername())){ return i; } } return -1; } private static void register(ArrayList<User> list) { Scanner sc=new Scanner(System.in); String username; while (true) { System.out.println("请输入用户名"); username = sc.next(); boolean flag=chackUsername(username); if(flag){ System.out.println("格式满足条件,继续判断用户名是否唯一"); }else{ System.out.println("用户名格式不满足条件,需要重新输入"); continue; } boolean flag2=contains(list,username); if(flag2){ System.out.println("用户名"+username+"已存在,请重新输入"); }else{ break; } } String password; while (true) { System.out.println("请输入要注册的密码"); password = sc.next(); System.out.println("请再次输入密码"); String password2=sc.next(); if(!password.equals(password2)){ System.out.println("两次密码不一致,请重新输入"); continue; }else{ break; } } String personID; while (true) { System.out.println("请输入身份证号码"); personID = sc.next(); boolean flag=checkPersonID(personID); if(flag){ System.out.println("身份号码满足要求"); break; }else{ System.out.println("身份号码格式有误,请重新输入"); continue; } } String phonenumber; while (true) { System.out.println("请输入手机号码"); phonenumber = sc.next(); boolean flag=checkPhoneNumber(phonenumber); if(flag){ System.out.println("手机号码格式正确"); break; }else{ System.out.println("手机号码格式错误,请重新操作"); continue; } } User u=new User(username,password,personID,phonenumber); list.add(u); System.out.println("注册成功"); printList(list); } private static void printList(ArrayList<User> list) { for (int i = 0; i < list.size(); i++) { User user=list.get(i); System.out.println(user.getUsername()+","+user.getPassword()+","+user.getPersonID()+","+user.getPhoneNumber()); } } private static boolean checkPhoneNumber(String phonenumber) { if(phonenumber.length()!=11){ return false; } boolean b=phonenumber.startsWith("0"); if(b){ return false; } for (int i = 0; i < phonenumber.length(); i++) { char c=phonenumber.charAt(i); if(!(c>='0' && c<='9')){ return false; } } return true; } private static boolean checkPersonID(String personID) { if(personID.length()!=18){ return false; } boolean flag=personID.startsWith("0"); if(flag){ return false; } for (int i = 0; i < personID.length()-1; i++) { char c=personID.charAt(i); if(!(c>='0' && c<='9')){ return false; } } char endChar=personID.charAt(personID.length()-1); if((endChar>='0' && endChar<='9')||(endChar=='x')||(endChar=='X')){ return true; }else{ return false; } } private static boolean contains(ArrayList<User> list, String username) { for (int i = 0; i < list.size(); i++) { User user=list.get(i); String rightUsername=user.getUsername(); if(username.equals(rightUsername)){ return true; } } return false; } private static boolean chackUsername(String username) { int len=username.length(); if(len<3||len>15){ return false; } int count=0; for (int i = 0; i < username.length(); i++) { char c= username.charAt(i); if((c>='0'&&c<='9')||(c>='a'&&c<='z')||(c>='A'&&c<='Z')){ return true; } } for (int i = 0; i < username.length(); i++) { char c= username.charAt(i); if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){ count++; break; } } return count>0; } private static void login( ArrayList<User> list) { Scanner sc=new Scanner(System.in); for (int i=0;i<3;i++) { System.out.println("请输入用户名"); String username=sc.next(); boolean flag=contains(list,username); if(!flag){ System.out.println("用户名"+username+"未注册,请先注册再登陆"); return; } System.out.println("请输入密码"); String password=sc.next(); while (true) { String rightCode=getCode(); System.out.println("当前正确的验证码为:"+rightCode); System.out.println("请输入当前验证码"); String code=sc.next(); if(rightCode.equals(code)){ System.out.println("验证码正确"); break; }else{ System.out.println("验证码错误"); continue; } } User useInfo=new User(username,password,null,null); boolean result= checkUserInfo(list,useInfo); if(result){ System.out.println("登陆成功"); StudentSystem ss=new StudentSystem(); ss.student(); break; }else{ System.out.println("登陆失败,请重新操作"); if(i==2){ System.out.println("当前账号"+username+"被锁定,请联系客服"); return; }else{ System.out.println("用户名或密码错误,还剩下"+(2-i)+"次机会"); } } } } private static boolean checkUserInfo(ArrayList<User> list, User useInfo) { for (int i = 0; i < list.size(); i++) { User user=list.get(i); if(user.getUsername().equals(useInfo.getUsername())&&user.getPassword().equals(useInfo.getPassword())){ return true; } } return false; } private static String getCode(){ ArrayList<Character>list=new ArrayList<>(); for (int i = 0; i < 26; i++) { list.add((char)('a'+i)); list.add((char)('A'+i)); } StringBuilder sb = new StringBuilder(); Random r=new Random(); for (int i = 0; i < 4; i++) { int index=r.nextInt(list.size()); char c=list.get(index); sb.append(c); } int number=r.nextInt(10); sb.append(number); char []arr=sb.toString().toCharArray(); int randomIndex=r.nextInt(arr.length); char temp=arr[randomIndex]; arr[randomIndex]=arr[arr.length-1]; arr[arr.length-1]=temp; return new String(arr); } }
public class User { private String username; private String password; private String personID; private String phoneNumber; public User() { } public User(String username, String password, String personID, String phoneNumber) { this.username = username; this.password = password; this.personID = personID; this.phoneNumber = phoneNumber; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPersonID() { return personID; } public void setPersonID(String personID) { this.personID = personID; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } }
20. static
表示静态,是Java中的一个修饰符,可以修饰成员变量,成员方法
被static修饰的成员变量叫静态变量
特点:被该类所有对象共享,不属于对象,属于类,随着类的加载而加载的,优先于对象出现的(非静态跟对象有关)
调用方法:类名调用;对象名调用
被static修饰的成员方法叫静态方法
特点:多用在测试类和工具类中,JavaBean类中很少用
调用方式:类名调用,对象名调用
Java分类
javabean类 用来描述一类事物的类,比如:Student,Teather;
测试类 用来检查其他类是否书写正确,带有main方法的类,是程序的入口
工具类 不是用来描述一类事物的,而是帮我们做一些事情的类
<1> 类名见名知意;<2> 私有化构造;<3> 方法定义为静态
注意事项:
静态方法只能访问静态变量和静态方法;不能调用实例变量(即对象)
非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法;
静态方法中没有this关键字。
//输入soutv,再按tab,自动打印变量名和变量的值 int num=10; System.out.println("num = " + num); // 输入sout后按Tab键;sout代表 System.out.println() 语句 System.out.println("Hello, World!"); // 输入soutm后按Tab键,自动打印当前所在方法名 System.out.println("Main.main");
public class free { public static void main(String[] args) { public:被JVM调用,访问权限足够大 static:被JVM调用,不用创建对象,直接类名访问,因为main方法是静态的,所以测试类中其他方法也需要是静态的 void:被JVM调用,不需要给JVM返回值 main:一个通用的名称,虽然不是关键字,但是被JVM(虚拟机)识别 String[] args:以前用于接收键盘录入数据,现在没用
21. 继承
Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系
public class Student extends Person{} Student称为子类(派生类),person成为父类(基类或超类) 使用继承的
好处:
可以把多个子类中重复的代码抽取到父类,提高代码的复用性
子类可以在父类的基础上,增加其他的功能,使子类更强大
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
特点:
JAVA只支持单继承,不支持多继承,但支持多层继承
即:一个子类只能继承一个父类,子类不能同时继承多个父类,子类A继承父类B,父类B可以继承父类C(A与C的关系是简介父类,A与B的关系是直接父类)
每一个类都直接或间接的继承于Object (祖宗)
public class A extends Object{} == public class Object{} //自动默认继承,但是只能继承是直系的
public class test { public static void main(String[] args) { buou rd = new buou(); rd.eat(); rd.drink(); rd.zhua(); hashi h = new hashi(); h.eat(); h.drink(); h.cha(); h.brea(); } }
public class Animal { public void eat(){ System.out.println("吃东西"); } public void drink(){ System.out.println("喝水"); } }
public class cat extends Animal { public void zhua(){ System.out.println("抓东西"); } }
public class dog extends Animal{ public void cha(){ System.out.println("看家"); } }
public class buou extends cat{ }
public class Lihua extends cat{ }
从大往小写
方法区:与字节码文件有关,类被使用,他的字节码文件就要加载到方法区里面,被临时存储
栈内存:与方法有关,方法被调用,进栈执行,方法执行完毕,出栈
堆内存:与new关键字有关,创建的对象在里面
main()函数首先加载---->main方法被虚拟机自动调用,进栈运行----->当用到子类时,子类的字节码文件被加载到方法区---->父类被加载----->object的字节码文件被加载(有的可忽略)---->栈内存声明变量----->new在堆里面开辟了空间---->堆内存会把对象一分为二,分别记录父子类,然后默认初始值
虚方法表:将经常可能用到的方法单独放在里面,不能被private,static,final修饰
只有父类中的虚方法才能被子类继承
子类继承父类内容:
构造方法:非私有 不能;private 不能
成员变量: 非私有 能;private 能
成员方法: 虚方法表 能;否则不能
(3)成员变量的访问特点
就近原则(先在局部位置找,本类成员位置找,父类位置找,逐级往上)
public class Test{ public static void main(String[] args) { Zi z =new Zi(); z.zishow(); } } class Fu{ String name="Fu"; } class Zi extends Fu{ String name="Zi"; public void zishow(){ String name="Zishow"; System.out.println(name); //Zishow 从局部位置往上找 System.out.println(this.name); //Zi 从本类成员位置往上找 System.out.println(super.name); //Fu 从父类成员位置往上找 } }
(4)成员方法的访问特点
就近原则,super调用,直接访问父类
(5)方法重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式:
在继承体系中,子类和父类出现了一模一样的方法声明,我们就称子类这个方法就是重写的方法
@Override重写注解
1.@Override是放在重写后的方法上的,校验子类重写时语法是否正确
2.加上注解后如果有红色波浪线,表示语法错误
@Override public void eat(){ System.out.println(""); }
如果发生了方法重写,则子类中的方法就会进行覆盖(覆盖了虚方法表)
注意事项:
1.重写方法的名称、形参列表必须与父类中的一致
2.子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)
3.子类重写父类方法时,返回值类型子类必须小于等于父类
4.建议:重写的方法尽量和父类保持一致
5.只有被添加到虚方法表中的方法才能被重写
(6)构造方法的访问特点
父类中的构造方法不会被子类继承;
子类中所有的构造方法默认先访问父类中的无参构造,在执行自己
(因为子类在初始化时,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法完成父类的数据,所以子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化)
怎么调用父类构造方法?
子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行
如果想调用父类有参构造,必须手动写super进行调用
this:理解为一个变量,表示当前方法调用者的地址值;
this.成员变量 this.成员方法(...) this(...)访问构造方法
访问本类成员变量 访问本类成员方法 访问本类构方法
this(null,0,"船只大学");(所有语句在它之下)
super:代表父类存储空间
super.成员变量 super.成员方法(...) super(...)
访问父类成员变量 访问父类成员方法 访问父类构造方法
22.多态
对象代表什么,就得封装对应的数据,并提供数据对应的行为,继承是多态的前提条件
public void register(Person p){
p.show();//根据传递对象的不同,调用不同的show方法
}
(1)定义
同类型的对象,表现出的不同形态(即对象的多种形态)
(2)表现形式
父类类型 对象名称=子类对象;
(3)多态的前提
有继承关系;有父类引用指向子类对象( Fu f=new Zi() );有方法重写
(4)多态的好处
使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性与便利
public class taxt { public static void main(String[] args) { Student s=new Student(); s.setName("张三"); s.setAge(20); Teather t=new Teather(); t.setName("望江"); t.setAge(20); Admin admin=new Admin(); admin.setName("管理员"); admin.setAge(20); register(s); register(t); register(admin); } public static void register(Person P){ P.show(); } }
public class Student extends Person { @Override public void show(){ System.out.println("学生的信息为"+getName()+","+getAge()); } }
(5)多态调用成员的特点
变量调用:编译看左边,运行也看左边 //Animal a=new Dog() 输出动物;如果左边的父类中没有这个变量,则编译失败
方法调用:编译看左边,运行看右边 //编译时会看有没有这个方法,如果有,会运行子类的方法
instanceof 是,判断.前面是变量名,后面是类名
成员变量:在子类的对象中,会把父类的成员变量也继承下来
成员方法:如果子类对方法进行了重写,那么在虚方法中是会把父类的方法进行覆盖
(6)多态的优势和弊端
《1》优势
在多态形势下,右边对象可以实现解耦合,便于扩展和维护
Person p=new Student(); p.work(); //业务逻辑发生改变时,后续代码无需修改
定义方法时,使用父类作为参数,可以接收所有子类对象,体现多态扩展性与便利
《2》弊端
不能调用子类的特有功能
解决方案:转回子类类型 Dog d=(Dog) a;(不能瞎转,如果转成其他类型,就会报错)转换需要用instanceof进行判断
23.包
定义:包就是文件夹,用来管理不同功能的JAVA类,方便后期维护
包名规则:公司域名+包的作用,需要全部英文小写,见名知意
package com.itheima.domain //全类名,全限定名:包名+类名
使用其他类时,需要使用全类名
com.itheima.domain.Student s=new com.itheima.domain.Student(); //等于import com.itheima.domain.Student Student s=new Student();
使用其它类的规则:
使用同一个包中的类时,不需要导包;
使用java.lang包中的类时,不需要导包;// String就是javalang包
其他情况都需要导包;
如果同时使用两个包中的同类名,需要用全类名;
import com.itheima.domain1.Teacher import com.itheima.domain2.Teacher com.itheima.domain1.Theacher t2=new com.itheima.domain1.Theacher(); com.itheima.domain2.Theacher t2=new com.itheima.domain2.Theacher();
<1> final (不可改变的)
可修饰
方法:表明该方法是最终方法,不能被重写
类:表明该类是最终类,不能被继承
变量:叫做常量,只能被赋值一次
《///》常量
实际开发中,常量一般作为系统的配置中心,方便维护,提高可读性
常量的命名规范:
单个单词:全部大写
多个单词:全部大写,单词之间用下划线隔开
细节:
final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的属性值可以改变
final double PI=3.14; final Student S=new Student("zjdk",12); S.setName("李四"); S.setAge("24"); //引用数据类型
24. 权限修饰符
定义:用来控制一个成员能被访问的范围
可以修饰成员变量,方法,构造方法,内部类
分类:作用范围由小到大(private<空着不写/缺省/默认<protected<public
修饰符 | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
---|---|---|---|---|
private (只能自己用) | ✓ | |||
空着不写(只能在本包中使用) | ✓ | ✓ | ||
protected(受保护的) | ✓ | ✓ | ✓ | |
public(公共的) | ✓ | ✓ | ✓ | ✓ |
实际开发中,一般只用private和public (成员变量私有,方法公开)
如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有
25.代码块
(1)局部代码块
出了括号就消失,提前结束变量的生命周期
(2)构造代码块
创建本类对象时会先执行构造代码块再执行构造方法(即将相同的内容放到代码块中),抽取构造方法中的重复代码(不够灵活)
public class Student{ private String name; private int age; public Student(){ this(null,0); //这个可直接调用下面的sout或者调用方法() } public Student(String name,int age){ System.out.println("开始创建对象了"); //或者调用方法() this.name=name; this.age=age; } }
(3)静态代码块
格式:static{}
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只进行一次
使用场景:在类加载的时候,做一些数据初始化的时候使用
作用:数据的初始化
26.抽象类
当不确定方法体时,就用抽象关键字abstract
抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容不一样,在父类中不能确定具体的方法体
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
抽象方法格式:
public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式:
public abstract class 类名{}
注意事项(父类不一定是抽象的):
1)抽象类不能实例化(即不能创建对象)
2)抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
3)抽象类可以有构造方法,作用:当创建子类对象时,给属性赋值
4)抽象类的子类
要么重写抽象类中的所有抽象方法,要么子类本身是抽象类
27.接口
定义:接口用关键字interface来定义
public interface 接口名{}
接口不能实例化(即不能创建对象)
接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名{}
接口的子类(实现类):要么重写抽象类中的所有抽象方法,要么子类本身是抽象类
注意:
接口和类的实现关系,可以单实现,也可以多实现
public class 类名 implements 接口名1,接口名2{}
实现类还可以在继承一个类的同时实现多个接口
public class 类名 extends 父类 implements 接口名1,接口名2{}
接口中成员特点:
成员变量:
只能是常量,默认修饰符:public static final
无构造方法
成员方法:
只能是抽象方法,默认修饰符:public abstract
接口和类的关系:
1)类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承
2)类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
3)接口和接口的关系:继承关系,可以单继承,也可以多继承(如果实现类实现了最下面的子接口,那么需要重写所有的抽象方法)
JDK8以后接口中新增的方法:
(1)允许在接口中定义默认方法,需要使用关键字default修饰,作用:解决接口升级的问题
默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表){}
范例:public delault void show(){}
注意事项:
默认方法不是抽象方法,所以不强制被重写,重写的时候去掉default关键字。
public可以省略,default不能被省略(如果省略了,默认为抽象方法)。
如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
(2)允许在接口中定义定义静态的方法,需要用static修饰
接口中静态方法的定义格式:
public static 返回值类型 方法名(参数列表){}
注意事项:
静态方法只能通过接口名调用,不能实现类名或者对象名调用
public 可以省略,static不能省略
普通的私有方法,给默认方法服务的;静态的私有方法,给静态方法服务的
接口代表规则,是行为的抽象,想让哪个类拥有一个行为,就让这个类实现对应的接口;
当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方法称之为接口多态
接口适配器
书写步骤:编写中间类XXXAdapter,实现对应的接口对接口中的抽象方法进行空实现,让真正的实现类继承中间类,并重写需要用的方法,为避免其他类创建适配器类的对象,中间的适配器类需要用abstract进行修饰
28.内部类
在一个类里面,再定义一个类,内部类表示的事物是外部类的一部分,内部类单独出现没有任何意义
1)访问特点:
内部类可以直接访问外部类的成员,包括私有;外部类要访问内部类的成员,必须创建对象
2)分类
成员内部类
写在成员位置的,属于外部类成员,可以被一些修饰符所修饰:private,默认,protected(其他包的子类可以用),public,static(称为静态内部类)
《1》获取成员内部类的对象
方法一:在外部类中编写(当成员内部被private修饰时),对外提供内部类的对象
方法二:当成语内部类被非私有修饰时,直接创建格式:外部类名.内部类名 对象名=外部类对象。内部类对象
$是给内部类用,__ 是常量用
如果在内部类里面,打印同一个变量,但是是不同赋值
public class outer{ private int a=10; class inner{ private int a=20; public void show(){ int a=30; System.out.println(a); //30 //就近原则 System.out.println(this.a); //20 System.out.println(outer.this.a); //10 //不能是super,不是继承关系,无extends } } }
静态内部类
只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象
格式:外部类名。内部类名 对象名=new 外部类名。内部类名();
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名。内部类名。方法名();
Outer.Inner oi=new Outer.Inner();
局部内部类
定义:将内部类定义在方法里面,类似于方法里面的局部变量
外界是无法直接使用局部内部类,需要在方法内部创建对象并使用
该类可以直接访问外部类成员,也可以访问方法内的局部变量
匿名内部类
本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
格式:
new 类名或者是接口名(){
重写方法;
}; //包含继承或实现,方法重写,创建对象
例如:
new Swim(){ //单独一个swim表示接口,如果有new表示类,new的后面表示没有名字的new的对象,用空参构造
@Override
public void eat(){
System.out.println("")
}
};
new Swim(){ @Override public void swim(){ System.out.println("") } }.swim(); //可以再次调用自己创造的方法
使用场景:
当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只要一次,就可以使用匿名内部类
29.鼠标监听机制
方法
void mouseClicked(MouseEvent e) 在组件上单击(按下并释放)鼠标时调用
void mouseEntered(MouseEvent e) 当鼠标进入组件时调用
void mouseExited(MouseEvent e) 当鼠标退出组件时调用
void mousePressed(MouseEvent e) 在组件上按下鼠标按钮时调用
void mouseReleased(MouseEAvent e) 在组件上释放鼠标按钮时调用
30.键盘监听机制
void keyPress(KeyEvent e) 按下键时调用
void keyReleased(KeyEvent e) 当键已被释放时调用
void keyTyped(KeyEvent e) 键入键时调用
33.Obejet
• Object是Java的顶级父类,所有的类都直接或间接的继承于Object,其类中的方法可以被所有子类访问
public Object() 空参构造
public String toString() 返回对象的字符串表示形式 public boolean equals(object obj) 比较两个对象是否相等 public Object clone(int a) 对象克隆
public class Main{ public static void main(String[] args){ Object obj=new Object(); String str1=obj.toString(); System.out.println(str1); //java.lang.Object@10f87f48 (java.lang是包名+类名,@是固定格式,后面则是地址值) // Object obj=new Object();也可以省略下面的 // System.out.println(obj);(System是类名,out是静态变量,System.out可以获取打印的对象,println()表示方法,括号里面是参数,表示打印的内容) } }
public boolean equals(object obj) :
如果没有重写wquals方法,那么默认使用Object中的方法进行比较,比较的是地址值是否相等;如果重写后,比较的是对象内部的属性值
public class Main{ public static void main(String[] args){ Student s1=new Student("张三",23); Student s2=new Student("张三",23); boolean re=s1.equals(s2); System.out.println(re);; } } //答案是true
import java.util.Objects; public class Student { private String name; private int age; 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; } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); } public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name+','+age; } }
/
public class Main{ public static void main(String[] args){ String s="abc"; StringBuilder sb=new StringBuilder("abc"); System.out.println(s.equals(sb)); //false //因为equals方法是被s调用的 ,而s是字符串,所以equals是要看String类中的 // 字符串中的equals方法,先判断参数是否为字符串,如果是字符串,在比较内部属性,如果不是,直接返回false System.out.println(sb.equals(s)); //false //因为sb是StringBuilder的,但在StringBuilder当中,没有重写equals方法,使用的是Object中的,在Object当中默认是使用==号比较两个对象的地址值, //地址值不同,所以答案是false } }
Cloneable 对象克隆
// 如果一个接口里面没有抽象方法,表示当前的接口是一个标记性接口,现在Cloneable表示一旦实现,那么当前类的对象就可以被克隆
浅克隆 不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来(默认)
深克隆 基本数据类型拷贝过来,字符串复用,引用数剧类型会重新创建新的(需要重写方法或使用第三方工具)
34.Objects
public static boolean(Object a,Object b) 先做非空判断,比较两个对象 public static boolean isNull(Object obj) 判断对象是否为null,为null返回true public static boolean nonNull(object obj) 判断对象是否为null,跟isNull的结果相反
35.BigInteger
对象一旦创建,内部的值不能发生改变
public BigInteger(int num,Random rnd) 获取随机最大整数,范围:【0~2的num次方-1】 public BigInteger(String val) 获取指定的大整数 public BigInteger(String val,int radix) 获取指定的大整数 public static BigInteger valueOf(long val) 静态方法获取BigInteger的对象,内部有优化
字符串中的数字必须是整数,且必须要跟进制吻合,比如二进制中只能写0和1,当静态方法获取BigIntegerz的对象时,内部有优化
1.能表示的范围很小,只能在long的取值范围之内,如果超出long的范围就不行
2.在内部对常用的数字:-16~16进行了优化
如果没有超出long的范围,可以用静态方法获取,超出用构造方法获取 对象一旦创建,内部记录的值不能发生改变 只要进行计算都会产生一个新的BigInteger对象 如何获取BigInteger的对象呢? BigInter b1=BigInter.valueof(0.1); BigInteger b1=new BigInteger("整数"); 常见操作: 加:add 减:subtract 乘:multiply 除:divide,divideAndRemainder 比较:equals,max,min 次幂:pow 转成整数:intValue,longValue,doubleValue
36.BigDecima
精确运算:
通过传递字符串表示的小数来创建对象 BigDecimal bd3=new BigDecimal("0.01"); BigDecimal bd4=new BigDecimal("0.09"); BigDecimal bd5=bd3.add(bd4); System.out.println(bd3); System.out.println(bd4); System.out.println(bd5);//0.10 通过静态方法获取对象 BigDecimal bd6=BigDecimal.valueOf(10); System.out.printlln(bd6);
如果表示的数字不大,没有超出double的范围,建议使用静态方法;
如果表示的数字比较大,超出了double的取值范围,建议使用构造方法;
如果传递的是0~10之间的整数,包含0和10,那么方法会返回已经创建好的对象,不会重新new,如果是小数,则会false
public static BigDecimal valueOf(double val) 获取对象 public BigDecimal add(BigDecimal val) 加法 public BigDecimal subtract(BigDecimal val) 减法 public BigDecimal multiply(BigDecimal val) 乘法 public BigDecimal divide(BigDecimal val) 除法 public BigDecimal divide(BigDecimal val,精确几位,舍入模式) 除法
37.正则表达式
字符类(只匹配一个字符) [abc] 只能是a,b或c [^abc] 除了a,b,c之外的任何字符 [a-zA-Z] a到z A到Z,包括(范围) [a-d[m-0]] a到d,或m到p [a-z&&[def]] a-z和def的交集为def [a-z&&[^bc]] a-z和非bc的交集(等同于[ad-z]) [a-z&&[^m-p]] a到z和除了m到p的交集(等同于[a-[q-z]])
预定义字符(只匹配一个字符) . 任何字符 \d 一个数字[0-9] \D 非数字[^0-9] \s 一个空白字符:[\t\n\x0B\f\r] \S 非空白字符[^\s] \w [a-zA-Z_0-9]英文,数字,下划线 \W [^\w]一个非单词字符
\ 转移字符 改变后面那个字符原本的含义,例如想打印“,就要在前面加个\
\ \ 前面的\是一个转义字符,改变了后面\原本的含义,把\变成了一个普通的\( 两个\表示一个\ )
数量词 X? X,一次或0次 X* 零次或多次 X+ 一次或多次 X{n} 正好n次 X{n,} 至少n次 X{n,m} 至少n次但不超过m次
38.爬虫
import java.util.regex.Matcher; import java.util.regex.Pattern; public class Main { public static void main(String[] args) { String str="JAVA自问世以来,经历了很多版本,目前企业中用的最多的是JAVA8和JAVA11"; Pattern p=Pattern.compile("JAVA\\d{0,2}"); //m:文本匹配器的对象 //str:大串 //p:规则 //m要在str中找符合p规则的小串 Matcher m=p.matcher(str); //拿着文本匹配器从头开始读取,寻找是否有满足规则的子串,如果没有,返回false,有则返回true,在底层记录了子串的起始索引和结束索引+1 while(m.find()){ String s=m.group(); System.out.println(s); } } private static void group(Matcher m) { boolean b= m.find();//方法底层会根据find方法记录的索引进行字符串的截取,subString(起始索引,结束索引);包头不包尾 String s1= m.group(); System.out.println(s1); b= m.find(); String s2= m.group(); System.out.println(s2); } }
贪婪爬取:在爬取数据的时候尽可能多的多获取数据;ab+ (JAVA默认) //如果在数量词+*的后面加上?那么就是非贪婪爬取
非贪婪爬取:在爬取的时候尽可能少的获取数据; ab
方法名 说明 publlic String[] mathes(String regex) 判读字符串是否满足正则表达式的规则 public String replaceAll(String regex,String newStr) 按照正则表达式的规则进行替换 public String[] split(String regex) 判断正则表达式的规则切割字符串
39. JDK 时间 Date 时间类
全世界有一个统一的时间:格林尼治时间/格林威治时间,简称 GMT;
计算核心:地球自传一天是24小时,太阳直射时为正午12点
后面原子钟提供:利用铯原子的振动频率计算出来的时间( UTC )
中国标准时间=世界标准时间+8小时
public class Date{
private long time; //当前时间的毫秒值
public Date( ){
this.time=System.currentTimeMillis( );
}
public Date( long time ){
this.time=time;
}
}
如何创建? import java.util.Date; public class Main { public static void main(String[] args) { Date d=new Date(); System.out.println(d); } }
如何修改时间毫秒值:setTime()
如何获取时间对象的毫秒值:getTime()
40. SimpleDateFormat
SimpleDateFormat类的作用:
格式化:把时间变成我们喜欢的格式
解析:把字符串表示的时间变成Date对象
构造方法 说明 public SimpleDateFormat() 构造一个 SimpleDateFormat,使用默认格式 public SimpleDateFormat(String pattern) 构造一个 SimpleDateFormat,使用指定格式
常用方法 说明 public final String format(Date date) 格式化(日期对象->字符串) public Date parse(String source) 解析(字符串->日期对象)
41.Calendar
方法名 说明 public final Date getTime() 获取日期对象 public final setTime(Date date) 给日历设置日期对象 public long getTimeInMillis() 拿到时间毫秒值 public void getTimeInMillis(long milllis) 给日历设置时间毫秒值 public int get(int field) 取日历中的某个字符信息 public void set(int field,int value) 修改日历的某个字段信息 public void add(int field,int amount) 为某个字段增加/减少指定的值
Calendar是一个抽象类,不能用new,而是用静态方法获取到子类对象
底层原理:
1.会根据系统的不同时区来获取不同的日历对象,默认是当前时间;会把时间中的年月日时分秒放在一个数组中
2.月份:范围0~11,如果获取的是0,则表示1月;
星期:星期日是一周的第一天
0:纪元;1:年;2:月;3:一年中的第几周;4:一个月中的第几周;5:一个月的第几天 所以只需要用get()引用
Zoneld时区
方法名 说明 static Set<String> getAvailableZoneIds() 获取JAVA中支持的所有时区 static ZoneId systemDefault() 获取系统默认时区 static ZoneId of(String zoneId) 获取一个指定时区
Instant时间戳
static Instant now() 获取当前时间的Instant对象(标准时间) static Instant ofXxxx(long epochMilli) 根据(秒/毫秒/纳秒)获取Instant对象 ZonedDateTime atZone(ZoneId zone) 指定时区 boolean isXxxx(Instant otherInstant) 判断系列的方法 Instant minusXxx(long millisTosubtract) 增加时间系列的方法
42.包装类
定义:基本数据类型对应的引用类型
自动装箱:把基本数据类型会自动变成其对应的包装类
自动拆箱:把包装类自动的变成其对象的基本数据类型(所以,在JDK5之后,int和Integer可以看作是同一个东西,因为在内部可以自动转化,所以可以直接赋值)
//在类型转换的时候,括号中的参数只能是数字不能是其他,否则代码会报错,8种包装类当中,除了Character都有相应的parseXxx的方法,进行类型转换
键盘输入,不管什么类型,统一使用nextLine (特点是遇到回车才停止),int i=Integer.parseInt(line)
ArrayList<Integer> list = new ArrayList<>(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入一个整数"); String num=sc.nextLine(); int i=Integer.parseInt(num); if(i>100||i<1){ System.out.println("当前数字不在1~100之间,请重新输入"); continue; } list.add(i);//int 变成Integer int sum=getSum(list);
public class Main { public static void main(String[] args) { System.out.println(toBinaryString(6)); } public static String toBinaryString(int number) { StringBuilder sb = new StringBuilder(); while (true) { if(number == 0) { break; } int remaindar=number%2; sb.insert(0,remaindar);//倒着插入 number/=2; } return sb.toString(); } }
--------------------------------------------------------
常见算法
1.二分查找的数据必须是有序的,以下公式为插值查找(数据分布均匀)
$$
mid=min+(key-arr[min])/(arr[max]-arr[min])*(max-min)
$$
$$
斐波那契查找:mid=min+黄金分割点(1:0.618)左半边长度-1
$$
2.分块查找
原则:
1.前一块的最大数据,小于后一块的所有数据(块内无序,块外有序)
2.块数数量一半等于数字的个数开根号,比如:16个数字一般分为4个左右
public class Main { public static void main(String[] args) { int[] arr={16,5,9,21,18, 32,23,37,26,45,34, 50,48,61,52,73,66}; Block b1=new Block(21,0,5); Block b2=new Block(45,6,11); Block b3=new Block(73,12,17); Block[] blockArr={b1,b2,b3}; int num=30; int index=getIndex(blockArr,arr,num); System.out.println(index); } private static int getIndex(Block[] blockArr,int[] arr,int num){ int indexBlock=findIndexBlock(blockArr,num); if(indexBlock==-1){ return -1; } int startIndex=blockArr[indexBlock].getStartIndex(); int endIndex=blockArr[indexBlock].getEndIndex(); for(int i=startIndex; i<=endIndex; i++){ if(arr[i]==num){ return i; } } return -1; } public static int findIndexBlock(Block[] blockArr,int num){ for(int i=0;i<blockArr.length;i++){ if(num<=blockArr[i].getMax()){ return i; } } return -1; } } class Block{ private int max; private int startIndex; private int endIndex; public int getMax() { return max; } public void setMax(int max) { this.max = max; } public int getStartIndex() { return startIndex; } public void setStartIndex(int startIndex) { this.startIndex = startIndex; } public int getEndIndex() { return endIndex; } public void setEndIndex(int endIndex) { this.endIndex = endIndex; } public Block() { } public Block(int max, int startIndex, int endIndex) { this.max = max; this.startIndex = startIndex; this.endIndex = endIndex; } }
2.Arrays 操作数 组的工具类
方法名 说明 public static String toString(数组) 把数组拼接成一个字符串 public static int binarySearch(数组,查找的元素) 二分查找法查找元素 public static int[] copyOf(原数组,新数组长度) 拷贝数组//如果新数组长度>老数组,则会补上0 public static int[] copyOfRange(原数组,起始索引,结束索引) 拷贝数组(指定范围) public static void fill(数组,元素) 填充数组,数组中全是填充的数字 public static void sort(数组) 按照默认方式进行数组排序//默认升序,使用的是快速排序 public static void sort(数组,排序规则) 按照指定的规则排序
public static int binarySearch(数组,查找的元素)
二分查找法查找元素:1.数组有序;2.如果要查找的数组不存在,返回的是 -插入点-1(比如:20在10的后面,但是20不存在,插入点是10,则返回-11)
public static void sort(数组,排序规则)
1)只能给引用数据类型的数组进行排序,如果数组是基本数据类型,需要变成其对于的包装类,而排序规则需要传递这个接口的实现类对象,只使用一次,所以直接采用匿名内部类的方式
2)底层原理:利用插入排序+二分查找的方式进行排序,默认0索引的淑君有序,其余无序,插入时用二分查找寻找插入点,并用compare方法的方法体进行比较,若返回的是正数或0,则与后面的数据比;返回的是负数,则与前面的数据比;
3.Lambda
Arrays.sort(arr.(Integer o1,Integer 02)->{ return o1-o2; } );
//Lambda表达式可以用来简化匿名内部类的书写;只能简化函数式接口的匿名内部类的写法(函数式接口:有且仅有一个抽象方法的接口,接口上方可以加@Functionallnterfacr注解)
核心:可推导,可省略
省略规则:
1) 参数类型可省略;
2) 如果只有一个参数,参数类型和()可以省略;
3) 如果方法体只有一行,{};return可以同时省略
4.增强for遍历Lambda表达式
增强for的底层就是迭代器,内部原理是Iterator迭代器,所有的单列集合和数组才能用增强for进行遍历
for(元素的数据类型 变量名:数组或集合){ //修改增强for中的变量,不会改变集合中原本的元素 }
数据结构
1.栈
特点:先进后出
2.队列
特点:先进先出
3.红黑树
对象的哈希值特点:
如果没有重写hashCode方法,不同对象计算出的哈希值是不同的;如果已经重写hashCode方法,不同对象只要属性值相同,计算出的哈希值就是一样的;在小部分情况下,不同属性值或者不同的地址值计算出来的哈希值也是一样的(小概率发生哈希碰撞)
创建一个默认长度为16,默认加载为0.75的数组,数组名为table;根据元素的哈希值跟数组的长度计算出应存入的位置;判断当前位置是否为null,如果是null直接存入;否则调用equals方法比较属性值(一样:不存;不一样:存入数组,形成链表) int index=(数组长度-1)&哈希值;