JavaSE个人学习笔记(2020年10月)
学习内容和时间:JavaSE课程(视频来自于b站Idea黑马)
目录
第一部分:Java语法
1、this指针
this 关键字用来表示当前对象本身,或当前类的一个实例,通过 this 可以调用本对象的所有方法和属性。
总结:
- this用在本类的【成员方法】中,可以访问本类的【成员变量】;
- this用在本类的【成员方法】中,可以访问本类的【另一个成员方法】;
- this用在本类的【构造方法】中,可以访问本类的【另一个构造方法】;
注意事项:
1、this(…)调用必须是构造方法的第一句;
2、一个构造方法最多调用一次this构造;
3、super和this两种构造调用,不能同时使用(super用在本类的【构造方法】中,用来访问【父类的构造方法】)。
2、重写和重载
2.1 重载(overload)
重载(overload) 是在一个类中,名称相同,参数列表【不同】的方法。
最常用的地方就是构造器的重载。
方法的重载与如下有关:
- 参数个数不同;
- 参数类型不同;
- 变量的多个类型的顺序不同。
方法的重载与如下无关:
- 参数的名称;
- 方法的返回值类型。
2.2 重写(override)
重写(override):也叫作覆盖。是指在继承关系中,名称相同,参数列表也【相同】的方法。
注意事项:
- 父子类的覆盖的方法必须【名称一样】,【参数列表一样】(可以使用@override来检测是否是有效的覆盖重写);
- 覆盖重写的子类方法的返回值的范围可以【小于等于】父类方法的返回值范围(如:java.lang.String类【小于等于】java.lang.Object类);
- 子类方法的权限必须【大于等于】父类方法的权限:权限排序(从大到小):public > protected > (default) > private(这里的(default)不是关键词default,而是什么都不写);
- 子类方法抛出异常的范围必须【小于等于】父类抛出的异常。
- 构造方法不能重写
- 如果父类方法访问修饰符为
private/final/static
,则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明。 - 发生阶段:运行期。重载的发生阶段在编译期。
3、static
static关键字的作用:在没有创建对象的情况下,来调用方法(或变量)。
3.1 static变量
静态变量和非静态变量的区别:
1、所有的对象共享一个静态变量,在内存中只有一个副本,当且仅当在第一次使用到本类时,静态变量会被初始化。
2、每个对象都有各自的非静态变量,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
3、可以直接通过类名直接调用静态变量【推荐】,不必通过对象【不推荐】;
3.2 static方法
静态方法:
1、是一种不能向对象施加操作的方法,换句话说:没有隐式参数,不能用this;
2、与静态变量一样,可以直接通过类名直接调用静态方法【推荐】,不必通过对象【不推荐】;
3、静态方法不属于对象,而属于类;
4、对于本类中的静态方法,调用时可以省略本类名称;
5、静态方法不要去访问非静态变量(如成员变量)。
3.3 static代码块
只有当第一次使用到本类时,静态代码块才会执行唯一的一次;
作用:用于一次性地对静态成员变量进行赋值。
4、final关键字
final关键字代表最终的、不可改变的。
常见的4种用法:
1、用来修饰一个类;
2、用来修饰一个方法;
3、用来修饰一个局部变量;
4、用来修饰一个成员变量;
4.1 final用来修饰一个类
使用格式:
public final class 类名称{
//...
}
含义:
当前这个类一定不能有任何子类,即不能使用final类作为任何一个类的父类。
注意事项:一个类如果是final,那么其中所有的成员方法都无法被覆盖重写。
4.2 final用来修饰一个方法
使用格式:
public final 返回值类型 方法名称(参数列表){
//方法体
}
含义:
当final关键字用来修饰一个方法时,这个方法就是最终方法,不能再被覆盖重写。
注意事项:
对于类和方法来说,abstract关键字和final关键字不能同时使用,因为相互矛盾。
4.3 final用来修饰一个局部变量
1、一旦final用来修饰一个局部变量,那么这个变量就不能进行更改。
2、“一次赋值,终生不变”。
3、对于基本类型来说,“终生不变”说的是变量当中的值不可改变。
4、对于引用类型来说,“终生不变”说的是变量所指的地址值不可改变,内容是可以改变的。
4.4 final用来修饰一个成员变量
- 一旦final用来修饰一个成员变量,那么这个变量就不能进行更改;
- 与final关键字修饰局部变量不同,final用来修饰一个成员变量,在定义时必须同时进行赋值;
- 进行赋值的方式二者选其一:要么直接赋值;要么通过构造方法赋值;
- 通过构造方法进行赋值时,必须保证类中所有重载的构造方法,最终都会对final修饰的成员变量进行赋值。
4.5 权限修饰符整理
public > protected > (default) > private
同一个类(我自己) yes yes yes yes
同一个包(我邻居) yes yes yes no
不同包子类(我儿子) yes yes no no
不同包非子类(陌生人) yes no no no
注意事项:(default)并不是关键字"default",而是不写,留空。
5、Scanner类的基本使用方法
1、调包:import java.util.Scanner;
2、创建:Scanner sc = new Scanner(System.in);
3、使用方法:
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
String str = sc.next();
4、使用建议:保证一个变量只会使用一次的时候,可以使用匿名变量;
int num = new Scanner(System.in).nextInt();
6、Random类的基本使用方法
import java.util.Random;
Random r = new Random();
int num = r.nextInt(10);//随机取[0,10)范围内的所有数字
int num = r.nextInt();//随机取int范围内的所有数字
7、String类的基本使用方法
7.1 字符串对象的构建
public static void main(String[] args) {
/*
创建字符串的常见3+1种方式:
3种构造方法+1种直接创建
*/
//使用【空参】构造
String str1 = new String();
System.out.println(str1);
//根据【字符数组】创建字符串
char[] charArray = {'A','B','C'};
String str2 = new String(charArray);
System.out.println(str2);//ABC
//根据【字节数组】创建字符串
byte[] byteArray = {97, 98, 99};
String str3 = new String(byteArray);
System.out.println(str3);//abc
//直接创建,注意:直接使用双引号创建的字符串也是字符串对象!
String str4 = "hello";
System.out.println(str4);//hello
}
7.2 字符串常量池
1、字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中
2、注意事项:对于引用类型来说,“==”进行的是地址值的比较
7.3 字符串的比较方法
/*
public boolean equals(Object obj):参数可以是任何对象,但是只有参数是字符串并且内容相同时才会返回true
注意事项:
1、任何对象都能被Object进行接受;
2、equals方法具有对称性:a.equals(b)和b.equals(a)相同
3、当比较的一方有常量时,推荐将常量放在前面
public boolean equalsIgnoreCase(Object obj):忽略大小写,进行内容比较。
*/
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
char[] charArray = {'h','e','l','l','o'};
String str3 = new String(charArray);
System.out.println(str1.equals(str2));//true
System.out.println(str1.equals(str3));//true
System.out.println("hello".equals(str1));//true【推荐】
System.out.println(str1.equals("hello"));//true【不推荐】
//忽略大小写进行比较
String str4 = "Hello";
System.out.println(str1.equals(str4));//false
System.out.println(str1.equalsIgnoreCase(str4));//true
}
7.4 字符串获取相关的方法
public static void main(String[] args) {
/*
String当中与获取相关的常用方法有:
public int length():获取字符串当中含有的字符个数,返回字符串的长度
public String concat(String str):将当前字符串与参数字符串拼接并返回新的字符串
public char charAt(int index):获取指定索引位置的单个字符
public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置(从0开始)。如果没有,则返回-1
*/
int length = "dfvdjksfhdsiofhdsjkfhksljd".length();
System.out.println(length);//26
//拼接字符串
String str1 = "hello";
String str2 = "world";
String str3 = str1.concat(str2);
System.out.println(str1);//hello原封不动
System.out.println(str2);//world原封不动
System.out.println(str3);//helloworld
char ch = "Hello".charAt(1);
System.out.println(ch);//e
String original = "HelloWorldHelloWorld";
int index = original.indexOf("llo");
System.out.println(index);//2
System.out.println(original.indexOf("lli"));//-1,表示不存在
}
7.5 字符串的截取方法
public String substring(int index): //截取从参数位置一直到字符串末尾,并返回;
public String substring(int begin,int end)://截取从[begin,end)的中间的字符串,并返回;
7.6 字符串的转换方法
public char[] toCharArray(): //获得当前字符串拆封成字符数组并返回
public byte[] getBytes(): //获得当前字符串底层的字节数组并返回
public String replace(CharSequence oldString, CharSequence newString): //将字符串中出现的所有老字符串替换成为新的字符串,并将替换之后的字符串返回
7.7 字符拆的分割方法
public static void main(String[] args) {
/*
分割字符串的方法:
public String[] split(Stirng regex):按照参数的规则,将字符串分割成若干部分
注意事项:split方法的参数实际上是一个“正则表达式”。
如果想用英文“.”进行分割的话,要用“\\.”
*/
String str1 = "aaa,bbb,ccc,ddd";
String[] array1 = str1.split(",");
for (int i = 0; i < array1.length; i++) {
System.out.println(array1[i]);//aaa bbb ccc ddd
}
}
8、Arrays类的基本使用方法
java.util.Arrays是一个与数组相关的工具类,里面提供了用于实现数组常见操作的静态方法;
public static String toString(数组)://将参数数组变成字符串;
public static void sort(数组)://将参数数组按照默认升序(从小到大)进行排序;
/*
注意事项:如果是数值,sort默认按照升序从小到大;
如果是字符串,sort默认按照字母升序从小到大;
如果是自定义的类型,那么这个自定义的类需要有Comparable或者Comparator接口支持;
*/
9、Math类的基本使用方法
java.util.Math是一个与数学相关的工具类,里面提供了用于实现数学运算相关的静态方法;
public static double abs(double num): //获得绝对值;
public static double ceil(double num): //向上取整;
public static double floor(double num): //向下取整;
public static long round(double num): //四舍五入;
Math.PI: //圆周率(double)
10、继承
10.1 继承中的成员变量的访问特点
1、使用子类对象直接访问成员变量:优先使用子类对象中的成员变量;如果没有,则往上(父类)找。
2、使用子类方法间接访问成员变量:该方法属于谁(定义在哪里),就优先使用谁;如果没有,则往上(父类)找。
10.2 区分子类方法中的重名的三种变量
1、调用局部变量:直接写成员变量
2、调用本类的成员变量:this.成员变量
3、调用父类的成员变量:super.成员变量
10.3 继承中的成员方法的访问特点
1、访问成员方法的规则:先优先使用本对象中的成员方法;如果没有,则向上找。
2、注意事项: 无论是成员变量还是成员方法,如果没有找到,都是向上(父类)找,绝对不会向下(子类)找。
10.4 继承中的方法的重写,以及与重载的区别
具体内容在第一部分第二节。
10.5 继承中构造方法的访问特点
1、子类构造可以通过super可以实现对父类构造器的调用;
2、super调用构造器的语句必须是子类构造器中的第一句;一个子类构造不能多次调用super构造。
3、如果没有super调用构造器,会默认添加一个super()(没有参数)的构造器。所以一定是先调用父类构造,再调用子类构造。
10.6 super关键字总结
1、在子类的成员方法中,访问父类的成员变量;
2、在子类的成员方法中,访问父类的成员方法;
3、在子类的构造方法中,访问父类的构造方法;
10.7 this关键字总结
this 关键字用来表示当前对象本身,或当前类的一个实例,通过 this 可以调用本对象的所有方法和属性。
总结:
- this用在本类的【成员方法】中,可以访问本类的【成员变量】;
- this用在本类的【成员方法】中,可以访问本类的【另一个成员方法】;
- this用在本类的【构造方法】中,可以访问本类的【另一个构造方法】;
注意事项:
1、this(…)调用必须是构造方法的第一句;
2、一个构造方法最多调用一次this构造;
3、super和this两种构造调用,不能同时使用(super用在本类的【构造方法】中,用来访问【父类的构造方法】)。
11、抽象
11.1 抽象类和抽象方法
1、抽象类:抽象方法所在的类必须是抽象类。在class之前写上abstract即可。
2、抽象方法:可以理解为起到一个占位的作用,具体的实现可以在子类中完成。加上abstract关键字,并且去掉大括号即可。
11.2 抽象类和抽象方法的使用
1、不能直接new创建一个抽象类;
2、需要用一个子类来继承这个抽象类;
3、子类必须覆盖抽象父类中的所有抽象方法;
4、new创建一个子类对象进行使用。
11.3 抽象类和抽象方法的注意事项
1、抽象类不能创建对象,必须要有一个子类来继承这个对象;
2、抽象类中可以有构造方法,是用来提供给子类创建对象时,初始化父类使用的;
3、抽象类中不一定要包含有抽象方法,但是有抽象方法的一定是抽象类;
4、子类在继承某个抽象类时,必须要覆盖这个抽象类中的所有抽象方法(除非这个子类也是抽象类)。
12、接口
接口是对类的一组需求的描述,这些类要遵从接口描述的统一格式进行定义。
12.1 接口的基本格式
public interface 接口名称{
//接口内容
}
12.2 接口中抽象方法的定义、实现步骤
接口中最重要的内容就是其中的抽象方法。
接口中抽象方法的格式:
public abstract 返回值类型 方法名称(参数列表);
注意事项:
- 接口中的抽象方法,修饰符必须是两个固定的关键词:public abstract;
- 这两个固定的关键词可以省略不写;
接口的实现步骤:
- 接口不能直接使用,必须有一个"实现类"来"实现"该接口;
- 接口类的实现类必须覆盖接口中的【所有】抽象方法;
- 创建实现类的对象,进行使用。
接口实现类的格式:
public class 实现类名称 implements 接口名称{
//...
}
注意事项:
如果实现类没有覆盖接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
12.3 接口默认方法的定义和使用
从java8开始,接口中允许定义【默认方法】
使用格式:
public default 返回值类型 方法名称(参数列表){
//方法体
}
注意事项:
- 接口中的默认方法,是为了解决接口中的【升级问题】;
- 接口的默认方法,可以通过接口的实现类对象,【直接调用】
- 接口的默认方法,也可以通过接口的实现类进行【覆盖重写】
12.4 接口静态方法的定义和使用
从java8开始,接口当中允许定义【静态方法】。
使用格式:
public static 返回值类型 方法名称(参数列表){
//方法体
}
注意事项: 不能通过接口实现类的【对象】来调用接口当中的【静态方法】
正确用法: 通过接口名称,直接调用其中的静态方法
使用格式:接口名称.静态方法名(参数)
12.5 接口私有方法定义和使用
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的
解决方案:
从java9开始,接口中允许定义【私有方法】。
1、普通私有方法:解决多个默认方法之间重复代码的问题。
格式:
private 返回值类型 方法名称(参数列表){
方法体
}
2、静态私有方法:解决多个静态方法之间重复代码的问题。
格式:
private static 返回值类型 方法名称(参数列表){
方法体
}
12.6 接口的常量的定义和使用
接口当中也可以定义"成员变量",但是必须使用public static final三个关键字进行修饰
从效果上看,这实际上是定义了接口的一个【常量】
使用格式:
public static final 数据类型 常量名称 = 数据值;
注意事项:
- 接口当中的常量,可以省略public static final;
- 接口当中的常量,必须在定义的同时进行赋值;
- 接口当中的常量,推荐使用大写,并且使用下划线进行分隔。
12.7 继承父类并实现多个接口的注意事项
注意事项:
- 接口是没有静态代码块或者构造方法的;
- 一个类的直接父类是【唯一】的,但是一个类可以同时实现【多个接口】;
- 如果实现类所实现的多个接口当中,存在重复的【抽象方法】,那么只需要覆盖重写【一次】即可;
- 如果实现类没有覆盖重写所有接口中的所有抽象方法,那么这个实现类也是抽象类;
- 如果实现类所实现的多个接口当中,存在重复的【默认方法】,那么实现类【一定】要对冲突的默认方法进行覆盖重写;
- 如果实现类的【直接父类】当中的方法,和【接口】当中的【默认方法】产生了冲突,优先使用【直接父类】当中的方法。
12.8 接口之间的多继承关系
- 类与类之间是单继承的。直接父类只有一个;
- 类与接口之间是多实现的。一个类可以实现多个接口;
- 接口与接口之间是多继承的。
注意事项:
- 多个父接口当中的抽象方法如果重复,没关系,只需要覆盖重写【一次】即可;
- 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】
13、多态性
13.1 多态性的概述
多态性的体现:父类引用 指向 子类对象
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 实现类名称();
13.2 多态中成员变量的使用特点
- 直接调用:直接通过【对象】访问成员变量:看等号左边是谁,优先用谁,没有则向上找;
- 间接调用:间接通过【成员方法】访问成员变量:看该方法属于谁(子类覆盖重写,则属于子),优先用谁,没有则向上找;
- 口诀:编译看左边,运行还是看左边。
13.3 多态中成员方法的使用特点
- 看new的是谁,就优先用谁,没有则向上找;
- 口诀:编译看左边,运行看右边。
13.4 对象的向上转型
- 对象的向上转型就是指:父类引用 指向 子类对象;
- 对象的向上转型一定是安全的。
13.5 对象的向下转型
问题描述:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
解决方案:用对象的向下转型【还原】
格式:子类名称 对象名 = (子类名称)父类对象
注意事项:
- 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫;
- 如果对象创建的时候本来不是猫,现在向下转型成为猫,会报错。
13.6类型判断:instanceof
作用:用以判断一个父类引用的对象,本身是什么子类?
格式:对象 instanceof 类名称(会返回一个boolean,用以判断对象是否能够被当作是后面的类名称的实例)
14、内部类
14.1 内部类的概述和分类
概述:如果一个事物中包含着另外一个事物,那么这就是一个外部类中包含着一个内部类。
分类:
- 成员内部类
- 局部内部类(包含匿名内部类)
14.2 成员内部类的定义和使用
定义格式:
修饰符 class 外部类名称{
//...
修饰符 class 内部类名称{
//...
}
//...
}
注意事项: 内用外,随意访问;外用内,需要内部类对象
使用内部类的方法:
- 间接方法:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法
- 直接方法:【格式】:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称()
14.3 内部类成员变量的访问
在内部类中,想要访问重名的【局部变量】,直接:重名变量名。
想要访问重名的【内部类成员变量】,需要:this.重名变量名。
想要访问重名的【外部类成员变量】,需要:外部类名称.this.重名变量名。
14.4 局部内部类的定义
概述:如果一个类是定义在一个【方法】内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能够使用这个类,出了这个方法的范围就不能使用。
定义格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 内部类名称{
//...
}
}
}
注意事项一: 定义一个类的时候,权限修饰符的规则:
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
- 局部内部类:什么都不能写
注意事项二: 如果希望局部内部类访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。
备注: 从java8开始,只要这个局部变量事实不变,那么这个final就可以省略不写。
14.5 匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
那么这种情况下就可以省略该类的定义,而改为使用【匿名内部类】。
定义格式:
接口名称 对象名 = new 接口名称(){
//覆盖重写所有的抽象方法
};
对格式进行解析:
- new代表创建对象的动作;
- 接口名称()就是匿名内部类所要实现的接口;
- {…}才是匿名内部类的内容;
注意事项:
- 匿名内部类,在【创建对象】的时候,只能使用唯一的一次,即只能创建一个对象。如果希望多次创建对象,而且类的内容是相同的话,那么就必须使用单独定义的实现类。
- 匿名对象,在【调用方法】的时候,只能调用唯一的一次,即只能调用一个方法。如果希望同一个对象,多次调用方法,那么必须给对象起名。
- 匿名内部类省略了【实现类(子类)名称】,但是匿名对象省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!!!