第一章 面向对象基础
1.1 概述
-
面向过程与面向对象:
- 面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节
- 面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做
- 举例:面向过程就是手洗衣服;面向对象就是把衣服丢给洗衣机,这里的对象就是洗衣机。
-
面向对象三大特征:封装、继承、多态
-
类和对象:
- 类是一组属性和行为的集合
- 类是对象的模板,对象是类的实例。
-
成员变量和成员方法:
- 成员变量就是属性,成员方法就是行为
- 成员变量是直接定义在类当中的,且在方法外面
- 成员方法不要写static关键字(如果写了static关键字,那么该方法就是静态方法,不属于对象,而属于类)
-
成员变量和局部变量:
- 定义的位置不一样(局部变量在方法的内部,成员变量在方法的外部,直接写在类当中)
- 作用范围不一样(局部变量只有方法当中才可以使用,成员变量整个类全都可以通用
- 默认值不一样(局部变量没有默认值,成员变量有默认值)
- 内存的位置不一样
- 生命周期不一样
-
this关键字:通过谁调用的方法,谁就是this。
-
一个标准的类通常拥有四个组成部分:
- 所有的成员变量都要使用private关键字修饰
- 编写一个无参数的构造方法
- 编写一个全参数的构造方法
- 为每一个成员变量编写一对get/set方法
这样标准的类也叫做 Java Bean
1.2 三大特性
1.2.1 封装性
- 方法就是一种封装
- 关键字private也是一种封装(一旦使用private进行修饰,那么本类当中仍然可以随意访问,但是,超出本类范围之外就不能再直接访问了)
1.2.2 构造方法
-
定义:专门用来创建对象的方法,当我们通过关键字new来创建对象的时候,其实就是在调用构造方法
-
格式:
public 类名称(参数类型 参数名称){ 方法体 }
-
注意事项:
- 构造方法的名称必须和所在的类名称完全一样
- 构造方法不要写返回值类型,连void都不写
- 构造方法不能使用return
- 如果没有编写任何构造方法,编译器会默认赠送一个构造方法
- 一旦编写了至少一个构造方法,编译器不再赠送
- 构造方法也是可以进行重载的
1.2.3 匿名对象
- 定义:只有右边的对象,没有左边的名字和赋值运算符。
- 格式:new 类名称()
- 注意事项:匿名对象只能使用唯一的一次,下次再用不得不再创建一个新对象。
- 使用建议:如果确定有一个对象只需要使用唯一的一次,就可以用匿名对象。
使用匿名对象可以进行传参 也可作为返回值
1.2.4 static关键字
-
一旦用了static关键字,那么这样的内容不再属于对象自己,而是属于类的,所以凡是本类的对象,都共享同一份。
-
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它;如果有了static关键字,那么不需要创建对象,直接就能通过类名称来使用它。
例如:静态变量:类名称.静态变量 静态方法:类名称.静态方法()
-
注意事项:
- 静态不能直接访问非静态(因为在内存中是先有静态内容,后有非静态内容)
- 静态方法当中不能用this(因为this代表当前对象,而静态方法与对象无关)
-
代码:
public class MyClass { int num; // 成员变量 static int numStatic; // 静态变量 // 成员方法 public void method(){ System.out.println("这是一个普通的成员方法"); System.out.println(numStatic); // 成员方法可以访问静态变量 } // 静态方法 public static void methodStatic(){ System.out.println("这是一个静态方法"); System.out.println(numStatic); // 静态方法可以访问静态变量 // System.out.println(num); // 错误! 静态方法不能直接访问非静态(重点) // System.out.println(this); // 错误! } }
-
静态代码块:
-
格式:
public class 类名称{ static{ // 静态代码块的内容 } }
-
特点:
- 当第一次用到本类时,静态代码块执行唯一的一次。
- 静态代码块比构造方法先执行。
-
典型用途:用来一次性地对静态成员变量进行赋值。
-
1.2.5 继承性
-
继承主要解决的问题就是:共性抽取。
-
特点:
- 子类可以拥有父类的内容
- 子类还可以拥有自己专有的内容
-
格式:
// 定义父类的格式: public class 父类名称{ } // 定义子类的格式 public class 子类名称 extends 父类名称{ }
-
注意事项:
-
在父子类继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接通过子类对象访问成员变量(对象是谁,就优先用谁,没有则往上找)
- 间接通过成员方法访问成员变量(该方法属于谁,就优先用谁,没有则往上找)
-
super关键字:
- 在子类中想调用父类的成员变量,使用:super.成员变量名
- 在子类中想调用父类的成员方法,使用:super.成员方法名()
- 在子类中调用父类构造方法,使用:super()
-
方法重写(override):
- 在继承关系中,方法的名称一样,参数列表也一样。
- 重写的方法前面加上@Override,用来检测重写是否有效
- 子类方法的返回值类型小于等于父类方法的返回值类型范围(例如:String<Object)
- 子类方法的权限必须 大于等于父类方法的权限修饰符。(public>protected>(default)>private
-
父子类构造方法的访问特点:
-
子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用父类构造后执行子类构造
-
可以通过super关键字来调用父类重载构造。
-
super的父类调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造(易错点)
总结:子类必须调用父类构造方法,不写就会赠送一个super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
-
-
java继承的三大特点:
- java语言是单继承的。(一个类的直接父亲只有唯一一个)
- java语言可以多级继承。
- 一个子类的直接父亲是唯一的,但是一个父类可以拥有很多个子类
-
1.2.6 抽象类
- 抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
- 抽象类:抽象方法所在的类,必须是抽象类才行,在class之前写上abstract即可。(不是一定有抽象方法)
- 如何使用抽象类和抽象方法:
- 不能直接创建new抽象类对象。
- 必须用一个子类来继承抽象类。
- 子类必须覆盖重写抽象父类中所有的抽象方法。
- 创建子类对象进行使用。
1.2.7 接口
-
定义:就是多个类的公共规范。
-
格式:
// 接口是一个引用数据类型,最重要的内容就是其中的:抽象方法 public interface 接口名称{ // 接口内容 } /* 如果是java7,那么接口可以包含的内容有: 1.成员变量(其实是常量) 2.抽象方法 如果是java8,还可以额外包括有 3.默认方法 4.静态方法 如果是java9,还可以额外包括有 5.私有方法 */
-
接口中的内容:
-
抽象方法:
-
定义:
- 格式:public abstract 返回值类型 方法名称(参数列表);
- 注意事项:
- 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
- 这两个关键字修饰符,可以选择性的省略。(不推荐)
- 方法的三要素,可以随意定义。
// 以下四种定义抽象方法的形式都正确 public abstract void method(); abstract void method(); public void method(); void method();
-
使用:
-
步骤:
-
接口不能直接使用,必须有一个“实现类”来“实现”该接口
格式:public class 实现类名称 implements 接口名{}
-
接口的实现类必须覆盖重写(实现)接口中所有的抽象方法
-
创建实现类的对象进行使用
-
-
-
注意事项:如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
-
-
默认方法
- 格式:public default 返回值类型 方法名称(参数列表){ 方法体 }
- 备注:接口当中的默认方法,可以解决接口升级的问题
- 注意事项:
- 接口的默认方法,可以通过接口实现类对象,直接调用
- 接口的默认方法,也可以被接口实现类进行覆盖重写
-
静态方法
- 格式:public static 返回值类型 方法名称(参数名称){ 方法体 }
- 使用:
- 格式:接口名称.静态方法名(参数)
- 注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
-
私有方法
- 普通私有方法:
- 格式:private 返回值类型 方法名称(参数列表){ 方法体 }
- 解决多个默认方法之间重复代码问题
- 静态私有方法:
- 格式:private static 返回值类型 方法名称(参数列表){ 方法体 }
- 解决多个静态方法之间重复代码问题
- 注意:private方法只有接口自己才能调用,不能被实现类或别人使用。
- 普通私有方法:
-
常量:
- 格式:public static final 数据类型 常量名称 = 数据值
- 注意:
- 一旦使用final关键字修饰,说明不可改变。
- 接口中的常量,可以省略public static final。
- 接口中的常量,必须进行赋值,不能不赋值。
- 接口中常量的名称,推荐使用完全大写的字母,用下划线进行分隔
-
-
使用接口的时候,需要注意:
- 接口是不能有静态代码块和构造方法的。
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
- 如果实现类所实现的多个接口当中,存在重复的抽象方法,只需要覆盖重写一次即可。
- 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
- 一个类如果直接父类当中的方法,和接口当中的默认方法发生了冲突,优先用父类中的方法。
1.2.8 类与接口总结
- 类与类之间是单继承的,即直接父类只有一个。
- 类与接口之间是多实现的,即一个类可以实现多个接口。
- 接口与接口之间是多继承的。
- 注意:
- 多个父接口当中的抽象方法如果重复,没有关系
- 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写【必须带default关键字】
- 注意:
- 类和接口都可作为成员变量类型。
1.2.9 多态性
-
extends继承或者implements实现,是多态性的前提。
-
定义:一个对象拥有多种形态。
-
格式:
// 代码中体现多态性,其实就是一句话:父类引用指向子类对象 /* 格式:(左父右子) 父类名称 对象名 = new 子类名称(); 或者 接口名称 对象名 = new 实现类名称(); */
-
成员变量和成员方法访问特点:和继承一样。
- 口诀:(左边指的是父类,右边指的是子类)
- 成员变量:编译看左边,运行还看左边。
- 成员方法:编译看左边,运行看右边
- 口诀:(左边指的是父类,右边指的是子类)
-
好处:无论右边new的时候换成哪个子类对象,等号左边调用方法都不会变化。
-
弊端:不能使用子类或者实现类特有的方法。
-
对象的向上转型:(其实就是多态写法)
- 格式:父类名称 对象名 = new 子类名称();
- 含义:右侧创建一个子类对象,把它当做父类来看待使用
- 注意事项:
- 向上转型一定是安全的。
- 从小范围转向了大范围。
-
对象的向下转型:(其实是一个还原的动作)(重点)
- 格式:子类名称 对象名 = (子类名称) 父类对象;
- 含义:将父类对象,还原成为本来的子类对象。
-
instanceof关键字:
- 格式:父类对象 instanceof 子类名称
- 含义:会返回一个boolean值,也就是判断父类引用对象本来是不是该子类
- 用处:向下转型的时候一定要利用instanceof进行判断。
1.2.10 final关键字
- 代表最终、不可改变的
- 用法:
- 可以用来修饰一个类
- 格式: public final class 类名称{}
- 含义:当前这个类不能有任何的子类(太监类)
- 可以用来修饰一个方法
- 格式:修饰符 final 返回值类型 方法名称(参数列表){}
- 含义:这个方法就是最终方法,也就是不能被覆盖重写
- 注意:对于类、方法来说,abstract关键字和final关键字不能同时使用。
- 可以用来修饰一个局部变量
- 格式:final 数据类型 变量名 = 数值;
- 含义:这个变量就不能进行更改(一次赋值,终生不变)
- 注意:不可变对于基本数据类型来说,数据不可改变;对于引用数据类型来说,地址值不可改变
- 可以用来修饰一个成员变量
- 格式:修饰符 final 数据类型 变量名 [= 数值];
- 注意:
- 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了
- 对于final的成员变量,那么使用直接赋值,要么通过构造方法赋值
- 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值
- 可以用来修饰一个类
1.2.11 四种权限修饰符
-
定义一个类的时候,权限修饰符选择:
- 外部类:public/(default)–指什么都不写,而并不是使用关键字default
- 成员内部类:都可以
- 局部内部类:什么都不能写
public > protected > (default) > private 同一个类 y y y y 同一个包 y y y n 不同包子类 y y n n 不同包非子类 y n n n
1.2.12 内部类
-
成员内部类:(在方法外面定义)
-
格式:修饰符 class 外部类名称{
修饰符 class 内部类名称{
// …
}
// …
}
-
使用:
- 间接方式:在外部类的方法当中,使用内部类,然后main只是调用外部类的方法
- 直接方式:记住这个公式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称()
-
注意:
- 内用外,随意访问;外用内,需要内部类对象
- 如果出现了成员变量名同名现象,访问外部类成员变量的方式:外部类名称.this.成员变量名
-
-
局部内部类:(在方法里面定义)
-
格式:修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数列表){
class 局部类名称{
// …
}
}
}
-
注意:
- 只有当前所属的方法才能使用它,出了这个方法就不能用了。
- 这个内部类的修饰符什么都不能写。
- 如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。(也就是只能赋值一次,不能再进行修改,等同于加上了final关键字)
-
-
匿名内部类(属于局部内部类):
-
为什么会出现匿名内部类?
答:使用多态来创建对象的时候,如果接口的实现类(或者是父类的子类)只需要使用唯一一次,那么这种情况下就可以省略掉该类的定义,而改为使用匿名内部类。
-
格式:接口名称 对象名 = new 接口名称(){
// 覆盖重写所有抽象方法
}; 对比一下多态的格式:
接口名称 对象名 = new 实现类名称();
-
1.2.13 包装类
- 定义:使用一个类,把基本类型的数据装起来,并在类中定义一些方法,这个类叫包装类。
- 列举:
基本类型 包装类(引用类型)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
注意:如果希望向集合ArrayList中存储基本类型数据,必须使用基本类型对应的包装类。
-
装箱与拆箱:- 装箱:从基本类型转换为对应的包装类对象。
- 构造方法:Integer(int value)
- 静态方法:valueOf(int value)
- 拆箱:从包装类对象转换为对应的基本类型。
- 成员方法:int intValue()
- 装箱:从基本类型转换为对应的包装类对象。
-
自动装箱与自动拆箱:基本类型的数据和包装类之间可以自动的相互转换
-
基本数据类型与字符串类型之间的转换:
-
基本类型->字符串:
- 基本类型的值+"" (常用)
- static String toString(int i):返回一个表示指定整数的String对象(包装类的静态方法)
- static String valueOf(int i):返回int参数的字符串表示形式 (String类的静态方法)
-
字符串->基本类型:使用包装类的静态方法parseXXX(“数值类型的字符串”)
Integer类:static int parseInt(String s)
Double类:static double parseDouble(String s)
-
第二章 常用API
2.1 String类
-
特点:
- 字符串的内容永不可变。(重点)
- 字符串是可以共享使用的。
- 字符串效果上相当于是char[]字符数组,但是底层原理是byte[]字节数组。
-
创建字符串的常见3+1种方式:
- 三种构造方法:
- public String():创建一个空白字符串,不含有任何内容
- public String(char[] array):根据字符数组的内容来创建对应的字符串
- public String(byte[] array):根据字节数组的内容来创建对应的字符串
- 一种直接创建:String str = “hello”;
- 三种构造方法:
-
常量池:程序中直接写上的双引号字符串,就在字符串常量池中。(new出来的字符串不在常量池中)
-
常用方法:
// == 是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法: public boolean equals(Object obj) public boolean equalsIgnoreCase(String str) // 字符串获取相关内容的方法: public int length(): 获取字符串当中含有的字符个数,即字符串长度 public String concat(String str): 将当前字符串和参数字符串拼接后成为返回值新的字符串 public char charAt(int index): 获取指定索引位置的单个字符。(索引从0开始) public int indexOf(String str): 查找参数字符串在本字符串中首次出现的索引位置,没有返回-1 // 字符串的截取方法: public String substring(int index): 截取从参数位置一直到字符串末尾,返回新字符串 public String substring(int begin,int end): 截取从begin开始,一直到end结束,左闭右开 // 字符串中与转换相关的方法: public char[] toCharArray(): 将当前字符串拆分成为字符数组作为返回值 public byte[] getBytes(): 获得当前字符串底层的字节数组作为返回值 public String replace(CharSequence oldString,CharSequence newString): 将所有出现的老字符串替换成为新的字符串,返回替换之后的新字符串作为结果 (CharSequence就是说可以接受字符串类型) // 分割字符串的方法: 使用\\ 来对 * ^ | . 等特殊符号进行转义 public String[] split(String regex): 按照参数的规则,将字符串切分成为若干部分 // 字符串判断相关内容的方法: public boolean startsWith(String prefix): 判断一个字符串是否以参数字符串开头 public boolean constains(String prefix): 判断一个字符串是否包含参数字符串
2.2 Arrays类
-
定义:是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作
-
基本使用:
public static String toString(数组): 将数组变成字符串(格式:[元素1,元素2,...] public static void sort(数组): 按照默认升序(从小到大)对数组的元素进行排序 /* 1. 如果是数值,sort默认按照升序从小到大 2. 如果是字符串,sort默认按字母升序 3. 如果是自定义的类型,那么自定义的类需要有Comparable或者Comparetor接口的支持(后面学) */
2.3 Math类
-
定义:是一个与数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作
-
基本使用:
public static double abs(double num): 获取绝对值(此参数可以是int、float...,返回值类型相对应) public static double ceil(double num): 向上取整 public static double floor(double num): 向下取整 public static long round(double num): 四舍五入
2.4 Object类
-
概述:Object类是类层次结构的根类。每个类都使用Object作为父类。
-
toString方法:
- public String toString():返回该对象的字符串表示
- 看一个类是否重写了toString方法,直接打印这个类对应对象的名字即可(重点)
- 如果没有重写toString方法,那么打印的就是对象的地址值。
- 如果重写了toString方法,那么就按照重写的方式打印。
-
equals方法:
-
public boolean equals(Object obj):指示其他某个对象是否与此对象相等。(默认比较地址值)
-
重写equals方法,用来比较两个对象的内容
public boolean equals(Object obj) { if(obj instanceof Person){ // 向下转型 Person p = (Person) obj; // 比较两个对象的属性 boolean b = this.name == p.name && this.age == p.age; return b; } return false; }
-
-
Objects类:
-
public static boolean equals(Object a,Object b):主要用来避免空指针异常的情况
-
使用
String a = "hello"; String b = "hello"; boolean b = Objects.equals(a,b); // true
补充:hashCode()方法:返回该对象的哈希码值(十进制数)(set和map集合中的元素不能重复的时候使用)
-
2.5 日期时间类
2.5.1 Date类
- 定义:表示日期和时间的类,精确到毫秒。
- 构造方法:
- 空参数:Date date = new Date() 获取当前系统的日期和时间
- 带参数:Date date = new Date(毫秒值) 把毫秒值转换为Date日期
- 成员方法:
- public long getTime():将Date日期转换为毫秒值
- 注意:这个方法的作用等同于System.currentTimeMills()
- public long getTime():将Date日期转换为毫秒值
2.5.2 DateFormat类
- 定义:是是日期/时间格式化子类的抽象类,SimpleDateFormat 是直接子类。
- 子类的构造方法:
- SimpleDateFormat(String pattern):用给定的模式和默认语言环境的日期格式符号构造
- 模式:y-年 M-月 d-日 H-时 m-分 s-秒 例如:“yyyy-MM-dd HH:mm:ss”
- 注意:模式中的字母不能更改,连接模式的符号可以改变。
- 作用:
- 格式化(日期 -> 文本):
- public final String format(Date date):按照指定的模式,把Date日期格式化为字符串
- 解析(文本 -> 日期):
- public Date parse(String source) throws ParseException: 把字符串解析为Date日期
- 异常问题:如果字符串和构造方法的模式不一样,那么程序就会抛出异常,调用一个抛出了异常的方法,就必须处理这个异常,要么throws继续抛出这个异常,要么try catch自己处理
- 格式化(日期 -> 文本):
2.6 Calendar类
- 定义:日历类,出现在Date之后,替换掉了很多Date的方法,该类将所有可能用到的时间信息封装到静态成员变量,方便获取。日历类是用来获取各个时间属性的。(抽象类)
- 创建对象:
- Calendar类无法直接创建对象使用,里面有一个静态方法叫getInstance(),该方法返回了子类对象。
- 格式:Calendar c = Calendar.getInstance();
- 常用方法:
- public int get(int field):返回给定日历字段的值
- public void set(int field,int value):将给定的日历字段设置为给定值
- 同时设置年月日:c.set(2020, 8, 8);
- public abstract void add(int firld,int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量
- public Date getTime():返回一个表示此Calendar的时间值(毫秒)的Date对象。
- 字段:YEAR MONTH(0-11) DAY_OF_MONTH/DATE HOUR MINUTE SECOND (都是静态变量,可通过类.静态变量获取)
2.7 System类
- 提供了大量的静态方法:
- long currentTimeMills():返回当前时间(毫秒)。
- void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中。
2.8 StringBuilder类
- 定义:字符串缓冲区,可以提高字符串的操作效率(看成一个长度可以变化的字符串),底层也是一个byte数组,但是没有被final修饰(可以改变长度)。
- 构造方法:
- StringBuilder():构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。
- StringBuilder(String str):构造一个字符串生成器,并初始化为指定的字符串内容。
- 常用方法
- public StringBuilder append(…):添加任意类型数据的字符串形式,并返回当前对象(不用接收返回值),可采用链式编程。
- 链式编程:方法返回值是一个对象,可以继续调用方法。
- public String toString():将当前StringBuilder对象转换为String对象
- public StringBuilder append(…):添加任意类型数据的字符串形式,并返回当前对象(不用接收返回值),可采用链式编程。