封装、继承、多态
如果不同class(类)中,存在相同的函数(功能),在开发中这种编码方式会降低程序的编码效率、复用性降低。
之前函数,是把功能提取出来,是从class(类)中提取到函数;
为了解决编码效率低、复用性差:
把相同的功能(函数)提取出来,使用一个新的class来封装;
怎么去用封装好的Tool类:
创建实例的格式:
Tool t(实例名)=new Tool();
t.getMax(num1,num2);
"t"表示就是t下的 或者 t的功能或者函数
过程:一个函数中的功能体的过程
吃饭[买菜==》洗菜==》切菜==》做菜==》吃]
它是一种解决问题的方法;
它就是我们书写的函数(功能)。
对象:一个实体或者个体,指得是生活中的某个事物或者某类事物。
面对具体封装了函数的对象(对象在程序中就是类[class])
面向对象其实是一种解决问题的方案。
面向对象是基于面向过程的;
面向对象举例:
组装电脑
面向过程:解决这个问题
1、去网上查询硬件参数和价格
2、去电脑城中的商家咨询价格
3、赛选满意商家,和它谈价格
4、监空整哥电脑的安装流程
5、付钱,电脑扛回家
面向对象:解决这个问题
1、找一个懂电脑硬件人
2、告诉他价格和配置
3、给他钱,让他帮你买
4、等电脑回来
1、他都是解决问题的方法
面向对象和面向过程了两个概念是不冲突。面向对象是基于面向过程的;
面向过程:
程序中组成的单位:函数。由若干函数组成。
面向对象:
程序中组成但是:类(class)
对象在需求中使用(伪代码):
案例1:人开门
名词:人 和 门
人{
//特征
姓名;
性别;
//功能
开门(门){
门.开门();
}
}
门{
//特征
门锁;
//功能
开门(){
}
关门(){
}
}
调用方法:
人 r=new 人();
门 m=new 门();
r.开门(m);
案例2:
老师用电脑上课
名词提取:电脑 老师
电脑{
//特征
CUP;
内存;
//功能
开机(){}
运行(){}
关机(){}
}
老师{
//特征
姓名;
性别;
//功能
上课(电脑){
电脑.开机();
电脑.运行();
}
}
电脑 d=new 电脑();
老师 l=new 老师();
l.上课(d);
对象在代码中的体现:
成员变量:类中成员
使用new 关键字创建类的对象
创建格式: 类名 对象名(实例名)=new 类名();
使用 对象名.成员变量(成员函数)去访问类中属性或方法
在创建对象(new的时候),JVM在开辟完对象的堆内存空间后,会把所有的成员变量加载到所开辟的空间下,然后会对所有的
成员变量进行默认初始化;
String null
int 0
float 0.0
double 0.0
char 空
boolean flase
1、类就是描述事物;对象是所描述事物的实例(使用实例名去访问类中成员)
2、现有类的描述(class),后有描述类的对象(类名 实例名=new 类名();)
成员变量(属性):定义类中的变量
局部变量:定义在函数中或者语句中(for if)的变量
区别:
定义上:
局部变量定义在函数内部,属于函数;
成员变量定义在类的内务,属于类的;
内存的存储上:
局部变量随着函数的入栈而存在,随着函数的出栈而销毁,存储在栈内存中
成员变量是随着对象的创建而存在,随着对象被标记为垃圾而销毁,存储在堆内存中。
使用上:
局部变量直接使用;
成员变量必须在对象创建完成之后,使用对象去调用;
初始值:
局部变量在定义时候必须要指定初始值;
成员变量可以不指定初始值,随着对象的创建会有初始值;
生命周期:
局部变量的生命周期比较短
成员变量是随着对象的创建到对象的销毁来计算生命周期的
封装、继承、多态
其实就是包装的意思:
它会把事物的部分的细节给隐藏
封装的体现:
1、函数:封装了一些功能的代码;
2、类:封装是事物共性的信息(共性的特征和功能)
封装的好处:
1、提高了程序的复用性,方便我们程序的维护
2、封装可以隐藏事物的细节,所以需要对外提供一些可以访问的方式(函数);
3、提升了程序的安全性
属性关键字:
public:公共的,公有的。
private:私有的,隐藏的,public的反义词
属性使用private关键字,在其他类中不能使用这个属性;在自己本身类当中是可以使用
在开发中,使用封装类的时候,通常会把属性(成员变量)修饰为:private,然后提供一些对外访问的public方法
对外访问的方法:
通常只有两种(操作变量:给变量赋值和获取变量的值)
也就是
赋值:public void setXxx(数据类型 变量)
public void setCode(Int c)
取值:public 返回类型 getXxx();
Xxx:就是属性名,属性名的首字母大写
构造函数(构造方法):
在创建对象时(使用New关键字的时候),自动调用的方法(JVM自己调用的),称为构造函数;
构造方法的体现:
1、构造方法的方法名和类名要完全相同(大小写都一样)
2、构造方法中没有返回值类型:不能书写void
3、构造方法中没方法值。(构造方法是在调用完之后,自动销毁)
构造方法的作用:
为了初始化对象用的。
所有的类当中,都有一个默认的构造方法
默认的构造方法
就是指没有带参数的构造方法;
没有写构造函数,java文件在编译的时候,jvm自动回给我加上默认
构造函数:类名(){ }
注意:
如果类当中,自己书写了带参数的构造函数。然后在调用的时候,需要使用不带参数的构造函数,那必须自己在类中,添加该构造函数。
构造函数 与 一般函数的区别:
1、调用的角度:
一般函数:在创建对象以后,使用对象名去调用一般函数;(创建对象后)
构造函数:在创建对象时,自动调用构造函数;(创建对象时)
2、调用的次数:
一般函数:在创建对象完后,可以调用一般函数,(多次调用)
构造函数:在创建对象时,自动调用一次,调用完之后,自动销毁(一次调用)
3、作用上
一般函数:用来描述事物的行为(功能)
构造函数:用来初始化对象
this:
表示当前对象的引用
当成员变量和局部变量名称相同的时候,他有优先级:先内后外,先使用函数中局部变量
作用:
this可以在构造函数中去调用其他的构造函数,还可以调用当前所引用对象的成员(方法和属性)
this还可以区分成员变量和局部变量名称相同
使用方式:
this.成员(属性和方法)
this.name(成员变量)=name(局部变量)
static
静态,是java中的修饰符(可以修饰类、修饰变量、修饰方法)
可以修饰成员变量、成员方法。不可修饰构造函数
使用:
被static修饰的成员,除了可以使用对象访问(对象名.成员),还可以使用类名访问(类名.成员)
java程序内存分为5个部分:
cpu 本地方法 方法区 栈 堆
方法区:
存放class和static
被static修饰的成员,都存放在方法区中的静态区域
当使用类名.方法名,就是直接去方法区中的静态区域调用这个静态方法。
静态使用注意事项
1、静态方法中只能调用静态方法和静态变量。不能调用非静态成员(普通方法和成员变量)
静态方法也叫类方法,静态变量也叫类变量;(直接使用类去调用)
普通方法也叫实例方法;
静态方法或静态的变量可以使用对象访问外,还可以直接使用类去访问
2、普通方法可以调用静态方法和静态变量;
3、在静态方法中,不适用以下关键字:this,super
静态变量个成员变量的区别:
1、所属不同
静态变量属于类
成员变量属于对象
2、调用不同
成员变量只能用对象名去调用
静态变量可以用个对象名去调用,也可以用类名去调用
3、存储不同
静态变量时存在方法区下的静态区域中
成员变量存在堆中
4、加载不同
静态变量是随着类的加载而存在
成员变量时随着对象创建而存在
java的三种代码块
静态代码块、构造代码块、局部代码块(后两种基本不用)
静态代码块
用法:
static{//静态代码块}
静态代码快的特点:
当类被加载时,随着类的加载而执行的代码,静态代码块只会执行一次(JVM加载类只会加载一次)
总结:
静态代码,会在构造代码块前执行。随着类的加载而执行
构造代码块:
格式:{
}
特点:
创建对象时,随着构造方法的调用,在构造方法中代码没有执行之前,存在隐式三步:
第一步:执行super语句
第二步:显示初始化非静态成员变量
第三步:执行构造代码块
小结:
构造代码块,在创建对象的时候,会执行一次(每次创建一个对象,就执行一次)
局部代码块:
类和对象的加载过程:
类加载:
jvm启动时,会去方法区找这个类,不存在就会加载到方法区里面:
先加载非静态的成员(构造函数),再加载静态成员;
加载静态成员变量的时候,先初始化默认值,在显示初始值
加载显示完成之后,就会执行静态代码块;
创建对象加载:
1、new 就会去堆中开辟空间,并分配一个内存地址
2、开辟完成后,把类中所有的非静态成员变量加载到开辟的堆内存中
3、然后进行默认初始化
4、调用构造函数后,先做下面三步:
存在隐藏的三步操作:
1、执行super
2、显示非静态成员变量的初始值
3、执行构造代码块
执行构造方法里面的代码,执行构造方法完成后,构造方法出栈;
标题一张图看懂代码块使用内存图解
需求:描述一个学生、工人
在java中使用继承来创建类与类之间的关系
关键字:extends
使用方法:
class 类名1 extends 类名2{
}
特点:特点:使用extends,父类私有化的成员是无法被继承;、
小结:使用extends关键字,私有成员(private)不能继承;
Preson:父类、基类、超类
学生类、工人类:子类、派生类
注意:
使用java关键字extends ,继承关系必须符合 is-a(是同一类型或者同一事物)
学生是个 人
工人 是 人
小轿车 是车
大巴车 是车
注意:
java语言只支持单一继承,不支持多继承;
class a{}
class b extends a{} //可以的
class c extends a,b{} //不行的,报错
不支持多继承的原因:
当多个父类中存在相同的功能时,子类继承了父类的功能,但是子类去调用父类中相同的功能时候,就会无法判断调用
哪一个,造成调用的不确定性。
java中支持多层继承:(多重继承)
class a{} //爷爷
class b extends a{} //父亲
class c extedns b{} //孙子
注意:
先调用子类的构造方法,因为里面有隐式三步(三步里面有个super),所以到super就去执行父类的构造函数。
继承中成员的特点:
成员变量
1、档父类与子类中存在相同的成员变量时,子类调用改变量名时,会优先调用子类中的成员变量名
2、不建议在子类中定义与父类相同的成员变量名
3、如果存在相同的,要使用父类中的成员变量,super.成员变量
成员方法
重写
当子类和父类中存在一模一样的方法,就叫做重写
特点:
会让程序的可夸张和维护性更好
方法(函数)的特点
重载
发生在一个类中
方法名相同、参数列表不同和返回值类型没有关系
重写
发生在子父类中(继承中)
方法名相同、参数列表相同、返回值类型相同
重写的应用:
需求:使用java实现手机来电显示、显示电话号码
继承重写的好处:
1、提高程序的复用性、扩展性、后期维护
this 和 super区别:
相同点:
都是用来引用对象的。
不同点:
this是引用当前对象
super是引用父类对象
重写注意的细节:
1、父类中的方法如果是private,不参与子类方法的重写(子类中不能重写父类中private修饰的方法)
private它是访问权限最小,只限于本类中使用。如果子类和父类中书写了一个相同的private方法时,该方法是属于本
类的,和重写没关系。
2、子类中重写方法的权限必须大于或等于父类中被重写方法的权限
3、父类中的方法是静态的话,子类的方法也必须是静态。
final关键字
父类中的某些方法不允许子类去重写
在java中我们就使用 final 关键进行修饰;
final修饰方法格式:
访问修饰符 final关键字 返回值类型 方法名(参数列表)
注意:
方法加上final关键字,是代表不能重写,但是能被继承。
方法的修饰符是private ,代表该方法是不能被继承和重写;
final修饰成员变量,会变成常量。常量是必须要赋值的,一但修饰为final,就不能更改了。
final修饰类,被final修饰的类,是不能被继承
抽象类:
需求:用java来描述两个动物:猫 和 狗
关键字:
abstract
当一个事务中的功能没有具体的功能体时,或者是事物无法描述清楚时,称为抽象
抽象类特点:
1、抽象类不能被实例化(不能创建对象)
2、子类继承抽象类,必须重写抽象类中所有的抽象方法后,子类才能创建对象。
3、被abstract修饰的方法,必须包含在抽象类当中。(抽象类当中是可以写普通方法)
抽象类的应用:
需求:
公司中有:
程序员:姓名、工号、薪水、工作内容
项目经理:姓名、工号、薪水、工作内容、奖金
分析:
描述的对象:
程序员
属性:姓名、工号、薪水
方法:工作内容
项目经理
属性:姓名、工号、薪水、奖金
方法:工作内容
共性的内容:
属性:姓名、工号、薪水
方法:工作内容
所谓的设计模式其实就是经过大量的时间的积累和总结,把一些常见的问题进行归纳,以后再开发中遇到类似的问题直接套用,来解决问题。
单例设计模式主要解决的问题:
确保创建的对象是唯一的。(保证创建的对象在堆内存中开辟的空间只有一个)
分析:怎么能才保证创建的对象是唯一的;
分析1:只要使用new去创建的对象,就会产生多个对象;
反向思考:是不是不能去new,就不能产生对象。
分析2:不让其他类去创建对象(不能new),那这个对象怎么出现?
我们本类(自己)可以去创建对象
分析3:自己本类创建了对象,是属于自己的,要让其他的类去使用这个对象的话,对外提供一些可以访问到所创建对象的方法,让其他的类去调用。
基于上面的分析,怎么去实现:
第一步:把构造函数设置为:private;这样就无法让其他的类创建对象。
第二步:直接在本类中创建一个自己的对象
第三步:对外提供一些方法,把创建的对象返回出来,让其他类使用
如果事物遇到扩展的功能,则使用接口来解决
接口的关键字:interface
在java中,定义接口内的陈冠修饰符已经固定化的
1、成员变量
固定的修饰符格式:public final static num=100;
书写在接口中的成员变量,全部是常量(必须赋值),接口中的常量只能被获取,不能被修改
2、成员方法
固定的修饰符格式:public abstract
实现接口的方式:
使用关键字:implements实现接口
接口特点:
1、接口中只能定义常量和抽象方法(有固定的修饰符格式)
2、接口不能被实例化
3、实现了接口的子类,必须把接口中的所有抽象方法全部重写后,才可以创建子对象
接口是为了对事物功能的扩展,但是接口的核心思想就是解决多继承问题,使用接口多实现的方式来代替多继承;
接口多实现,接口多继承
接口和抽象的区别:
接口中定义的全部是仇晓方法,而抽象类中可以定义普通方法;
接口中定义的变量都是常量(必须赋值);而抽象类中可以定变量
接口中没有构造方法;而抽象类中具有抽象方法的;
接口是用来描述事物功能的扩展;抽象类是描述事物共性的内容;
接口可以多实现(解决java中只能单继承的问题);而抽象类只能单一使用
事物以多种形态来表现。
java中,我们可以使用对象的具体类型来描述
例子:Dog(具体类型) dog(对象)=new Dog();//这就是对象具体类型来描述
也可以使用对象的父类型来描述:
Aniaml an=new Dog(); //使用父类类型描述对象
注意:使用多态有个前提:必须是继承关系或者实现关系
多态的体现:
父类(接口)的引用指向子类对象
例子:
父类 引用变量=new 子类();
接口 引用变量=new 子类();
多态好处:
提高程序中代码的扩展性
多态的前提:
使用多态必须是继承或者实现关系
通常子类需要把父类中的方法进行重写。
多态弊端:
只能操作父子类公有的方法,不能操作子类中特有的方法;
如何解决这个弊端:
多态的转型:
向上转型:
Aniaml an=new Dog();
Aniaml 父类类型 an 父类引用 new Dog() 子类对象
使用父类引用(an)指向子类对象时,其实子类类型已经向上提升为父类型;
向下转型:
Aniaml an=new Dog();
Dog dog=(Dog)an;
java.lang.ClassCastException:在使用多态中的向下转型时,会常遇到ClassCastException(类型转换异常)
例子:Aniaml an=new Dog();
Cat cat=(Cat)an; //会引发类型转换异常
向下转型遇见类型转换异常时,使用关键字 instanceof 来对转换的类型进行判断
小结:
向上转型:
为了提高程序中代码的扩展性
不需要使用子类中特有的方法
向下转型:
需要用到子类中特有的方法
转型的时候,使用instanceof(判断) 来避免 ClassCastException异常
没有抽象方法的抽象类
接口与子类之间新增一个抽象类去实现这个接口。然后子类继承这个抽象类。然后重写子类需要的功能方法。
是指在程序运行中出现的问题
java中存在的两种问题:异常、错误(错误是比异常严重)
描述其中异常信息的类
java.lang.ArrayIndexOutOfBoundsException
描述错误的类
java.lang.OutOfMemoryError
异常:
在程序运行中发生的议程。通过这个异常有针对性的处理方案(程序员自己写)
错误:
错误都是系统级别,通常是不会有针对性的处理方案。
通常是程序在书写的时候,产生JVM在操作内存上出现的问题
过程:
当JVM运行到异常时,这时程序就不会向下执行,会在发生异常的位置进行详细的描述:
描述内容:问题的名称、问题发生的位置、问题的内容
JVM会把这些描述的信息封装到一个类中:ArrayIndexOutOfBoundsException(类由JAVA自己提供)
他会把描述异常的类丢出去。丢给调用错误方法的地方(main)
throw new ArrayIndexOutOfBoundsException(“异常的信息”)
抛出异常步骤:
1、创建异常类的对象,并且给对象提供异常信息(程序写)
2、把异常类的对象,给抛出去 使用throw关键字
自定义异常
异常类继承 RuntimeException
然后书写无参和有参构造函数,构造函数调用super()方法
java中,提供了两种处理异常的方法:声明、捕获
声明
使用关键字throws对异常进行声明(throw和throws配合使用)
声明的格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名2...{
//语句
//Exception(throw)
}
捕获:
就是自己处理异常
java中捕获的关键字: try catch finally
try{}catch(异常类 引用变量){//处理异常的代码}finally{//永远会执行的代码}
或者
try{}catch(异常类 引用变量){//处理异常的代码}
throw和throws的区别
throw是书写在方法内,用来跑出异常
throws是书写在方法上,用来生命该方法中出现的异常类,可以声明多个异常类,用逗号隔开
API:JAVA提供的封装了不同功能的类
面向对象的思想:遇到需求的时候,先去找是都有解决问题的封装类。(java提供了很多封装了不同功能的类)
Object类:是所有类的父亲,所有定义的类,都可以使用Object类中的方法
equals(Object obj);其他的对象是否与此对象相等。----比较两个对象
包的概念:
问题1:如果电脑同一个目录有两个文件名称相同是否放在一起?不可以
问题2:要放在一起?在这个文件目录下面新建两个目录,再分别存储这两个文件
java中的包在计算机操作系统上的体现:指的就是文件夹。
包的关键字:Package
com.公司名称.项目名称.程序员名称.功能类的名称
java中包的命名规范:
包名所有的字母都是小写字母
当有多层次包名时,每个包名中间用点(.)分隔
包之间使用访问权限:
访问方式1:包名1.包名2.包名3.类名 对象引用=new 包名1.包名2.包名3.类名();
访问方式2:(推荐)
java关键字:import
使用方法:
import 包.类;//导入包中下的一个类
import 包.类.*; //导入包下所有类
注意:
当前包中有和类中个引用的类名称相同时候,类里面调用相同类的时候,就会选择引入的类
包与包之间的权限:
public | protected | private | 默认 | |
同一个类中 |
YES | YES | YES | YES |
同一个包中不同类 | YES | YES | NO | YES |
同一个包中的子类 | YES | YES | NO | YES |
不同包中的不同类 | YES | NO | NO | NO |
不同包中的子类 | YES | YES | NO | NO |
public 公共的,访问权限最大,没有限制,随便使用
private:只能在本类
public > protected > 默认 > private
String类
例:“张三” java中只要被双引号包含起来的内容就是字符串常量
String 他是一个描述字符串的类(不是一种数据类型)
String str="csdn";代表是一个String对象
String str=new String("csdn");