面向对象在开发中是一种运用对象、类、继承、封装、聚合、消息传递、多态等概念来构造系统的软件开发方法。
面向对象其实是相对于面向过程而言。
面向对象在开发中的优点:
减少软件的复杂性
表述非常自然
面向对象特征:
对象是系统中用来描述客观事物的一个实体,它是构成系统的基本单位。
对象的性质:
对象的特性:
对象的标识:
缩写(OID)
是将一个对象和其它对象加以区分的标识符
一个对象标识和对象永久结合在一起,不管这个对象状态如何变化,一直到对象消亡为止。
类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分
类的作用:
类与对象:
类的定义格式:
class { //属性... //方法... }
代码示例:
//定义Person类 class Person { //定义属性name和age String name; int age; //定义方法speak,可以定义具有返回值的方法 public void speak() { System.out.println(("name=" + name + ",age=" + age)); } }
方法格式:
权限修饰符 返回值类型 函数名(){ //业务逻辑 }
代码示例:
//定义返回值类型为String,权限为public的toStr方法 public String toStr() { //返回值 return name + " : " + age; }
类中局部变量和成员变量(类变量)
作用范围:
存储位置:
初始化值:
使用场景:
静态使用场景:
针对静态修饰的变量有两种调用方式
生命周期:
静态区中的变量(所属于类的) > 堆内存中对象里面的变量(所属于对象的) > 栈内存中变量(所属于当前的花括号)
注意:
在静态方法内部职能调用静态属性,如果想要调用非静态属性,必须先要获取到这个属性所属的对象。
静态使用场景注意事项:
成员变量
普通成员变量(实例变量)
成员函数
普通成员函数
静态成员函数
main函数是JVM运行java程序的入口。
格式:
public static void main(String[] args) { //业务逻辑 }
每个结构表示的意义:
格式:
static{ //业务逻辑 }
静态代码块一般放在类中,和构造代码块平级
作用:
可以负责对类进行初始化。
静态代码块什么时候执行:
当类被加载进内存的时候,静态代码块执行。
封装 继承 多态
封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装是一种信息隐藏技术,在java中通过关键字private实现封装。什么是封装?封装把对象的所有组成部分组合在一起,封装定义程序如何引用对象的数据,封装实际上使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。
代码示例:
//定义Person类 class Person { //封装的属性 String name; int age; //封装的方法 public void speak() { System.out.println(("name=" + name + ",age=" + age)); } }
使用关键字extends实现。
格式:
class Zi extends Fu{}
继承的好处:
继承的特点:
到底什么时候使用继承:
继承中的成员的特点
成员变量
this:是为了区分成员变化和局部变量重名的情况
super:是为了区分子父类中成员变量重名的情况
成员函数
当子父类中出现相同函数的时候,会出现函数的覆盖(重写,复写),也就是子类中的函数覆盖了父类中的同名函数
这个就是函数的重写(overwriter)
函数的重载(overload)
依据:只和参数列表有关
如果子父类中函数相同的时候,需要使用super调用父类中的同名函数
构造函数
默认情况下子类在创建对象的时候都会调用父类的无参的构造函数。需要使用super语句
注意,这个super语句默认是在子类的构造函数的第一行,没有显示,如果显式调用super语句的话,也必须写到子类构造函数的第一行。
this()和super()的用法类似
那也就意味着,在子类的构造函数中不能同时存在this和super语句。
小结:
代码示例:
//定义Person类 class Person { //定义类的属性 String name; int age; //定义类的方法 public void speak() { System.out.println(("name=" + name + ",age=" + age)); } } //继承Person类 class employee extends Person{ @Override public void speak() { System.out.println("this is employee"); } }
体现:
Animal a = new Cat();//animal是cat的父类 Inter i = new InterImpl();//interimpl是inter接口的实现类
作用:多态的存在提高了程序的扩展性和后期可维护性
前提:类与类之间需要存在继承或者实现关系,要有覆盖操作
弊端:只能调用父类或者接口中已经定义的功能,在执行的时候会执行对应子类或者实现类中的功能。
类型强制转换动作和判断实例动作(instanceof)一般会在一块使用。
if(c instanceof Dog){ Dog d = (Dog)c; d.lookDoor(); }
多态中成员的特点:
成员变量
编译的时候,看等号左边
执行的时候,看等号左边
非静态成员函数
编译的时候:看等号左边
执行的时候:看等号右边
静态函数
编译的时候,看等号左边
执行的时候,看等号左边
小结:
final关键字可以修饰不同东西
1:修饰类
这个类就是一个最终类,不能被继承。
2:修饰函数
这个函数就是一个最终函数,在子类中不能被覆盖。
3:修饰变量
这个变量的值就是一个最终值,不能被修改,只能被显式初始化一次。
final修饰的变量必须要被初始化。
一般使用final修改一个常量的时候会和static组合使用,注意:static和final的位置可以互换
如果在函数上定义static和final的时候,一般放在public后面 返回数据类型前面
小结:
如果类中有抽象函数,那么类也必须是抽象的。
抽象类的特点:
特点:
成员特点:
成员函数
接口中的所有函数默认情况下都是抽象的,并且权限修饰符默认都是public,所以在定义的函数的时候,public abstract都可以省略
成员变量
默认情况向接口中的所有变量都是被public static final修饰
特性:
类只能单继承
class A extends B//只支持这中格式
接口可以多实现
class A implements B,C,D//支持实现多个接口 BCD 都是接口
抽象类(普通类)里面一般定义的东西:
都是一些事物共性的属性或行为
接口里面一般定义的东西:
一些扩展的东西
class A extends AbstractDemo implements Inter,Inter2{ //业务逻辑 }
继承和实现的区别:
继承:extends
一个类继承一个抽象类,因为抽象类中可以存在非抽象方法,所以子类可以把父类中的非抽象方法直接继承过来使用。
实现:implements
因为接口中全部都是抽象方法,这些方法全部都需要进行实现,所以说一个类需要实现一个接口。
多继承的特性(了解)
interface A{} interface B{} interface C extends A,B{}//正确的 接口之间可以多继承 class A1{} class B1{} class C1 extends A1,B1{}//错误的,java中的类不支持多继承
boolean equals(Object obj)
:比较两个对象是否相等,默认是比较内存地址值,这个意义不大,所以在工作中如果需要对对象进行比较的话,一般会重写此方法,实现自己的比较逻辑。
String toString()
:默认会打印对象的名称和内存地址值,但是打印这个意义不是很大,所以工作中一般会进行覆盖,在这个方法中把对象的基本属性信息给打印出去
Class getClass()
:获取当前对象的字节码文件对象,然后根据这个对象就可以获取字节码中保存的类的名称等信息getName和getSimpleName
int hashCode()
:返回的是对象在内存中的地址值
格式:
class Outer//外部 { private int num; class Inter//内部类,可以在成员位置 { show(){ } } public void method(){ Inter inter = new Inter(); inter.show(); } }
特点:
什么时候需要定义内部类呢?
假设A类可以随意访问B类中的属性,但是B类在访问A类中的属性的时候,需要创建A类的对象,才能调用
class B{ class A{ } } class Body{//身体 priavte class Heart{//心脏 } public Heart method(){ if(是医生){ return new Heart(); } return null;//Heart h = null; } }
如何在main函数中获取内部类对象(前提条件:内部类没有私有化)
//外部类名.内部类名 变量名 = 外部类对象.内部类对象 //内部类和函数都是普通的 //Outer.Inter io = new Outer().new Inter(); //io.show(); //如果内部类是静态的时候 //Outer.Inter io1 = new Outer.Inter(); //io1.show(); //如果内部类和调用的函数都是静态 Outer.Inter.show();
注意:
内部类也可以放在函数内部
在这个位置的时候,需要注意:如果这个局部内部类访问到了函数的局部变量的时候,这个局部变量必须是final类型的。
内部类的命名:
Outer$1Inter.class Outer$Inter2.class Outer$1Inter.class Outer$1Inter3.class
Throwable
处理方法有两种:
1:try-catch代码块
try{ //待检测的代码,也就是在运行时可能出现问题的代码 }catch(Exception e){//Exception e = new ArithmeticException(); //对异常情况进行处理 }
2:throws Exception
工作中针对异常到底使用哪种处理方案呢?
如果这个异常我能处理,就处理,不能处理的就抛出去。
jvm默认对异常的处理方式是这样的
Exception包含两种异常
编译时异常:在编译的时候,如果没有处理,程序就会报错
如果调用的函数抛出了编译时异常,那么在使用这个函数的时候,必须要对这个异常进行处理。
包含Exception和(非runtimeException及其子类)
非编译时异常(运行时异常):编译时不会报错,运行的时候才会报错
这种异常在调用的时候不需要进行处理。因为一般抛出这种异常的时候是想希望让程序停掉。
runtimeException 以及子类
运行时异常,一般不建议使用try-catch进行捕获处理,如果真想处理,也可以使用try-catch
什么时候抛出runtimeException:
下面例子中在调用div之后的代码的运算逻辑需要使用x(除法运算的结果)的值,也就是说,
如果除法运算出错了,那么后面的代码再执行就没有意义了。
那么这个时候,就可以在div方法上抛出一个运行时异常,main方法再调用的时候就不需要进行处理了,
如果除法运算在执行的时候真是出现了问题,那么就希望把程序停掉即可。
class Demo11{ public static void main(String[] args) { Test t = new Test(); int x = t.div(10,0); System.out.println(x); System.out.println("hehe"+x); } } class Test{ //除法运算 public int div(int a,int b) throws RuntimeException {//这也是一种对异常的处理方法 return a/b; } }
try-catch-finally
组合可以有下面这几种
如果函数抛出的多个异常有父子关系,那么在写多个catch语句的时候,子类的异常需要先捕获,父类异常写在最下面的一个catch中。
父子类中进行函数覆盖的时候,如果父类的函数中抛出了异常,那么子类只能抛出父类异常的子类或者子集,子类中不能抛出未知的异常
如果子类中确实有新的异常产生,那么只能try-catch处理掉。
throws和throw
表示是解决某一个类问题最行之有效的方法。
Java有23种设计模式
比如单例设计模式
:这个设计模式可以保证在内存中一个对象只存在一份。
例子:现在有A程序和B程序,
使用场景:
代码实现过程: