面向对象基础
1. 类和对象
- 面向过程 :是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的
- 面向对象 :是一种以对象为中心的编程思想,通过指挥对象实现具体的功能
类和对象:类是对事物的一种描述,对象则为具体存在的事物
2. 对象内存
当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)
只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。
3. 成员变量和局部变量
- **类中位置不同:**成员变量(类中方法外)局部变量(方法内部或方法声明上)
- **内存中位置不同:**成员变量(堆内存)局部变量(栈内存)
- **生命周期不同:**成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而存在,醉着方法的调用完毕而消失)
- **初始化值不同:**成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)
4. 封装
- 封装概述
是面向对象三大特征之一(封装,继承,多态)
是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的 - 封装原则
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
成员变量private,提供对应的getXxx()/setXxx()方法 - private关键字
被private修饰的成员,只能在本类进行访问 - this关键字
概述 : this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
- 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
- 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
5. 构造方法
1 构造方法的格式和执行时机
- 格式注意 :
- 方法名与类名相同,大小写也要一致
- 没有返回值类型,连void都没有
- 没有具体的返回值(不能由retrun带回结果数据)
- 执行时机 :
- 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
- 不能手动调用构造方法
2 构造方法的作用
用于给对象的数据(属性)进行初始化
3 构造方法的注意事项
如果没有定义构造方法,系统将给出一个默认的无参数构造方法如果定义了构造方法,系统将不再提供默认的构造方法
面向对象高级
1.包
1.包的概述
包:本质上就是文件夹
创建包:(单级包、多级包)多级包之间使用 " . " 进行分割
多级包的定义规范:公司的网站地址翻转(去掉www)
包的命名规则:字母都是小写
2.包的定义
使用package关键字定义包
格式:package 包名;
3.包的注意事项
package语句必须是程序的第一条可执行的代码
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名
4.类与类之间的访问
- 同一个包下的访问不需要导包,直接使用即可
- 不同包下的访问
- import 导包后访问
- 通过全类名(包名 + 类名)访问
- 注意:import 、package 、class 三个关键字的摆放位置存在顺序关系
- package 必须是程序的第一条可执行的代码
- import 需要写在 package 下面
- class 需要在 import 下面
2.static 关键字
static 关键字是静态的意思,是Java中的一个修饰符,可以修饰成员方法,成员变量
- 被static修饰的成员变量,一般叫做静态变量
- 被static修饰的成员方法,一般叫做静态方法
static 修饰的特点
- 被类的所有对象共享是我们判断是否使用静态关键字的条件
- 随着类的加载而加载,优先于对象存在,对象需要类被加载后,才能创建
- 可以通过类名调用也可以通过对象名调用,推荐使用类名调用
注意:静态方法中,只能访问静态成员,静态中没有this关键字
3.继承
继承:让类与类之间产生关系(子父类关系),子类可以直接使用父类中非私有的成员
1.继承的格式
- 格式:public class 子类名 extends 父类名 { }
- 父类,也被称为基类、超类
- 子类,也被称为派生类
2.继承优缺点
- 好处:提高了代码的(复用性、维护性),是多态的前提
- 弊端:降低了代码灵活性,增强了代码的耦合性
3.继承使用场景
当类与类之间,存在相同 (共性) 的内容,并且产生了 is a 的关系,就可以考虑使用继承,来优化代码。
4.继承的特点
Java只支持单继承,不支持多继承,但支持多层继承。
5.继承的成员变量访问特点
在子类方法中访问一个变量
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
注意:如果子父类中,出现了重名的成员变量,通过就近原则,会优先使用子类的如果一定要使用父类的,可以通过super关键字,进行区分。
this:代表本类对象的引用
super:代表父类存储空间的标识(可以理解为父类对象引用)
6.方法重写
在继承体系中,子类出现了和父类中一模一样的方法声明
方法重写的应用场景:
当子类需要父类的功能,而功能主体子类有自己特有内容,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
方法重写注意事项
- 父类中私有方法不能被重写
- 父类静态方法,子类必须通过静态方法进行重写,父类非静态方法,子类也必须通过非静态方法进行重写
- 注意:静态方法不能被重写!如果子类中,也存在一个方法声明一模一样的方法可以理解为,子类将父类中同名的方法,隐藏了起来,并非是方法重写!
- 子类重写父类方法时,访问权限必须大于等于父类
7.权限修饰符
|
修饰符 | 同一个类中 | 同一包中子类无关类 | 不同包的子类 | 不同包的无关类 |
---|
private | true | false | false | false |
默认 | true | true | false | false |
protected | true | true | true | false |
public | true | true | true | true |
8.继承中构造方法的访问特点
- 子类中所有的构造方法默认都会访问父类中无参的构造方法
- 子类通过 super,手动调用父类的带参的构造方法
- 子类通过 this 去调用本类的其他构造方法,本类其他构造方法再通过 super 去手动调用父类的带参的构造方法
注意:
- 如果我们编写的类,没有手动指定父类,系统也会自动继承Object (Java继承体系中的最顶层父类)
- this(…) super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存。
4.抽象类
- 抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
- 抽象方法的定义格式:public abstract 返回值类型 方法名(参数列表);
- 抽象类的定义格式:public abstract class 类名{}
注意
- 抽象类不能实例化
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 可以有构造方法
- 抽象类的子类,要么重写抽象类中的所有抽象方法,要么是抽象类
final关键字
final 关键字是最终的意思,可以修饰(方法,变量,类)
final 修饰的特点
- 修饰方法:表明该方法是最终方法,不能被重写
- 修饰变量:表明该变量是常量,不能再次被赋值
- 修饰类:表明该类是最终类,不能被继承
变量是基本类型:final 修饰指的是基本类型的数据值不能发生改变
变量是引用类型:final 修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的
5.代码块
在Java中,使用 { } 括起来的代码被称为代码块
1.局部代码块
- 位置:方法中定义
- 作用:限定变量的生命周期,及早释放,提高内存利用率
2.构造代码块
- 位置:类中方法外定义
- 特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
- 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
3.静态代码块
- 位置:类中方法外定义
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
- 作用:在类加载的时候做一些数据初始化的操作
6.接口
当一个类中的所有方法都是抽象方法的时候,我们就可以将其定义为接口接口也是一种引用数据类型,它比抽象类还要抽象
1.接口的定义和特点
- 接口用关键字interface来定义
- 接口不能实例化
- 接口和类之间是实现关系,通过implements关键字表示
- public class 类名 implements 接口名 {}
- 接口的子类(实现类)
- 要么重写接口中的所有抽象方法
- 要么是抽象类
注意:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements 接口名1 , 接口名2 {}
2.接口中成员的特点
-
成员变量只能是常量默认修饰符:public static final
-
构造方法没有
-
成员方法只能是抽象方法默认修饰符:public abstract
3.JDK8版中接口成员的特点
-
JDK8版本后
-
允许在接口中定义非抽象方法,但是需要使用关键字 default 修饰,这些方法就是默认方法
-
作用:解决接口升级的问题
接口中默认方法的定义格式:
- 格式:public default 返回值类型 方法名(参数列表) { }
- 范例:public default void show() { }
- 接口中默认方法的注意事项:
- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
接口中允许定义static静态方法
接口中静态方法的定义格式:
- 格式:public static 返回值类型 方法名(参数列表) { }
- 范例:public static void show() { }
- 接口中静态方法的注意事项:
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
4.JDK9版中接口成员的特点
接口中私有方法的定义格式:
- 格式1:private 返回值类型 方法名(参数列表) { }
- 范例1:private void show() { }
- 格式2:private static 返回值类型 方法名(参数列表) { }
- 范例2:private static void method() { }
5.接口使用思路
- 如果发现一个类中所有的方法都是抽象方法,那么就可以将该类,改进为一个接口
- 涉及到了接口大面积更新方法,而不想去修改每一个实现类,就可以将更新的方法,定义为带有方法体的默认方法
- 希望默认方法调用的更加简洁,可以考虑设计为static静态方法。(需要去掉default关键字)
- 默认方法中出现了重复的代码,可以考虑抽取出一个私有方法。(需要去掉default关键字)
6.类和接口的关系
- 类和类的关系继承关系,只能单继承,但是可以多层继承
- 类和接口的关系实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口和接口的关系继承关系,可以单继承,也可以多继承
7.多态
同一个对象,在不同时刻表现出来的不同形态
多态的前提和体现
多态中成员访问特点
多态中的转型
- 向上转型: 从子到父,父类引用指向子类对象
- 向下转型: 从父到子,父类引用转为子类对象
注意
- 如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
避免强转出现的问题
- 关键字 instanceof
- 使用格式:变量名 instanceof
- 类型通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
8.内部类
内部类:就是在一个类中定义一个类。
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
成员内部类按照内部类在类中定义的位置不同,可以分为如下两种形式
- 在类的成员位置:成员内部类
- 在类的局部位置:局部内部类
成员内部类,外界创建对象使用
- 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
成员内部类,也属于(成员),既然是成员就可以被一些修饰符所修饰
- private私有成员内部类访问:在自己所在的外部类中创建对象访问。
- static静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
- 静态成员内部类中的静态方法:外部类名.内部类名.方法名();
局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用该类可以直接访问外部类的成员,也可以访问方法内的局部变量
匿名内部类
- 概述:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)
- 前提:需要存在一个接口或类
- 格式: new 类名或者接口名() {重写方法;};
- 理解:匿名内部类是将(继承 \ 实现)(方法重写)(创建对象)三个步骤,放在了一步进行
- 使用: 当方法的形式参数是接口或者抽象类时可以将匿名内部类作为实际参数进行传递
9.Lambda表达式
Lambda表达式函数式编程思想的体现
- 面向对象思想强调“必须通过对象的形式来做事情”
- 函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”
Lambda表达式的标准格式
- 组成Lambda表达式的三要素:形式参数,箭头,代码块
- 格式:( 形式参数 ) -> { 代码块 }
Lambda表达式的省略规则
- 参数类型可以省略,但是有多个参数的情况下,不能只省略一个
- 如果参数有且仅有一个,那么小括号可以省略
- 如果代码块的语句只有一条,可以省略大括号和分号,甚至是return
Lambda表达式和匿名内部类的区别
- 所需类型不同
- 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
- Lambda表达式:只能是接口
- 使用限制不同
- 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
- 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
- 实现原理不同
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成