面相对象入门
面向对象与面向过程
-
面向过程,面向对象都是一种看待问题、解决问题的思维方式。
-
面向过程
—强调的是功能行为—关注的是解决问题需要哪些步骤
—着眼点在于问题是怎样一步步的解决的,然后亲力亲为的解决这个问题。 -
面向对象
—强调的是完成功能的对象—关注的是解决问题需要哪些对象
—着眼点在于找到一个能够帮助解决问题的实体,然后委托这个实体解决问题。 -
面向对象是相对面向过程而言
-
面向对象是基于面向过程的。
面相对象特点
- 是一种符合人们思考习惯的思想
- 可以将复杂的事情简单化
- 将程序员从执行者转换成了指挥者
完成需求时:
- 先要去找具有所需的功能的对象来用。
- 如果该对象不存在,那么创建一个具有所需功能的对象。
类与对象分析
在面向对象的编程思想中, 着眼点在于找到一个能够帮助解决问题的实体, 然后委托这个实体解决问题。
在这里, 这个具有特定的功能, 能够解决特定问题的实体, 就是一个对象。
由若干个具有相同的特征和行为的对象的组成的集合, 就是一个类。
类是对象的集合, 对象是类的个体。
类与对象详述
对象的实例化
实例化对象, 其实就是从类中找到一个实体。
使用关键字 new 进行实例化。
class Person {
// 使用属性, 描述所有对象的特征
String name; // 描述所有人的姓名
int age; // 描述所有人的年龄
// 使用方法, 描述所有对象的行为
public void eat() {}
public void sleep() {}
}
class Test {
public static void main(String[] args) {
// 使用new进行对象的实例化,对象内的属性会自动进行初始化,引用类型初始化成
null,int赋值成0,boolean赋值成false
Person xiaoming = new Person();
}
}
匿名对象
- 定义
匿名对象就是没有名字的对象
因为没有名字,所以当我们想使用匿名对象实现功能时,只能在创建对象的这个时刻使用一次.一旦使用完毕,这个对象我们就再也无法调用,变成了垃圾.系统会通过垃圾回收机制在某个时刻进行内存回收
- 作用
内存很宝贵,使用匿名对象可以更好的使用内存(随用随建,用完更快回收内存),节省内存
- 使用场景
1.用作方法参数
2.用作匿名内部类
类中的成员访问
成员分类
- 使用关键字static修饰的属性、方法, 被称为静态属性、静态方法。
- 没有使用关键字static修饰的属性、方法, 被称为非静态属性、非静态方法, 又被称为实例属性、实例方法。
空间分配
- 静态的成员是属于类的,在类第一次被加载到内存中的时候,就已经分配空间了。
- 非静态的成员是属于对象的,在实例化对象的时候分配空间。
访问
- 静态成员需要使用类访问,非静态成员需要使用对象访问。
- 静态方法中可以直接访问本类中的静态成员,不能直接访问本类中的非静态成员。
- 非静态方法中可以直接访问本类中的静态成员,也可以直接访问本类中的非静态成员。
static
是一个关键字,被static修饰的成员就变成了静态的.具有保值功能
温馨提醒
如果某些属性是属于不同的对象, 每一个对象的值都不同, 可以设计为非静态。 例如人的名字。
如果某些属性是可以被所有的对象共享的, 每一个对象看到的值都是相同的, 可以设计为静态。 例如对象的数量。
static的内存展示
图示说明:
1.java内存分成分成堆区,栈区,方法区,本地方法区,寄存器,图中为堆区,栈区,方法区的内存使用情况
2.在方法区内部有一块儿特殊的区域-静态方法区,专门用来盛放static修饰的成员,可以延长成员的存活时间与字节码(.class)一致
3.字节码文件对象(Demo2.class,student.class)是在程序执行时,由JVM负责将字节码文件生成的字节码文件对象.内部包含类的所有二进制形式的内容.每个类都有唯一的一个字节码文件对象,负责当前类所有实例对象的创建工作(new方法执行具体的开辟空间,构造方法执行具体的属性初始化),字节码文件对象的生存周期与类一致,是整个程序.
过程说明:
1.将Demo2.class对象加载进方法区
2.将静态方法-main()方法保存在静态方法区一份
3.将Student.class对象加载进方法区
4.将静态成员height,jump()保存在静态方法区一份,同时height初始化成0
5.main()方法入栈
6.执行main()中的代码,创建局部变量s
7.在栈中创建Student对象,给非静态成员变量age初始化成0,并将地址返回,保存在引用s中
8.给age赋值成10
9.给height赋值成20
10.jump()方法入栈
static的作用
用于保值
static int a = 3;
只要我们不手动改变a的值,到程序结束前a的值会一直存在.
用于工具类的创建
工具类内部都是使用的静态方法,这样就不需要在调用方法时再创建工具类对象,节省内存,提高效率.
用于单例设计模式的实现
this关键字
概念
是一种引用数据类型,本身是一个关键字,用在类的实例方法或者构造方法中,代表的是当前的对象,保存的是当前对象的地址
场景:当我们想在当前类的内部拿到当前对象的引用时,可以使用this
this的功能总结:
- 用来区分成员变量和局部变量
- 可以在构造方法内部调用其他重载的构造方法,提高代码的复用性,简化代码
区分成员变量和局部变量
在类中, 使用方法时,为了更好的表示参数代表的成员变量意思,我们会将参数的名字和对应成员变量的名字一致。 此时, 如果在方法内部直接使用名字来访问, 根据就近原则(在内存中离方法的远近判断)优先访问的是局部变量(参数)。 因此, 需要使用this关键字表示对当前对象的引用,访问成员变量,因为使用this访问的一定成员变量。
this关键字的省略
当需要访问的属性与局部变量没有重名的时候, this关键字可以写, 也可以不写。
当需要访问的属性与局部变量重名的时候, this关键字必须写, 不可以省略。
构造方法
概念
构造方法, 其实也是一个方法。 用于实例化对象, 在实例化对象的时候调用
和普通的方法的区别
- 构造方法的名字,必须和类名一致。
- 构造方法没有返回值,返回值类型部分不写。
构造方法的意义
- 一般情况下,使用构造方法,是为了在实例化对象的同时,给一些属性进行初始化和赋值。
构造方法的注意事项
- 如果一个类中没有写构造方法, 系统会自动提供一个public权限的无参构造方法, 以便实例化对象。
- 如果一个类中写构造方法了, 此时系统将不再提供任何的默认的构造方法。
- 多个构造方法之间是重载的关系
this在构造方法中的使用
注意点总结:
- 不能自己调用自己—死循环
- 不能相互调用----死循环
- this充当构造方法时,必须放在第一行—先构造对象再调用对象
- this在作为方法的时候,只能充当构造方法,不能作为其他方法[this();]
- this的使用范围就是当前类的内部
- 只有在非静态方法中,才可以使用this.
封装性
基础
- 定义:我们可以通过对具体属性的封装实现.把对成员变量的访问进行私有化,让他只能在类内部可见,通过公共的方法间接实现访问.
- 优点:提高了代码的安全性,复用性和可读性.
getter,setter方法
因为往往我们会有大量的属性需要进行赋值取值操作,所以就形成了一个规范
-
赋值的规范:set
构成:
修饰词 返回值 方法名 (参数列表){
方法体中的代码
return 返回值
}
修饰词:一定是public
返回值:不需要,这里写void
方法名:set+属性的名字,名字的首字母大写
参数列表:一般只有一个,写法与属性同名
代码:this.属性的名字 = 参数
return:不需要 -
取值的规范:get
构成:
修饰词 返回值 方法名 (参数列表){
方法体中的代码
return 返回值
}
修饰词:public
返回值:类型与属性一致
方法名:get+属性的名字,首字母大写
参数列表:不需要
代码:没有
return 属性的名字/this.属性的名字
快捷方式提醒
右键点击-列表中选择Generate
继承
在设计类的时候, 可以根据程序中需要使用到的多个具体的类, 进行共性的提取, 定义为父类。
将多个具体的类中相同的属性和行为提取出来到一个类中。
继承的特点
- 产生继承关系后, 子类可以使用父类中的属性和方法, 也可以定义子类独有的属性和方法
- Java是单继承, 一个类有且只能有一个直接的父类,可以有若干个间接的父类,一个父类可以有0个或者多个子类,子类之间互不影响
- 使用继承,可以简化代码,提高代码的复用性,提高代码的拓展性,增加代码的健壮性,最重要的使类与类之间产生了继承的关系,是多态的前提
继承的语法
- 继承, 需要使用关键字 extends。 在定义类的时候, 使用 子类 extends 父类 的方式描述继承。
- Object类:是java继承体系中所有类的父类,Object类没有父类.
不可以被继承
-
构造方法
- 构造方法是为了创建当前类的对象的, 不可以继承给子类。
-
私有成员
- 私有成员只能在当前的类中使用, 不可以继承给子类。
- 注意:父类的私有成员,在子类中不可用
-
跨包子类
- 默认权限(default修饰)的属性、方法, 不可以继承给跨包的子类。
访问权限修饰符
访问权限修饰符, 就是修饰类、属性的访问级别。
对于类来说:只能有default和public两个修饰符
方法重写
子类可以继承到父类中的属性和方法, 但是有些方法, 子类的实现与父类的方法可能实现的不同。 当父类提供的方法已经不能满足子类的需求时, 子类中可以定义与父类相同的方法。
这时子类方法完成对父类方法的覆盖, 又叫重写(Override)。
- 当出现同名方法后,方法如何调用?
对象调用方法的原理
首先会在自己的内部找这个方法,找到了直接使用,找不到会继续去父类中找,同理,找到了使用,停止查找,找不到继续向上找,一直找得到Object类,如果还没有找到,就认为没有这个方法
@Override
一个注解, 进行重写前的校验。 校验这个方法是否是一个重写的方法。 如果不是重写的方法, 会直接报错。
重写的注意事项
- 方法名字必须和父类方法名字相同
- 参数列表必须和父类一致
- 子类方法的访问权限需要大于等于父类方法的访问权限,父类不能是private
- 子类方法的返回值类型需要小于等于父类方法的返回值类型–引用类型
super关键字
- 有时候,子类重写父类方法的时候,并不是要对父类的实现全盘推翻,而是对父类方法进行拓展
- 父类方法中的实现仍然需要, 但是还需要在父类方法的基础上进行拓展的实现, 此时就需要使用super关键字调用父类的方法。
- this和super的对比
- this:是一种引用类型,代表当前对象,保存的是当前对象的地址
- super:代表的是当前对象的父类,可以调用父类的成员.但是他不是引用数据类型.
继承中使用构造方法
基本使用
- 子类对象在实例化的时候, 需要先实例化从父类继承到的部分。 此时通过super()默认调用父类中的无参构造方法。
- 注意:super()方法是默认的,不需要显示写出来.
- 当我们创建构造方法的时候,为什么一定要调用super?
原因:父类中也有属性要进行初始化,而对象的属性必须由自己的构造方法进行初始化,所以必须调用super(),所以每个构造方法中都默认有一个super()
- 如果父类中没有无参构造方法, 对所有的子类对象实例化都会造成影响, 导致子类对象无法实例化!
类中没有无参构造方法的情况:当我们在类中只写了有参构造方法时,系统不会再自动创建无参构造方法.
两种方案:
1.给父类添加无参构造方法。
2.在子类的构造方法中, 使用 super(参数列表) 调用父类中的有参构造方法。总结:在继承体系中,作为父类最好的办法就是将无参构造方法和有参构造方法都写了.
类与类之间的关系
1.继承---描述:谁是谁 例如:人是动物
2.组合---描述:谁属于谁 例如:狗属于人/人拥有狗
3.传参
传参效率最高.
因为使用传参 两个类的内聚性最高、耦合性最低
内聚性:两个类之间的关系越松散,内聚性越高
耦合性:两个类之间的关系越紧密,耦合性越高
开发追求高内聚、低耦合。
注意:在实现继承或组合时,要符合现实的逻辑,我们写的代码是为人们的生活服务的
比如:语法中我们写成人属于狗也可以.但是不符合现实逻辑,现实中应该是狗属于人.
final关键字的使用
是一个关键字,最后的,最终的.被final修饰的内容是不能再被改变的.
可以修饰的内容
- 类:final修饰的类不能有子类
- 成员变量:变量是一个终值,不能再被改变.所以在定义时必须先手动给一个值.
- 局部变量:被final修饰的局部变量是一个终值,不能再被改变
- 方法:final修饰的方法不允许重写
空白final
- 描述:修饰成员变量的一种形式
- 如果是自定义的类可以在定义时先不给值,但是必须在构造方法中给值,即必须保证属性是被初始化了的.这种情况叫空白final.
合时,要符合现实的逻辑,我们写的代码是为人们的生活服务的比如:语法中我们写成人属于狗也可以.但是不符合现实逻辑,现实中应该是狗属于人.`
final关键字的使用
是一个关键字,最后的,最终的.被final修饰的内容是不能再被改变的.
可以修饰的内容
- 类:final修饰的类不能有子类
- 成员变量:变量是一个终值,不能再被改变.所以在定义时必须先手动给一个值.
- 局部变量:被final修饰的局部变量是一个终值,不能再被改变
- 方法:final修饰的方法不允许重写
空白final
- 描述:修饰成员变量的一种形式
- 如果是自定义的类可以在定义时先不给值,但是必须在构造方法中给值,即必须保证属性是被初始化了的.这种情况叫空白final.
- 优点:空白final在final的使用上提供了更大的灵活性,因为一个类中的final域可以做到根据对象而有所不同,却又保持其恒定不变的特性.