1.面向对象
1.1.概述
面向对象:面向对象是软件开发方法,一种编程范式,面向对象的概念和应用已超越程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段的产物。
面向对象是相对于面向过程来说的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统的建模,更贴近事物的自然运行模式。
Java特性:跨平台,多线程,自动垃圾回收,面向对象
面向对象特性:封装,继承,多态,抽象。
1.2.面向对象和面向过程
面向对象侧重分模块
在编程思想方面是以对象为核心,将问题分解成不同对象,每个对象都有其属性和行为,通过对象之间的交互来解决问题
在数据处理与控制方式上,面向对象的数据与操作封装成一个对象,其他对象不能直接修改其数据,只能通过对象的set或者get函数来操作。控制程序的方式是通过”事件驱动“来激活和运行程序。
在模块化与复用上,面向对象通过类和继承来实现模块化,提高了代码的可重用性和可维护性。
封装、继承和多态都是面向对象特有的 特性。
在软件开发的视角
面向对象更注重于问题的整体解决方案和对象的交互,适合于大型、复杂的系统开发。
面向过程侧重分步骤
在编程思想方面以过程为核心,强调问题分解成一系列的步骤或者函数,然后按照顺序调用这些函数来解决问题。
在数据处理与控制方式上,面向过程的数据与代码是分离的,数据通过函数或者过程来处理,处理完毕后显示结果。控制程序的方式是按照设计调用或者返回程序。
在模块化与复用上,面向过程在模块化实现上使用子程序或者过程,便于开发和维护,但可重用性差,数据安全性差。
在软件开发的视角,面向过程更注重于过程的实现和流程的清晰性,适合于小型项目或者简单的任务。
1.3.构造方法
构造方法:用于创建对象并对数据初始化。
语法:权限修饰符 类名 (参数列表){方法体}
构造方法的方法名必须和类名一致,构造方法没有返回值,连void都没有
如果没有编写构造方法,则默认有一个公共的无参构造方法
如果我们编写了任意构造方法,不论是否是有参构造方法,都不会在有默认的无参构造了
所以一般我们编写有参构造的时候,会再写一个无参构造
1.4.类和对象
类:把具有相同”特征“的事务进行分类,代码中:根据具体事务或者需求进行特征的抽象,进行描述汇总,是我们描述客观事物的一个标准,一个模板
对象:对象是一个类中具体的个体,比如有一个学生类,里面记录着成员变量姓名 name ,年龄age等,还有他的构造方法,我们通过构造函数生成一个对象(张三,18),生成的数据就是对象。
类只是属性的封装描述,对象是对属性进行赋值存储。
根据不同的特征/属性划分成不同的类,根据不同的属性值,划分不同的对象
同类的多个对象,一定具有相同的特征
1.5.对象使用
对于属性没有private权限修饰符的数据,我们可以直接用 对象.属性 直接修改其数据。但是大部分应该将属性private私密起来,通过set,get方法获取和修改其中的属性。
1.6.Bean
JavaBean是一个实体类,类必须是具体的,公共的,并且具有无参构造器。JavaBean中的属性需要用private修饰,并且具有set和get方法,以及构造器。
1.7实例化
语法: 引用类型 变量名 = new 引用类型(参数);
第一步:静态加载:运行时会把所有相关的类全部加载到左边的静态区
动态加载:运行时,只加载当前类,当用到其它类的时候再去加载
Java中采用的动态加载:
实例化:
1.加载类到静态区
2. new 在堆内存中创建内存空间
3.执行构造方法对对象中数据进行初始化赋值
4构造方法弹栈,返回堆内存地址。
1.8.常见异常
空指针异常:
类是引用数据类型,所以在创建对象时,对象的数据类型是引用数据类型,所以对象存储的是地址,所有引用数据类型都可以赋值null,引用数据类型默认值为null。但是对象为null之后不在指向堆内存对象数据,就会丢失对象数据。此时在用null的对象访问成员属性,就会报空指针异常。
1.9.对象调用静态属性
在对象中设置成员属性的修饰符 为静态时,即使对象是空指针也不会影响该属性的调用,因为在编译时,会自动将对象、属性 转化成 类名、属性 (这里防止看不清楚,我用、代替小数点.,编译时要用小数点.);
1.10.注释事项
1.10.1.静态调用成员
Java中静态上下文中无法引用非静态变量:
non-static variable mainframe cannot be referenced from a static context
非静态的成员变量是一个对象属性,只有在对象存在时才可以引用。因此,如果在对象未创建实例时,在静态方法中调用了非静态成员方法是非法的。静态方法可以不用创建对象就调用,非静态方法必须有了实例对象才能调用。因此在静态方法中引用非静态方法是不可能的。
具体了解可以去下面这个博主发的文章里了解,有截图有举例。
该播主链接:https://blog.csdn.net/u014663877/article/details/84861362
1.10.2 区分成员方法和构造方法
1.构造方法的方法名必须与类名一致,成员方法的方法名可以与类名一致,当成员方法的方法名与类名一致时要看返回值区分,构造方法是没有返回值的,连void都没有,成员方法必有返回值。
2.This
2.1概述
this:是每个对象中第一个成员变量,用于保存当前对象的内存地址
this只能出现在构造方法和成员方法中,不能在静态上下文中使用
2.2作用在哪
1.在成员方法或者构造方法中,用于区分同名的成员变量或者局部变量
2.用在构造方法中,用于重载调用构造方法,必须在构造方法的有效代码的第一行
比如存在如下两个构造方法,一个无参构造,一个有参构造,在无参构造中可以使用this调用其他的构造方法,实现所有的对象的初始化。
3.返回的this可以链式调用
2.3用法
1.区分成员和局部:成员和局部同名时,this指的是调用该方法的对象,编写方法时传入的值的名字与成员变量相同时,使用this来区分成员和局部。
2.重载调用构造方法,同上图,用于重载调用构造方法时,必须放在构造方法第一行。
3.链式调用:目的是前者方法的返回值能够调用后者方法的对象,下图中Test02 t2 = t1.m1();
等价于Test02 t2 = t1;
2.4.注意事项
this只能出现在构造方法和成员方法中,不能再静态上下文中使用
原因:静态方法与类相关联,而this与实例对象相关联,意味着,即使一个类没有调用构造方法或者实例化任何对象,静态方法依然可以通过类名调用,而这时如果有this,this只能指向类,这在Java中是不允许的,所以静态上下文中不能有this
3.Static
static是修饰符,用于修饰静态数据。
1.static修饰的变量,方法,和语句块分别是静态变量、静态方法、静态语句块。
3.1静态语句块
静态语句块可以看成没有语句块的静态方法,不能调用,在类加载阶段会自动执行,是最先执行的语句并且只执行一次(main方法之前),因此静态语句块适合初始化操作(如果需要在main方法中使用初始化的数据,最好在静态语句块之前先静态声明出来)。当访问一个类的静态属性时,才会加载这个类。
3.2实例语句块
实例语句块可以看作没有名字的成员方法
每次创建一个对象就执行一次,并且在构造方法之前执行。
4.封装
4.1包的机制
4.1.1.package
package:解决命名冲突问题,在文件名前,加上命名空间(前缀)
package限制的是class文件的保存目录,和java文件无关
命名规则一般采用公司域名倒叙
例如河北地质大学 : com.HebeiGEO.www
cn.edu.hgu.www
4.1.2.Import
同目录(同包)下,可以直接写名字使用
Package_01 p = new Package_01();
不同目录下,需要写全名,格式是包名.类名
如果当前的类用到了其他包内的类,可以通过import 导入用到的类。
可以导入多个类,如果某一个包内大多数的类都会用到,可以导入时用包名.*代替包名.某一个类
java.lang.*下所有类都是核心类,可以直接使用不需要导入
注:impor语句在编译工具中一般不需要我们手动导入,在编译中一般按回车或者空格会自动导入,但是需要注意可能会导错包。
静态导入:使用一个类的静态变量时候,需要加类名.静态变量名
静态导入后,,可以在当前类中直接写变量名使用,不需要加类名,不过不建议这样写,小规模无所谓,大项目变量多容易重名
4 .2. 权限控制
上图摘自网络(水印是自动加上去删不掉)
权限控制修饰符要根据数据被使用情况而定
1.private 私有的,除了自己类中的,其他都不能访问,一般用于保护数据,类中会设有get、set方法调用私有的属性
2.default 默认修饰符,不写修饰符时就是包权限,在同一个包中的类都可以调用,其他包调用需要修改修饰符为public公共的,如果保持default,即使导入包也不能直接访问。
3.protected 是受保护的修饰符,在同一包中的其他类或其子类都可以直接访问数据,这里的子类不单单是继承于含有受保护属性的类,包内的所有类的子类都可以直接访问数据。
4.public 公共的修饰符。权限最高,项目中哪里的数据都能访问。
5.继承
5.1继承是什么
继承就是从已有的类中派生出新的类,新的类中包含父类的属性和行为
在新的类中 ,还能扩展新的属性和行为
在Java中,类只有单继承,一个类只能继承一个父类,继承关系是可以传递的,就是孙子可以继承爷爷的属性和行为,但是不能环形继承(即其中某一个子类成为这条继承线的父类)
私有化属性是不能被继承的,但是可以通过父类提供的get方法进行访问
如果没有显示继承其他类,则默认继承java.lang.Object类,Object是Java提供的根类(所有类的祖宗)
5.2.继承的作用
继承目的是实现代码的复用,最核心的实现方法就是方法覆写Override(这里不同于方法重载)
方法重载是相同方法名,不同的返回值类型,不同的参数类型,相同功能
方法覆写是相同的方法名,相同的返回值类型,相同的参数类型,不同的功能
5.3.继承的使用
class A{
}
class B extends A{
}
6.Super
6.1.Super是什么
super官方解释是:super保存了父类型特征
可以理解为子类中super代表父类
6.2.能做什么
可以用在成员方法/构造方法中,用于区分父类和子类同名的属性
可以用在子类构造方法中,调用父类构造方法,如super(参数);改写法必须在子类的构造方法的第一行,所以super(参数)和this(参数)无法同时出现
如果构造方法中,没有出现this(参数)和super(参数),则默认有一个super()去调用父类的无参构造
6.3.怎么用
可以用在成员方法/构造方法中,区分子类与父类同名属性:
可以用在子类构造方法中,调用父类构造方法:
运行结果与上图无异;
当调用父类的有参构造时,父类中this指向的时父类的age,修改的是父类的age,在子类构造时如果没有显式调用父类的构造方法,则会默认调用父类的无参构造方法。因此子类构造无论如何都会调用父类的构造方法,这里就算用this调用子类的其他构造方法,该方法也会去调用父类构造,拦不住的~!
6.4.注意
1 this和super都不能出现在静态上下文中,因为this和super都是引用类型,有指向目标(this一般指向对象或者子类,super一般指向父类),在静态上下文中,静态能够无对象直接类名加点来调用,这时this和super无意义,必然报错。
6.5.实例语句块和构造方法
想要加载一个类必须先加载对应的父类,因为子类需要拥有父类属性
因此当父类子类中都有 静态语句块,实例语句块,构造方法时,运行结果,创建子类对象运行结果必然是父类静态(先加载),子类静态(第二加载),父类实例(super先运行父类,实例语句块在构造方法之前),父类构造(super运行父类构造器),子类实例(super执行完之后,运行)子类构造
注意:实例对象是在构造方法执行中创建,这里的父类构造是构造方法即将结束时才输出,因为super必须在有效代码的第一句,因此无论怎么写,这个输出都在构造方法快结束时才会执行,在这之前,对象实例已经被创建,实例语句块执行,先构造方法结束一步输出。子类同理。
7.覆写Override
7.1.覆写是什么
Override方法覆写就是对继承父类的方法进行重写
覆写条件:
1.在有继承关系的体系中
2.方法名,参数列表,返回值必须一致
3.不能比原方法拥有更低的访问权限
4.不能比原方法有更宽泛的异常
5.方法覆写特指成员方法,与其他无关
7.2.应用场景
当父类无法满足当前子类需求的时候,子类根据需求对父类方法重写:
比如父类中方法是输出“父类的年龄”,这时候创建的子类对象使用这个方法肯定是不合理的,因此需要对这个方法覆写,方法体改成输出“子类的年龄”。
7.3.面试题
Override 和 Overload的区别
Override 是方法覆写,当父类功能无法满足子类的需求时,子类需要根据需求对父类方法进行重写,需要注意的是,覆写后的方法,方法名,返回值,参数列表,必须和原方法一致,不能有更低的访问权限,不能有更宽泛的异常
Overload时方法重载,指的是在同一个类里,方法名相同,参数列表不同的情况
作用是相同的功能,设置相同的方法面,更容易记忆,更容易记忆。
8.Final
8.1.final是什么
final是修饰符,表示最终的,无法更改的
8.2.final能做什么
final修饰的类,不能继承
final修饰的成员方法不能被覆写
final修饰的局部变量不能二次赋值
final修饰的成员变量,不能被二次赋值,没有默认值,必须显示赋值(因此,final修饰必然有值)
final修饰的静态变量,我们称为常量,常量一般使用public static final 修饰,不能被二次赋值。
8.3.final怎么用
成员变量(类下的变量):final 修饰的成员变量必须显示赋值
静态变量(用static修饰的成员变量,但是该变量属于类而不是对象实例,不能在方法中和类外存在):final修饰的静态变量就是常量
局部变量(方法内的变量):final修饰的局部变量不能二次赋值
类:final修饰的类没有子类,无法被继承
方法:final修饰的方法,无法被覆写
8.4.深入final
-
Final 变量: 声明的变量只能被赋值一次,之后不能再改变其值。这在确保变量值不被修改或被意外改变时非常有用。
-
Final 方法: 声明的方法不能被子类重写或覆盖。这通常在你确定一个方法不需要被修改或者子类化时使用。
-
Final 类: 声明的类不能被其他类继承。这意味着该类的行为不能被改变或扩展。Final 类通常是为了安全性或者效率而设计的,因为它们的行为不会受到子类的影响。
-
Final 参数: 在方法参数中使用 “final” 关键字表示该参数在方法内部不可修改。
-
Final 数组: 声明的数组引用不能被改变,但是数组中的元素可以被修改。这意味着你不能再将该引用指向另一个数组,但是可以修改数组中的内容。
由上,final修饰的基本类型一旦赋值不能再改变,final修饰的数组其内的值可以被改变,但是其地址不能改变。使用 final
关键字修饰的类表示该类是最终的,不能被其他类继承。这意味着即使子类想要覆写父类的方法,也是不允许的。虽然父类的地址不会变,但是通过将类声明为 final
,可以确保类的行为和实现不会被修改或扩展,从而提高代码的稳定性和安全性。
final运行原理如下:
final修饰的数组,固定的是数组的引用,其内的值保存在堆内存,可以对其内的值进行修改
9.多态
9.1.多态的设计原则
多态是面向对象编程的一个重要概念,它允许不同种类的对象对同一消息做出响应。多态的设计原则包括:
-
接口隔离原则: 通过接口或抽象类来定义公共的接口,减少对具体实现的依赖,使得不同的实现可以独立变化。
-
开闭原则: 多态允许在不修改已有代码的情况下,对程序进行扩展或修改。
-
单一职责原则: 每个类或接口都应该保持单一的职责,避免在设计中引入不必要的复杂性。
-
依赖倒置原则: 高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节;细节应该依赖抽象。
-
里氏代换原则: 任何基类可以出现的地方,子类都可以出现,子类可以扩展父类的功能,但不能改变父类原有的功能。
-
合成复用原则: 尽量使用对象组合而不是继承关系来实现代码复用,这样可以减少代码间的耦合。
-
最少知识原则: 一个对象应该尽可能少地与其他对象发生相互作用,通过接口或抽象类来减少相互之间的依赖。
在设计多态时,应该遵循以上原则,这样可以使得程序更加灵活、易于维护和扩展。
9.2.多态是什么
Java有两种多态机制
1.编译时多态 编译时多态是静态的,主要指的是方法重载,可以根据参数不同,来区分不同的方法,不同的功能。
2.运行时多态 运行时多态是动态的,主要指动态绑定来实现,主要靠父子类实现
多态是里氏替换原则的一种体现,父类引用指向子类对象
父类引用:使用父类类型创建的引用类型变量
指向:可以找到谁
子类对象:子类创建的实例化对象
父类类型创建的变量 保存了 子类对象
9.3.多态怎么用
语法结构:
父类 变量名 = new 子类(); 不一定是直接子类,只要是长辈都可以
输出结果为狗吃肉。一个动物吃东西的方法有很多种方式,每一个物种都有一个特定的方式,使用多态可以优化main方法中代码的可读性和冗杂。
9.4.应用场景和优点
优点:降低类直接的耦合度,降低需求变动带来的代码修改的风险
应用场景:当一个需求对应多种不同实现的时候,一定要使用多态
如果一个事物只有一种可能,就没必要多态了。
9.5.缺点
会丢失子类特有的属性:当父类不存在的属性或方法,子类存在时会报错
9.6.多态进行属性调用
多态缺点:丢失子类的特有的属性(父类没有子类有,就是特有)
多态进行属性调用:
1.父类没有,子类有,报错,不能访问,丢失子类的特有属性
2.父类没有,子类没有,报错,都没有没办法访问
3.父类有,子类没有,执行父类
4.父类有,子类有,成员方法执行子类,其他执行父类
9.7.Instanceof
作用:判断某个对象是否由某个实例化而来,从而降低类型转换异常的风险(多态可以向下转型)
在Java中,instanceof
是一个用于判断一个对象是否是特定类或接口的实例的关键字。它的语法形式为 object instanceof Class
,其中 object
是要判断的对象,Class
是要检查是否为其实例的类或接口。
如果 object
是一个 Class
的实例,或者是 Class
的子类的实例,则返回 true
;否则返回 false
。这可以用来在运行时判断一个对象的具体类型,以决定如何处理这个对象。
示例:
class Animal {}
class Dog extends Animal {}
Animal a = new Dog();
if (a instanceof Dog) {
System.out.println("a is an instance of Dog");
} else {
System.out.println("a is not an instance of Dog");
}
在上面的示例中,a
是 Animal
类的实例,但由于其实际类型是 Dog
类,因此 instanceof
判断为 true
。
9.8.多态的几种形式
只要最终父类保存了子类对象,都是多态。
1.直接多态:Animal a = new Dog();
2.形参实参多态: 一个方法的参数列表是父类 声明,但是方法调用时传入 子类对象
3.返回值多态 :返回值是父类类型,但是返回数据时,返回了子类的对象
4.隐式多态 : 通过子类调用父类方法的时候,父类的这个方法中的上下文环境,就会发生多态(父类空间,子类对象)
10.抽象
10.1.抽象概述
abstract 修饰符,表示抽象的
修饰的类 是抽象类,抽象类不能创建对象 (专门用来被继承的)
修饰的方法 是抽象方法,抽象方法没有方法体(专门用来覆写的,抽象方法只存在在抽象类中)
抽象方法必须在抽象类中,而抽象类中,可以没有抽象方法
抽象类往往用来表示设计中得出的抽象概念:比如,动物类,自然界没有一个种族叫做动物,不能代表实体,这个时候我们称这个类为抽象类
抽象类中往往是对事务的属性和行为进行封装,但是不会有实现,一般是用于子类覆写实现
10.2.抽象怎么用
根据概述:抽象类里可以写抽象方法(抽象方法没有方法体),有构造方法(但不能创建对象),功能的实现靠子类
10.3.注意
注意:
1.一个类继承了一个抽象类,需要实现所有的抽象方法
2.一个抽象类继承了一个抽象类,可以实现了0~N个抽象方法
3.abstract 和final 不能同时出现
4.抽象类不能创建创建对象,但是有构造方法,用于子类实例化调用
11.接口
11.1.接口是什么
接口:是引用类型,并且接口可以发生多态
接口可以看做是一个特殊的类,完全抽象,是Java为了解决单继承功能变弱的问题
Java1.8之前:接口完全抽象,只有抽象方法和常量,
Java1.8之后:可以有默认方法和静态方法
接口定义由class变成interface:public interface 接口名{}
接口中没有变量,只有常量{public static final},并且psf可以省略
接口中没有成员方法,只有抽象方法,并且abstract可以省略,public也可以省略
接口和接口之间是多继承,多个使用逗号隔开interface接口名extends父接口1,父接口2,。。。{}
类和接口之间是多实现,使用implements表示,多个逗号隔开,如果需要继承 则必须先继承后实现。
一个类实现一个接口的时候,需要实现所有的抽象方法
接口不能创建对象,并且没有构造方法(因为子类创建对象时调用的父类的构造方法,并不会调用父接口的构造方法,所以接口不需要有构造方法)
抽象类和接口都能完成某个功能时,优先使用接口,保留类继承(因为类之间是单继承,而类和接口是多实现)
11.2.优点
接口可以发生多态,如果一个类没有继承只有实现,则该子类调用的父类构造是隐式父类object的构造方法
类和接口多实现
接口的使用思想是实现多态和解耦,面向接口编程,降低类之间耦合度
11.3.接口怎么用

11.4.接口和抽象类的区别
接口,之间多继承,逗号隔开,类和接口多实现,逗号隔开,接口没有构造方法,不能创建对象
抽象,类与抽象类之间单继承,抽象类有构造方法,但是不能创建对象
接口中只有常量,静态常量,抽象方法,静态方法,默认方法,一个类实现一个或多个接口,需要实现所有抽象方法,一个抽象类实现一个或多个接口,可以实现0~N个抽象方法
抽象中相比普通类,可以有抽象方法,但是抽象方法子类需要全部实现,一个抽象类继承一个抽象类,可以实现0~N个抽象方法
当抽象类和接口都能完成某个功能的时候,优先使用接口,这样能够保留类的继承
12.object
12.1.toString
toString方法的设计目的是返回该对象的字符串表示形式,结构为包名和类名 + @ +十六进制的hash值
当打印一个引用类型的时候,会自动调用该对象的toString方法(隐式调用)
默认的toString方法,返回十六进制整型值(一般称为内存地址)
如果不需要打印内存地址,则需要我们根据需求进行重写
12.2.Equals
==比较基本类型的时候,比较的是值的大小,而比较引用类型的时候,比较的是内存地址
equals方法的设计目的:比较两个对象是否相同
使用Object中的equals方法和使用==没有区别。
new 的两个对象,地址一定不一样,我们比较不会去比较地址,而是比较其保存的属性是否一致
而Object中的equals方法,默认比较的也是内存地址,所以需要根据需求进行重写
重写前:重写后:
12.3.Finalize
finalize
是Java中的一个方法,用于在对象被垃圾回收之前执行一些清理操作。当Java虚拟机确定不再有任何对对象的引用时,即将回收该对象时,会调用其finalize
方法。
JVM四大特性:跨平台,自动垃圾回收,面向对象,多线程
所谓回收,就是把该对象在内存中删除,该对象的生命周期也到此结束
finalize方法是对象生命周期中,最后做的事,所以一般适合做一些关闭和销毁资源等操作
垃圾:当一个对象没有任何引用可以指向它的时候,这个对象就被视为垃圾对象
finalize方法不需要手动调用,该方法并没有垃圾回收的功能,如果手动调用也仅仅是方法调用而已。但是可以用System.gc()建议垃圾回收机制进行垃圾回收,垃圾过多的时候不用建议也会回收
13.类关系
继承:类和类是单继承,接口和接口是多继承,多个使用逗号隔开
实现:类和接口是多实现,多个使用逗号隔开
关联:关系性比较强,一般是某个类的成员变量保存了另一个类的引用
依赖:关系性较弱,一般是某个局部变量,保存了另一个类的引用
组合:各自不具备独立的生命周期,需要依赖于整体,生命周期相绑定
聚合:各自具有独立的生命周期,不需要依赖于整体,生命周期不稳定