1、switch
case里没有break 直接击穿本case下所有case同时也击穿执行了default。
2、逻辑算术符
短路与&&短路或||异或^
3、==与equal()的差别
==比较的是地址值是否相同
equals()比较的是内容 适用字符串内容的比较
对于字符串对象的比较,==比较的是地址,容易出业务bug
基本数据类型的变量或者值应该使用==比较。
使用String提供的equals方法,它只关心字符串内容一样就返回true。
4、a++/++a
在算术方程里的执行顺序
5、for与while
for(;;){}//格式
fori
界限次数.fori
while适用不知道循环次数的情况。
for适用知道具体循环次数的情况。
foreach:
for(类型变量名:集合) {
语句块;
}
// 声明并初始化数组
int[] numbers= { 43, 32, 53, 54, 75, 7, 10 };
System.out.println("----for----");
// for语句
for (inti=0; i<numbers.length; i++) {
System.out.println("Count is:"+numbers[i]);
}
// 声明并初始化int数组
int[] numbers= { 43, 32, 53, 54, 75, 7, 10 };
System.out.println("----for each----");
// for-each语句
for (intitem : numbers) {
System.out.println("Count is:"+item);
}
其中,“类型”为集合元素的类型,“变量名”表示集合中的每一个元素,“集合”是被遍历的集合对象或数组。每执行一次循环语句,循环变量就读取集合中的一个元素.
for (元素的数据类型变量名 : 数组或者集合) {
}
//增强for可以用来遍历集合或者数组。
//增强for遍历集合,本质就是迭代器遍历集合的简化写法。
Collection<String>c=newArrayList<>();
...
for(Strings : c) {
System.out.println(s);
}
//修改增强for中的变量值不会影响到集合中的元素。
for(元素的数据类型变量名 : 数组或者集合) {
//在此处使用变量即可,该变量就是元素
}s
6、方法
形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值。
形参是接受数据,return返回数据。
形参可以没有。
方法被调用的时候,是进入到栈内存中运行。
方法有返回值直接调用,可以不用赋值给变量,单独存在。
方法调用:直接调用,赋值,打印
publicstaticvoidmethod(inta ,intb){
return ;
}//格式:修饰符 返回类型 方法名(形参){方法体
}
构造方法:与普通方法相比不需要定义返回值类型。
7、+=
a+=b等于a=(a的数据类型)(a+b) //自带强制转换。
8、if
if(){}可没有{},只有一行代码时。
9、除/
整数 / 整数 = 整数
整数*1.0 / =保留小数的浮点数
取整左偏 7/2=3.5 取整是3
10、数字的相加与拼接
后面遇到数字(字符)就是相加,先遇到字符串就是拼接。
在字符串之前相加,之后拼接。
11、常用函数
Scannerscanner=newScanner(System.in);
intn=scanner.nextInt();
doublem=scanner.nextdouble();
Strings=scanner.next();//字符
Strings1=nextLine();//输入的字符有空格就用这个
Randomr=newRandom();
intnumber=r.nextInt(n)//0到n-1 可能重复 可以在外面加数+1 1-n 先调整左边的界限,再调整右边的界限。
12、Math方法中pow
Math.pow(数,次方)
13、值传递
Java的参数传递机制都是:值传递
数据值传递:指的是在传输实参给方法的形参的时候,传输的是实参变量中存储的值的副本。
地址值传递:传递的是地址实时更新。
基本类型的参数传输存储的数据值。
引用类型的参数传输存储的地址值。
14、数组初始化
int[] arr=newint[]{11,22,33,44,55};
int[] arr={};//简写形式
int[] arr=newint[5];//动态数组
int[] arr1=null;//空值
Ststem.out.printLn(arr1);//打印出null
Ststem.out.printLn(arr1[1]);//NullPointerEeception空指针
Ststem.out.printLn(arr1.length);//NullPointerEeception空指针
int[]默认值是0
double[]默认值是0.0
Sttring[]默认值是null
15、方法重载
方法重载:
一个类中,方法名相同,形参数据类型,个数,顺序不一样。那么这些方法就称为方法重载了。
一个类中,只要一些方法的名称相同、形参列表不同,那么它们就是方法重载了,其它的都不管(如:修饰符,返回值类型是否一样都无所谓)。
形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
调用方法的时候,会通过参数的不同来区分调用的是哪个方法。
方法应用:
处理用一类业务,提供多种解决方案。
调用方法:
适用一类任务,多种要求。
16、byte、short、char算术运算时都是默认int类型.
17、三目运算符的注意事项。
值的数据类型要相同
18、程序执行区域
方法区、栈、堆、本地方法栈、寄存器。
方法区:main方法
栈:普通变量,new出来的首地址
堆:new出来的内容
19、跳出结束
return; 跳出并立即结束所在方法的行。break; 跳出并结束当前所在循环的执行。continue; 结束当前所在循环的当次的执行,进入下一次执行。
20、idea快捷键
fori 循环
ctrl+/ 单行注释
ctrl+shift+/
sout 快速打印 System.out.println();
soutv 带参数快速打印 System.out.println("i = " + i);
alt+enter 快速生成变量
ctrl+alt+t 生成循环
ctrl+鼠标左键 查看方法全称
ctrl+enter 生成方法的修饰符返回值
21、String
String索引和数组一样,从零开始。
String初始化:
String代表字符串对象,可以用来封装字符串数据,并提供了很多操作字符串的方法
在 String 类中,有两个特殊的字符串,分别是:空串 和Null
串。null表示的是一个对象的值,而不是一个字符串。如声明一个对象的引用,String a=null。 “”表示的是一个空字符串,也就是说它的长度为0。如声明一个字符串String s=”“。 String a=null;表示声明一个字符串对象的引用,但指向为null,也就是说还没有指向任何的内存空间。String s=”“;表示声明一个字符串类型的引用,其值为“”,也就是空字符串,这个s引用指向的是空字符串的内存空间。
方式一:Java 程序中的所有字符串文字(例如“abc”)都为此类的对象。
String s1="";//空串 分配了地址空间
String s2=null;//没有分配地址空间
方式二:调用String类的构造器初始化字符串对象。
new String类,调用构造器初始化字符串对象。
String常用方法:
String s= String.valueof('c');字符型转化成字符串。用StringBuilder转化Char成为String。String.valueOf(c);也可以。
数组是.length,String是.length().
replace(被替换,用于替换)是全部替换。
String使用时的注意事项:
*String对象的内容不可改变,被称为不可变字符串对象。
*变量和字符拼接是创建新的对象
*只要是以“...”方式写出的字符串对象,会存储到字符串常量池,且相同内容的字符串只存储一份;
*但通过new方式创建字符串对象,每new一次都会产生一个新的对象放在堆内存中。
*String的对象是不可变字符串对象:每次试图改变字符串对象实际上是新产生了新的字符串对象了,变量每次都是指向了新的字符串对象,之前字符串对象的内容确实是没有改变的,因此说String的对象是不可变的。
22、优先级
23、变量
占内存,使用时必须赋值。
23、引用数据类型
类、方法、数组、String
直接打印引用数据类型,会打印出所在地址
String引用数据类型是特别的引用数据类型
默认值为:null
24、搞懂main方法
25、面向对象
直接打印对象就相当于调用了Object里面的toString()方法。
对象就是一种特殊的数据结构。---引用数据类型
对象是用类new出来的,有了类就可以创建出对象。
类名 对象名 = new 类名();
publicclass类名{
//1、变量,用来说明对象可以处理什么数据
//2、方法,描述对象有什么功能,也就是可以对数据进行什么样的处理 ... }
26、对象执行原理
Student s1 = new Student();
类名 对象名 是栈内存:s1变量里面记住的是学生对象的地址。s1变量中存储的是对象的地址,因此变量s1也称为引用类型的变量。
new 类名()是堆内存:每次new Student(),就是在堆内存中开辟一块内存区域代表一个学生对象。
变量 方法的执行是在方法区
成员变量(对象的属性)
成员方法(对象的行为)
成员变量本身存在默认值,与相对应的变量默认值相同
一个代码文件中,可以写多个class类,但只能一个用public修饰,且public修饰的类名必须成为代码文件名。
对象与对象之间的数据不会相互影响,但多个变量指向同一个对象时就会相互影响了。(一个对象赋值给另一个对象,两个对象共用一个堆内存的地址)
如果某个对象没有一个变量引用它,则该对象无法被操作了,该对象会成为所谓的垃圾对象。
当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。Java存在自动垃圾回收机制,会自动清除掉垃圾对象,程序员不用操心。
27、this
this就是一个变量,可以用在方法中,来拿到当前对象。
this主要用来解决:变量名称冲突问题的。
用来解决对象的成员变量与方法内部变量的名称一样时,导致访问冲突问题的。
28、构造方法(构造器)
创建对象时,对象会去调用构造器。
创建对象时,同时完成对对象成员变量(属性)的初始化赋值。
类在设计时,如果不写构造器,Java是会为类自动生成一个无参构造器的。
一旦定义了有参数构造器,Java就不会帮我们的类自动生成无参构造器了,此时就建议自己手写一个无参数构造器出来了。
修饰符+方法名(类名),无返回值。
构造方法的重载:同一个类内,相同方法名,不同的参数列表,与返回类型无关。
子类构造器的特点:子类的全部构造器,都会先调用父类的构造器,再执行自己。
子类构造器是如何实现调用父类构造器的:默认情况下,子类全部构造器的第一行代码都是 super() (写不写都有) ,它会调用父类的无参数构造器。如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(….),指定去调用父类的有参数构造器
子类构造器可以通过调用父类构造器,把对象中包含父类这部分的数据先初始化赋值,再回来把对象里包含子类这部分的数据也进行初始化赋值。
this(…)调用本类里其他的构造器:任意类的构造器中,是可以通过this(…) 去调用该类的其他构造器
this(...)和super(…)使用时的注意事项:this(…) 、super(…) 都只能放在构造器的第一行,因此,有了this(…)就不能写super(…)了,反之亦然。
29、封装
就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去。
公开成员,可以使用public(公开)进行修饰。
隐藏成员,使用private(私有,隐藏) 进行修饰。
合理隐藏。合理暴露。
30、数据类型
四种类型 八种数据结构
整数数据类型默认是int类型默认是21亿,赋值给long类型超过21亿需要用L/l在末尾修饰。
- byte的取值范围为-128~127,占用1个字节(-2的7次方到2的7次方-1)因为有0所以要减1.
- short的取值范围为-32768~32767,占用2个字节(-2的15次方到2的15次方-1)
- int的取值范围为(-2147483648~2147483647),占用4个字节(-2的31次方到2的31次方-1)
- long的取值范围为(-9223372036854774808~9223372036854774807),占用8个字节(-2的63次方到2的63次方-1)
- float 3.402823e+38 ~ 1.401298e-45(e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节
- double 1.797693e+308~ 4.9000000e-324 占用8个字节
31、JavaBean(实体类)
这个类中的成员变量都要私有,并且要对外提供相应的getXxx ,setXxx方法
类中必须要有一个公共的无参的构造器。
实体类只负责数据存取,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离。
成员变量必须私有,且要为他们提供get、set方法;必须有无参数构造器 。仅仅只是一个用来保存数据的java类,可以用它创建对象,保存某个事物的数据。
应用:实体类对应的是软件开发里现在比较流行的开发方式,数据和数据的业务处理相分离
32、成员变量和局部变量的区别
33、static修饰
static修饰的main只能直接使用static的方法
本类里方法调用本类的另一个方法,本类里不用static修饰的方法可以调用static方法。本类里static修饰的方法,调用的方法必须也是static修饰的方法。
34、ArrayList(集合之一)
ArrayList是集合中最常用的一种,集合类似于数组,也是容器,用来装数据的,但集合的大小可变。只能装引用类型的数据。删除元素,索引会-1。ArrayList增删改查是增删总体上加一减一,不是数组的覆盖。
直接打印ArrayList的实例,如果是String打印的是字符串的内容,如果是对象打印的是对象的地址
ArrayList是泛型类,可以约束存储的数据类型。
数组定义完成并启动后,类型确定、长度固定。
集合大小可变,提供的功能更为丰富,开发中用的更多
要点:
创建对象:调用无参数构造器初始化对象:public ArrayList();
增删改查:调用相应的增删改查数据的方法
容器的其他特点。
ArrayList的索引从0开始,size()方法相当于数组的length。
remove():使用remove方法都会导致原本在该元素之后的所有元素的索引值减1,如果直接按照下一个索引值继续遍历,会导致跳过一个元素,因此在删除一个元素后应该让索引值减1后再继续遍历。
remove删除重复内容的元素,一次只能删一个。
ArrayList的底层原理:
基于数组实现的。
- 查询速度快(注意:是根据索引查询数据块):查询数据通过地址值和索引定位,查询任意数据消耗时间相同。
- 删除效率低:可能需要把后面很多的数据进行前移。
- 添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容。
应用场景:
- ArrayList适合根据索引查询数据,数据量不是很大的时候。
- ArrayList不适合数量大,又要频繁的进行增删操作的情况。
35、包
用来分门别类的管理各种不同程序的,类似于文件夹,建包有利于程序的管理和维护。。
建包的语法格式:
package com.itheima.javabean;
package com.itheima.javabean;
public class Student {
}
导包格式:import 包名.类名;
在自己程序中调用其他包下的程序的注意事项:
*如果当前程序中,要调用自己所在包下的其他程序,可以直接调用。(同一个包下的类,互相可以直接调用)
*如果当前程序中,要调用其他包下的程序,则必须在当前程序中导包, 才可以访问!导包格式:import 包名.类名;
*如果当前程序中,要调用Java提供的程序,也需要先导包才可以使用;但是Java.lang包下的程序是不需要我们导包的,可以直接使用。
*如果当前程序中,要调用多个不同包下的程序,而这些程序名正好一样,此时默认只能导入一个程序,另一个程序必须带包名访问。
36、ASCII对照表
37、对象注意小点
自动垃圾回收机制
38、类变量与成员变量
有static修饰的成员变量是类变量,由所有该类的全部对象共享。
类变量(静态成员变量):属于类,与类一起加载一次,在内存中只有一份,可以被类和类的所有对象共享。
类名.类变量(推荐)
对象名.类变量(不推荐)
实例变量:属于对象,每个对象中都有一份,只能用对象访问。
对象.实例变量
访问自己类中的类变量,可以省略类名不写。
在某个类中访问其他类里的类变量,必须带类名访问
39.类方法
有static修饰的成员方法,属于类。
static修饰的方法只能使用本类里的类变量或者自己的内部变量。
类名.类方法 (推荐)
对象名.类方法(不推荐)
无static修饰的成员方法,属于对象。
对象.实例方法
类方法最常见的应用场景是做工具类。
注意事项:
- 类方法中可以直接访问类的成员,不可以直接访问实例成员。
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员。
- 实例方法中可以出现this关键字,类方法中不可以出现this关键字的。
40、java三大特性
封装、继承、多态。
封装:成员变量用private修饰,用构造方法初始化或用set方法去初始化,用get方法去获取成员变量。
41、工具类
工具类中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的。
提高了代码复用;调用方便,提高了开发效率。
工具类不需要创建对象, 建议将工具类的构造器私有化。目的是为了防止创建对象调用构造器,再调用类方法,这样会浪费内存。
42、修饰符修饰的作用范围
修饰符是用来限制类中的成员(成员变量、成员方法、构造器、代码块…)能够被访问的范围。
public:不同包可以点取访问。范围:任意位置
protected:不同类可以点取访问 范围:本类,同一个包中的类、子孙类中
private:用同一类可以点取访问。范围:只能本类
缺省:范围:本类、同一个包中的类。
43、类的5大成分之一
成员变量、构造器、方法、代码块、内部类。
代码块:
44、设计模式(design pattern)
一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。目的是确保一个类只有一个对象。
设计模式有20多种,对应20多种软件开发中会遇到的问题。
单列设计模式
模板方法设计模式
45、单列设计模式:
创建步骤:
- 私有化构造器。
- 创建私有化的类成员,储存对象。
- 创建返回对象的方法。
优点:可以避免浪费内存。
缺点:线程安全。全局就一个单例对象,都来操作。
饿汉式单例:
//把类的构造器私有。
//定义一个类变量记住类的一个对象。
//定义一个类方法,返回对象。
// 单例类
public class A { // 2、定义一个类变量记住类的一个对象
private static A a = new A();
// 1、私有构造器
private A(){ }
// 3、定义一个类方法返回对象
public static A getObject(){
return a; }
}
//这是饿汉式单例,还有很多单例,比如懒汉式单例。
//把类的构造器私有;定义一个类变量存储类的一个对象;提供一个类方法返回对象。
//在获取类的对象时,对象已经创建好了
懒汉式单例设计模式:
//拿对象时,才开始创建对象。
//把类的构造器私有。
//定义一个类变量用于存储对象。
//提供一个类方法,保证返回的是同一个对象。
public class B {
// 2、定义一个类变量量用于存储对象
public static B b ; // null
// 1、单例必须私有构造器
private B(){ }
// 3、提供一个类方法返回类的一个对象
public static B getObject(){
if(b == null){
b = new B();
}
return b;
}
}
46、继承(派生类)
##### 特点:
子类能继承父类的**非私有成员**(成员变量、成员方法)。
##### 创建:
子类的对象是由子类、父类共同完成的。
带继承关系的类,java会用类和其父类,这多张设计图来一起创建类的对象。
对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员。
##### 总结:
带继承关系的类,java会用类和其父类,这多张设计图来一起创建类的对象。
对象能直接访问什么成员,是由子父类这多张设计图共同决定的,这多张设计图对外暴露了什么成员,对象就可以访问什么成员。
##### 好处:
减少了重复代码的编写,提高了代码的复用性。
**注意**:
Java是单继承的,Java中的类不支持多继承,但是支持多层继承。
object类是java所有类的**祖宗类**。我们写的任何一个类,其实都是object的子类或子孙类。
47、方法重写
当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。注意:重写后,方法的访问,Java会遵循就近原则 。
先子类局部范围找。然后子类成员范围找。然后父类成员范围找,如果父类范围还没有找到则报错。
重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限( public > protected > 缺省 )。重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。私有方法、静态方法不能被重写,如果重写会报错的。
如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的成员,则可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法。
私有方法不能被重写。
静态方法不能被重写,但是可以被隐藏。如果在子类中定义了一个与父类中同名、同参数列表、同返回类型的静态方法,那么子类中的方法会隐藏父类中的方法,而不是重写父类中的方法。这是因为静态方法是与类关联的,而不是与对象关联的,所以子类中的静态方法与父类中的静态方法是两个不同的方法。如果在子类中调用这个方法,会调用子类中的方法,而不是父类中的方法。
直接打印对象就相当于调用了Object里面的toString()方法。
48、多态
定义:多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
前提:有继承/实现关系;存在父类引用子类对象;存在方法重写。
注意事项:多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
多态下不能直接调用子类的独有方法。要使用子类的独有方法,就把父类强制转换成子类。先使用instanceof()判断是否是相同类型。
父类作为方法的形参,其子类也可以作为该方法的形参
作用:多个类中只要有重复代码(包括相同的方法签名),我们都应该抽取到父类中去,此时,父类中就有可能存在只有方法签名的方法,这时,父类必定是一个抽象类了,我们抽出这样的抽象类,就是为了更好的支持多态。
People p1 = new Teacher();
p1.run();
//定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
//类型转换
//自动类型转换:父类 变量名 = new 子类();
People p = new Teacher();
//子类 变量名 = (子类) 父类变量
Teacher t = (Teacher)p;
//类型转换的注意事项
//存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
//运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
People p = new Teacher();
Student s = (Student) p; // java.lang.ClassCastException
//instanceof关键字,判断当前对象的真实类型,再进行强转。
p instanceof;
49、final
修饰类:该类被称为最终类,特点是不能被继承了。修饰方法:该方法被称为最终方法,特点是不能被重写了。修饰变量:该变量只能被赋值一次。
注意事项:final修饰基本类型的变量,变量存储的数据不能被改变。final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。
50、常量:
使用了 static final 修饰的成员变量就被称为常量;作用:通常用于记录系统的配置信息。
命名:注意!常量名的命名规范:建议使用大写英文单词,多个单词使用下划线连接起来。
使用常量记录系统配置信息的优势、执行原理:
代码可读性更好,可维护性也更好。程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
51、abstact:
在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
继承抽象类必须实现父类其中所有的抽象方法,否则只能变成抽象类。
修饰符 abstract class 类名{
修饰符 abstract 返回值类型 方法名称(形参列表);
}
public abstract class A {
// 抽象方法:必须abstract修饰,只有方法签名,不能有方法体
。 public abstract void test();
}
抽象类的注意事项、特点:
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。类该有的成员(成员变量、方法、构造器)抽象类都可以有。抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
52、模板方法设计模式
*定义一个抽象类。*在里面定义2个方法一个是模板方法:把相同代码放里面去。一个是抽象方法:具体实现交给子类完成。
建议使用final关键字修饰模板方法:
模板方法是给对象直接使用的,不能被子类重写。
一旦子类重写了模板方法,模板方法就失效了。
53、接口
方法只能为抽象方法
//Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口。
public interface 接口名 {
// 成员变量(常量)
// 成员方法(抽象方法)
//注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
// 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
好处:弥补了类单继承的不足,类可以同时实现多个接口。让程序可以面向接口编程,这样既不用关心实现的细节,也可以灵活方便的切换各种实现。
面向接口编程
//JDK 8开始,接口新增了三种形式的方法:
public interface A{
/** * 1、默认方法(实例方法):使用用default修饰,默认会被加上public修饰。
* 注意:只能使用接口的实现类对象调用
*/
default void test1(){
...
}
/** * 2、私有方法:必须用private修饰(JDK 9开始才支持) */
private void test2(){
...
}
/**
* 3、类方法(静态方法):使用static修饰,默认会被加上public修饰。 * 注意:只能用接口名来调用。
*/
static void test3(){
...
}
}
默认方法(正常方法):使用default修饰,使用实现类的对象调用。静态方法:static修饰,必须用当前接口名调用私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。他们都会默认被public修饰。
//接口的多继承
public interface C extends B , A{
}
//便于实现类去实现。
接口其他注意事项(了解):
1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的方法。4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
54、内部类
定义:如果一个类定义在另一个类的内部,这个类就是内部类。
场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
public class Car{
// 内部类 public class Engine{
}
}
成员内部类:
就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法。
public class Outer {
// 成员内部类
public class Inner {
}
}
//JDK16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了
//外部类名.内部类名 对象名 = new 外部类(...).new 内部类(...);
Outer.Inner in = new Outer().new Inner();
//1、和前面学过的实例方法一样,成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员。
//2、可以在成员内部类的实例方法中,拿到当前外部类对象,格式是:外部类名.this 。
静态内部类:
有static修饰的内部类,属于外部类自己持有。
public class Outer{
// 静态内部类
public static class Inner{
}
}
//外部类名.内部类名 对象名 = new 外部类.内部类(…);
Outer.Inner in = new Outer.Inner();
//可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员.
局部内部类:
局部内部类是定义在在方法中、代码块中、构造器等执行体中。
只能在其方法里new。
public class Test {
public static void main(String[] args) {
}
public static void go(){
class A{
}
abstract class B{
}
interface C{
}
}
}
匿名内部类:
就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字。new 类或接口(参数值…)
通常作为一个参数传输给方法。
{
类体(一般是方法重写);
};
new Animal(){
@Override
public void cry() {
}
};
//特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
//作用:用于更方便的创建一个子类对象。
//需求:猫、狗参加游泳比赛。
public interface Swimming{
void swim();
}
public class Test {
public static void main(String[] args) {
// 目标:认识匿名内部类,并掌握其作用。
Swimming s1 = new Swimming() {
@Override
public void swim() {
System.out.println(“狗🏊飞快~~~”);
}
};
go(s1);
go(new Swimming() {
@Override
public void swim() {
System.out.println(“猫🏊也还行~~~");
}
});
}
public static void go(Swimming s){
System.out.println("开始============");
s.swim();
}
}
匿名内部类本质就是一个子类,并会立即创建出一个子类对象
作用:
可以更方便的创建出一个子类对象。匿名内部类通常作为一个参数传输给方法。
匿名内部类的使用前提: 一定得继承继承父类或实现一个接口 匿名内部类共有三类,一是继承式的匿名内部类,二是接口式的匿名内部类,三是参数式的匿名内部类。(注意object的equals方法重写,IEDA匿名内部类提示有坑,不能每一个字母敲出来,要P直接去拿public boolean equals(){})
55、Override注解
重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。
56、枚举
Java 中的每一个枚举都继承自 java.lang.Enum 类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可。
格式:
修饰符 enum 枚举类名{
名称1 , 名称2, ... ;
其他成员…
}
public enum A{
X , Y , Z;
...
}
//枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
//这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
//声明枚举时必须使用 enum 关键字,然后定义枚举的名称、可访问性、基础类型和成员等。枚举声明的语法如下:
enum-modifiers enum enumname:enum-base {
enum-body,
}
//其中,enum-modifiers 表示枚举的修饰符主要包括 public、private 和 internal;enumname 表示声明的枚举名称;enum-base 表示基础类型;enum-body 表示枚举的成员,它是枚举类型的命名常数。
//任意两个枚举成员不能具有相同的名称,且它的常数值必须在该枚举的基础类型的范围之内,多个枚举成员之间使用逗号分隔。
//提示:如果没有显式地声明基础类型的枚举,那么意味着它所对应的基础类型是 int。
//使用枚举还可以使 switch 语句的可读性更强,例如以下示例代码:
enum Signal {
// 定义一个枚举类型
GREEN,YELLOW,RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch(color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。枚举都是最终类,不可以被继承。枚举类中,从第二行开始,可以定义类的其他各种成员。编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
使用枚举类实现单例模式?
枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数。枚举在曰常生活中很常见,例如一个人的性别只能是“男”或者“女”,一周的星期只能是 7 天中的一个等。类似这种当一个变量有几种固定可能的取值时,就可以将它定义为枚举类型。
//通过调用枚举类型实例的 values( ) 方法可以将枚举的所有成员以数组形式返回,也可以通过该方法获取枚举类型的成员。
enum Signal {
// 定义一个枚举类型
GREEN,YELLOW,RED;
}
public static void main(String[] args) {
for(int i = 0;i < Signal.values().length;i++) {
System.out.println("枚举成员:"+Signal.values()[i]);
}
}
//创建一个示例,调用valueOf() 方法获取枚举的一个成员,再调用 compareTo() 方法进行比较,并输出结果。具体实现代码如下:
57、泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>) ,称为泛型类、泛型接口,泛型方法、它们统称为泛型。只能是引用类型。
泛型本质上是提供类型的“类型参数”,也就是参数化类型。我们可以为类、接口或方法指定一个类型参数,通过这个参数限制操作的数据类型,从而保证类型转换的绝对安全。
//泛型类
public class ArrayList<E>{
. . .
}
修饰符 class 类名<类型变量,类型变量,…> {
}
//注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
//泛型接口
修饰符 interface 接口名<类型变量,类型变量,…> {
}
public interface A<E>{
. . .
}
//泛型方法
修饰符 <类型变量,类型变量,…> 返回值类型 方法名(形参列表) {
}
public static <T> void test(T t){
}
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
泛型的本质:把具体的数据类型作为参数传给类型变量。
通配符:
就是 “?” ,可以在“使用泛型”的时候代表一切类型; E T K V 是在定义泛型的时候使用。
泛型的上下限:
泛型上限: ? extends Car: ? 能接收的必须是Car或者其子类 。 泛型下限: ? super Car : ? 能接收的必须是Car或者其父类。
泛型的擦除问题和注意事项:
泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
58、API
API(Application Programming interface) :应用程序编程接口
就是Java帮我们已经写好一些程序,如:类、方法等,我们直接拿过来用就可以解决一些问题。
toString存在的意义:toString()方法存在的意义就是为了被子类重写,以便返回对象具体的内容。
equals存在的意义:直接比较两个对象的地址是否相同完全可以用“==”替代equals,equals存在的意义就是为了被子类重写,以便子类自己来定制比较规则(比如比较对象内容)。
clone:
浅克隆:
拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址)
深克隆:
对象中基本类型的数据直接拷贝。对象中的字符串数据拷贝的还是地址。对象中还包含的其他对象,不会拷贝地址,会创建新对象。
Objects:
更安全
包装类:
8种,int -> Integer , char -> Character,其他的都是首字母大写
包装类就是把基本类型的数据包装成对象。
自动装箱:基本数据类型可以自动转换为包装类型。
自动拆箱:包装类型可以自动转换为基本数据类型。
//包装类的其他常见操作
//可以把基本类型的数据转换成字符串类型。
public static String toString(double d)
public String toString()
//可以把字符串类型的数值转换成数值本身对应的数据类型。
public static int parseInt(String s)
public static Integer valueOf(String s)
59、StringBuilder
StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的。好处:StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。
对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高!
注意:如果操作字符串较少,或者不需要操作,以及定义字符串变量,还是建议用String。
60、StringBuffer与StringBuilder
StringBuffer的用法与StringBuilder是一模一样的但 StringBuilder是线程不安全的 StringBuffer是线程安全的
61、StringJoiner
JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。
好处:不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
62、API II
Math:代表数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法.
System:
System代表程序所在的系统,也是一个工具类。
status是系统退出时展现的代码:
System.exit(0) 正常为0,非正常为非0。按照惯例,非零状态代码表示异常终止。此方法在类运行时调用exit方法。此方法从不正常返回。
进程已结束,退出代码0
时间毫秒值:
指的是从1970年1月1日 00:00:00走到此刻的总的毫秒数,应该是很大的。 1s = 1000ms。
Runtime:
代表程序所在的运行环境。Runtime是一个单例类。
BigDeciamal:
用于解决浮点型运算时,出现结果失真的问题。
Date:
SimpleDateFormat:
代表简单日期格式化,可以用来把日期对象、时间毫秒值格式化成我们想要的形式。
Calendar:
代表的是系统此刻时间对应的日历.
通过它可以单独获取、修改时间中的年、月、日、时、分、秒等。
63、java.time包下面的类:
LocalDate:代表本地日期(年、月、日、星期)LocalTime:代表本地时间(时、分、秒、纳秒)LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)
LocalDate的常用API(都是处理年、月、日、星期相关的):
LocalTime的常用API (都是处理时、分、秒、纳秒相关的):
LocalDateTime的常用API(可以处理年、月、日、星期、时、分、秒、纳秒等信息):
LocalDateTime的转换成LocalDate、LocalTime:
63、国际标准时间UTC与中国标准时间:
ZoneId:代表时区Id。
64、时区
由于世界各个国家与地区的经度不同,各地区的时间也有所不同,因此会划分为不同的时区。
65、Instant
Instant时间线上的某个时刻/时间戳:通过获取Instant的对象可以拿到此刻的时间,该时间由两部分组成:从1970-01-01 00:00:00 开始走到此刻的总秒数 + 不够1秒的纳秒数。
Tip:1秒=1000毫秒;1毫秒=1000微秒;1微秒=1000纳秒;1秒 = 1000 000 000纳秒
作用:可以用来记录代码的执行时间,或用于记录用户操作某个事件的时间点。
传统的Date类,只能精确到毫秒,并且是可变对象;
新增的Instant类,可以精确到纳秒,并且是不可变对象,推荐用Instant代替Date。
66、DateTimeFormatter与SimpleDateFormat
区别:DateTimeFormatter线程安全,SimpleDateFormat线程不安全。
67、Period(一段时期)
可以用于计算两个 LocalDate对象相差的年数、月数、天。
68、Duration(持续时间)
可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数;支持LocalTime、LocalDateTime、Instant等时间。
69、Arrays工具类
用来操作数组的一个工具类。
sort方法不能接收对象数组,不能进行排序。
copyOfRange()方法结束索引不包括屁股
解决方法:
*让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
*使用下面这个sort方法,创建Comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
public static <T> void sort(T[] arr, Comparator<? super T> c)
自定义排序规则时,需要遵循的官方约定如下:
升序:
如果认为左边对象 大于 右边对象 应该返回正整数如果认为左边对象 小于 右边对象 应该返回负整数如果认为左边对象 等于 右边对象 应该返回0整数
70、Lambda表达式
Lambda表达式是JDK 8开始新增的一种语法形式; 作用:用于简化匿名内部类的代码写法。
//格式
(被重写方法的形参列表) -> {
被重写方法的方法体代码。
}
//Lambda表达式简化setAll方法中匿名内部类
double[] scores = {99.8, 128.0, 100.0};
Arrays.setAll(scores, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {
return scores[value] * 0.8;
}
});
System.out.println(Arrays.toString(scores));
Arrays.setAll(scores, (int value) -> {
return scores[value] * 0.8;
});
//Lambda表达式简化Comparator接口的匿名形式
public static void main(String[] args) {
…
Arrays.sort(students, new Comparator<Student>(){
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() – s2.getAge();
}
});
…
}
Arrays.sort(students, (Student s1, Student s2) ->{
return s1.getAge() – s2.getAge();
});
注意 : Lambda表达式只能简化函数式接口的匿名内部类!!!
Lambda表达式的省略写法(进一步简化Lambda表达式的写法)
参数类型可以省略不写。如果只有一个参数,参数类型可以省略,同时()也可以省略。如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写。
静态方法的引用:
类名::静态方法。
如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
实例方法的引用:
如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。
特定类型的方法引用:
如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
构造器引用:
如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。
71、函数式接口,@FunctionalInterface的注解
有且仅有一个抽象方法的接口。
注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,有该注解的接口就必定是函数式接口。
72:排序算法
解决某个实际问题的过程和方法。
冒泡排序:
每次从数组中找出最大值放在数组的后面去。
确定总共需要做几轮: 数组的长度-1.
每轮比较几次:
i(第几轮) 比较位 次数规律: 数组的长度 – i -1
0 0 1 2 (3次)
1 0 1 (2次)
2 0 (1次)
当前位置大于后一个位置则交换数据
选择排序:
每轮选择当前位置,开始找出后面的较小值与该位置交换
72、查找算法
二分查找:
前提条件:数组中的数据必须是有序的
核心思想:每次排除一半的数据,查询数据的性能明显提高极多!
定义变量记录左边和右边位置。使用while循环控制二分查询(条件是左边位置<=右边位置)循环内部获取中间元素索引判断当前要找的元素如果大于中间元素,左边位置=中间索引+1判断当前要找的元素如果小于中间元素,右边位置=中间索引-1判断当前要找的元素如果等于中间元素,返回当前中间元素索引。
73、正则表达式
就是由一些特定的字符组成,代表的是一个规则。
用途:
一、用来校验数据格式是否合法。
二、在一段文本中查找满足要求的内容。
书写格式:
74、异常
是程序出现问题。
Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来, 说白了,Error是给sun公司自己用的,不是给我们程序员用的,因此我们开发人员不用管它。
Exception:叫异常,它代表的才是我们程序可能出现的问题,所以,我们程序员通常会用Exception以及它的孩子来封装程序出现的问题。运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
抛出异常(throws):
在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。
方法 throws 异常1 ,异常2 ,异常3 ..{
…
}
方法 throws Exception{
}
//Execption代表可以捕获一切异常
捕获异常(try…catch):
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常}...
}
try{
}catch(Exception e){
e.printStackTrace();//直接打印异常对象
}
自定义异常:
Java无法为这个世界上全部的问题都提供异常类来代表, 如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
自定义异常的种类:
作用:
一、用来查询系统bug的关键参考信息
二、可以作为方法内部的一种特殊返回值,以便通知上层调用者,底层的执行情况!
总结:
在开发中异常的常见处理方式是:底层的异常抛出去给最外层,最外层集中捕获处理。
75、collection与map
collection:是单列集合,一个元素包含一个值。
map:是双列集合,一个元素包含二个值。(键值对)
List系列集合:添加的元素是有序、可重复、有索引。
ArrayList/LinkedList:有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。
HashSet:无序、不重复、无索引。
LinkedHashSet:有序,不重复,无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。
Collection的常见方法如下:
- List集合支持的遍历方式for循环(因为List集合有索引)迭代器 增强for循环Lambda表达式
76、迭代器(集合专属)
迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator。
Iterator<E> iterator():得到迭代器对象,默认指向当前集合的索引0。
迭代器集合元素索引越界:NoSuchElementException异常。
remove()删除从底层集合中迭代器返回的最后一个元素。
77、Lambda表达式遍历集合
得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合。作用:简化内部类的写法。
Collection<String> lists = new ArrayList<>();
...
lists.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
}
);
//lambda:
lists.forEach(s -> {
System.out.println(s);
}
);
// lists.forEach(s -> System.out.println(s));
78、LinkedList集合的底层原理
基于双链表实现的。
链表:
链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
特点:
- 查询漫,无论查询哪一个元素都要从头开始找。
- 增删相对于数组比较快。
特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
应用场景:
- 设计队列:
- 队列的特点是:先进先出,后进后出。
- 设计栈:
- 只是对首元素进行增删的时候适合
- 栈的特点是:先进后出,后进先出。
- 数据进入栈模型的过程称为:压/进栈(push)。
- 数据离开栈模型的过程称为:弹/出栈(pop)
- 栈底元素:是瓶子底部。
- 栈顶元素:是瓶子顶部。
79、Set集合
特点:无序:添加数据的顺序和获取出的数据顺序不一致; 不重复; 无索引;
注意:Set要用到的常用方法,基本上就是Collection提供的!!自己几乎没有额外新增一些常用功能!
- HashSet无序、不重复、无索引。LinkedHashSet 有序、不重复、无索引。TreeSet 可排序、不重复、无索引。
80、哈希值(散列表)
就是一个int类型的数值,Java中每个对象都有一个哈希值。同一个类不同对象之间相同的属性成员哈希值是相同的。可以利用这一点去重写hashCode(),优化hashSet去掉内容和hashc相同的对象。
Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。
public int hashCode()://返回对象的哈希码值。
对象哈希值的特点:
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的。不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)。
- int (-21亿多 ~ 21亿多) 45亿个对象
81、HashSet集合的底层原理
基于哈希表实现。哈希表是一种增删改查数据,性能都较好的数据结构。
哈希表:
- JDK8之前,哈希表 = 数组+链表
- JDK8开始,哈希表 = 数组+链表+红黑树
- JDK8开始,当链表长度超过8,且数组长度>=64时,自动将链表转成红黑树
82、二叉树
- 二叉树中,任意节点的度<=2度:每一个节点的子节点数量
- 树高:树的总层数
- 根节点:最顶层的节
- 左子节点
- 右子节点
- 左子树
- 右子树
二叉查找树(二叉排序树):
二叉查找树存在的问题:
当数据已经是排好序的,导致查询的性能与单链表一样,查询速度变慢!
一腿短一只腿长相当于单链表。
平衡二叉树:
在满足查找二叉树的大小规则下,让树尽可能矮小,以此提高查数据的性能。
红黑树:
- 红黑树,就是可以自平衡的二叉树。
- 红黑树是一种增删改查数据性能相对都较好的结构。
83、理解HashSet集合去重复的机制。
HashSet集合默认不能对内容一样的两个不同对象去重复!
比如内容一样的两个学生对象存入到HashSet集合中去 , HashSet集合是不能去重复的!
如何让HashSet集合能够实现对内容一样的两个不同对象也能去重复?
结论:如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法
- 去重原理,当HashSet add一个元素时,先获取这个元素的散列码(hashcode方法),获取元素的哈希值。
- 放计算出的元素的存储位置目前没有任何元素存储,那么该元素可以直接存储在该位置上
- 如果计算出的位置目前已经有其他元素的,那么会调用钙元素的equals方法于该位置的元素在比较一次
- 如果equals返回值是true,那么说明该元素重复,不允许添加
- 如果equals返回值为false,那么说明该元素不重复,那么继续探查下一个位置是否重复,然后重复上面情况s
84、instanceof
是Java的一个二元操作符(运算符),也是Java的保留关键字。它的作用是判断其左边对象是否为其右边类的实例,返回的是boolean类型的数据。用它来判断某个对象是否是某个Class类的实例。
85、hashCode()的写法:
- 首先整理出判断对象相等的属性
- 然后去乘一个尽可能小的正整数,防止最终结果超出整型int的取数范围
- 然后计算[正整数 * 属性的hashCode + 其余某个属性的hashCode]
- 重复步骤
/*
* 重写hashCode()方法
*/
@Override
public int hashCode() {
int result = name.hashCode();
result = 17 * result + sex.hashCode();
result = 17 * result + age.hashCode();
return result;
}
86、LinkedHashSet
有序、不重复、无索引。
基于哈希表(数组、链表、红黑树)实现的。(和其父类hashSet一样)
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
底层基于哈希表,使用链表记录添加顺序。
87、TreeSet(比较器)
特点:不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)底层是基于红黑树实现的排序。已经重写hashCode()和equals(),可以去掉具有重复内容的对象。默认可以排序字符串。
注意:
- 对于数值类型:Integer , Double,默认按照数值本身的大小进行升序排序。
- 对于字符串类型:默认按照首字符的编号升序排序。
- 对于自定义类型如Student对象,TreeSet默认是无法直接排序的。
自定义排序规则:
TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则。
方式一:自然排序让自定义的类(如学生类)实现Comparable<被排序该类的泛型>接口,重写里面的compareTo方法来指定比较规则。
方式二:定制排序通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象,用于指定比较规则。)
public TreeSet(Comparator<? super E> comparator);
两种方式中,关于返回值的规则:
- 如果认为第一个元素 > 第二个元素 返回正整数即可。
- 如果认为第一个元素 < 第二个元素返回负整数即可。
- 如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。
注意:如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。
优点:增删改查性能较好。
88、各个集合的应用场景
89、集合的并发修改异常
90、可变参数
就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型...参数名称;
特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。
好处:常常用来灵活的接收数据。
注意事项:
- 可变参数在方法内部就是一个数组。
- 一个形参列表中可变参数只能有一个
- 可变参数必须放在形参列表的最后面
91、Collections
是一个用来操作集合的工具类
常用静态方法:
Collections只能支持对List集合进行排序
comparable:compareTo()重写,返回值代表的意义与元素排序规则。
92、comparable接口(函数式接口有注解)
唯一方法:compareTo(T o),将此对象与指定的对象进行比较以进行排序。 返回值类型:int。
- 如果认为第一个元素 > 第二个元素 返回正整数即可。
- 如果认为第一个元素 < 第二个元素返回负整数即可。
- 如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。
93、Map集合
应用:需要存储一一对应的数据时,就可以考虑使用Map集合来做
- Map集合称为双列集合,格式:{key1=value1 , key2=value2 , key3=value3 , ...}, 一次需要存一对数据做为一个元素.
- Map集合的每个元素“key=value”称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做“键值对集合”
- Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值
remove()只是删除了元素,键的地址也没有了。get为NULL。
- HashMap集合是一种增删改查数据,性能都较好的集合但是它是无序,不能重复,没有索引支持的(由键决定特点)
- HashMap的键依赖hashCode方法和equals方法保证键的唯一
- 如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的。
Map遍历方式:
- 先 获取全部的键,再通过遍历键去找值。
- 把键值对整体进行遍历(难度大)
- Lambda
package com.itheima.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
* 整体遍历Map的键和值
* */
public class KeyValueTatolFor {
public static void main(String[] args) {
Map<String,Double> map=new HashMap<>();
map.put("蜘蛛精",169.8);
map.put("紫霞",165.8);
map.put("至尊宝",169.5);
map.put("牛魔王",183.8);
// 直接遍历Map键值对
Set<Map.Entry<String,Double>> entries=map.entrySet();
// Set<Map.Entry<String,Double>>应该是数据类型
for (Map.Entry<String, Double> entry : entries) {
String key=entry.getKey();
Double value=entry.getValue();
System.out.println(key+"---->"+value);
}
System.out.println("---------------------");
// 先获取全部键,然后再遍历键获取值 通过键找值遍历,这种方式的效率比较低,因为本身从键取值是耗时的操作。
Set<String> key=map.keySet();
// Set<String>应该是数据类型
for (String s : key) {
System.out.println(map.get(s));
}
System.out.println("-----------------------");
// Lambda表达式
map.forEach((String,Double)->{
System.out.println(String+"-------->"+Double);
});
}
}
94、HashMap
HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。
实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。
- HashMap集合是一种增删改查数据,性能都较好的集合但是它是无序,不能重复,没有索引支持的(由键决定特点)
- HashMap的键依赖hashCode方法和equals方法保证键的唯一
- 如果键存储的是自定义类型的对象,可以通过重写hashCode和equals方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的。
95、LinkedHashmap
底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。
实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap。
96、Treemap
- 特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
- 原理:TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。
TreeMap集合同样也支持两种方式来指定排序规则:
- 让类实现Comparable接口,重写比较规则。
- TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。
97、包装类
在Java中,基本数据类型和对应的包装类之间可以进行自动装箱(Autoboxing)和自动拆箱(Unboxing)操作。自动装箱是指将基本数据类型转换为对应的包装类,自动拆箱是指将包装类转换为对应的基本数据类型。
valueOf();转换成引用数据类型(对象)
parseInt:转换为整数基础数据类型
parseDouble:转换为双精度浮点数基础数据类型
98、Stream
也叫Stream流,是Jdk8开始新增的一套API (java.util.stream.*),可以用于操作集合或者数组的数据。
优势: Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作
实现步骤:
- 先得到集合或者数组的Stream流。
- 然后调用Stream流的方法对数据进行处理。
- 获取处理的结果。
1、获取Stream流
2、Stream流常见的中间方法
中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。
3、Stream流常见的终结方法
终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。
收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回。
Stream流:方便操作集合/数组的手段; 集合/数组:才是开发中的目的。
99、File类
File是java.io.包下的类, File类的对象,用于代表当前操作系统的文件(可以是文件、或文件夹)。
注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据。
创建File类的对象:
- File对象既可以代表文件、也可以代表文件夹。File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的。
- 绝对路径:从盘符开始:File file1 = new File(“D:\itheima\a.txt”);
- 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件。File file3 = new File(“模块名\a.txt”);
File提供的判断文件类型、获取文件信息功能:
File类创建文件的功能:
File类删除文件的功能:
注意:delete方法默认只能删除文件和空文件夹,删除后的文件不会进入回收站。
File类提供的遍历文件夹的功能:
使用listFiles方法时的注意事项:
- 当主调是文件,或者路径不存在时,返回null
- 当主调是空文件夹时,返回一个长度为0的数组
- 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
- 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
- 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
File里为null则是没有地址,exist()方法是判读地址里面的内容是否为空。
100、IO流
用于读写数据的(可以读写文件,或网络中的数据…)
101、方法递归
- 递归是一种算法,在程序设计语言中广泛应用。
- 从形式上说:方法调用自身的形式称为方法递归( recursion)。
递归的形式:
直接递归:方法自己调用自己。间接递归:方法调用其他方法,其他方法又回调方法自己。
使用方法递归时需要注意的问题:
递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出错误。
递归算法三要素:
- 递归的公式: f(n) = f(n-1) * n;
- 递归的终结点:f(1)
- 递归的方向必须走向终结点:
102、final
103、抽象类
在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
注意事项:
- 抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类
- 类有的成员(成员变量、方法、构造器)抽象类都具备。
- 抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
104、接口
public interface 接口名 {
// 成员变量(常量)
// 成员方法(抽象方法)
}
修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
接口的好处:
- 弥补了类单继承的不足,类可以同时实现多个接口。
- 让程序可以面向接口编程,这样既不用关心实现的细节,也可以灵活方便的切换各种实现。
JDK 8开始,接口新增了三种形式的方法:
public interface A{
/**
* 1、默认方法(实例方法):使用用default修饰,默认会被加上public修饰。
* 注意:只能使用接口的实现类对象调用
*/
default void test1(){
...
}
/**
* 2、私有方法:必须用private修饰(JDK 9开始才支持)
*/
private void test2(){
...
}
/**
* 3、类方法(静态方法):使用static修饰,默认会被加上public修饰。
* 注意:只能用接口名来调用。
*/
static void test3(){
...
}
}
接口其他注意事项(了解):
1、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。2、一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。3、一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。