碎碎念~
啊重新整理一遍这些笔记才发现自己真的有好多不清晰的地方和没有完全理解的地方,后面封装啊抽象啊接口的语法并且没有完全理解,所以要趁着课程设计赶快好好整理好思绪啊加油加油
目录
面向对象概述
面向过程和面向对象有什么区别?
从语言方面出发:
对于C语言来说,是完全面向过程的。(面向过程强调以我中心)
对于C++语言来说,是一半面向过程,一半是面向对象。(C++是半面向对象的)
对于Java语言来说,是完全面向对象的。
什么是面向过程的开发方式?
面向过程的开发方式主要的特点是:
注重步骤,注重的是实现这个功能的步骤。
第一步干什么
第二步干什么
....
另外面向过程也注重实现功能的因果关系。
因为A所有B
因为B所以C
因为C所以D
.....
面向过程中没有对象的概念。只是实现这个功能的步骤以及因果关系。
面向过程有什么缺点?(耦合度高,扩展力差。)
面向过程最主要是每一步与每一步的因果关系,其中A步骤因果关系到B
步骤,A和B联合起来形成一个子模块,子模块和子模块之间又因为因果
关系结合在一起,假设其中任何一个因果关系出现问题(错误),此时
整个系统的运转都会出现问题。(代码和代码之间的耦合度太高,扩展力
太差。)
螺栓螺母拧在一起:耦合度高吗?
这是耦合度低的,因为螺栓螺母可以再拧开。(它们之间是有接口的。)
螺栓螺母拧在一起之后,再用焊条焊接在一起,耦合度高吗?
这个耦合度就很高了。耦合度就是黏连程度。
往往耦合度高的扩展力就差。
耦合度高导致扩展力差。(集成显卡:计算机显卡不是独立的,是集成到主板上的)
耦合度低导致扩展力强。(灯泡和灯口关系,螺栓螺母关系)
采用面向过程的方式开发一台计算机会是怎样?
这台计算机将没有任何一个部件,所有的都是融合在一起的。
你的这台计算机是一个实心儿的,没有部件的。一体机。
假设这台一体机的任何一个“部位”出问题,整个计算机就不能用了,
必须扔掉了。(没有对象的概念。)
采用面向对象的方式开发一台计算机会是怎样?
内存条是一个对象
主板是一个对象
CPU是一个对象
硬盘是一个对象
然后这些对象组装在一起,形成一台计算机。
假设其中CPU坏了,我们可以将CPU拆下来,换一个新的。
(就是耦合度很低啦)
面向过程有什么优点?(快速开发)
对于小型项目(功能),采用面向过程的方式进行开发,效率较高。
不需要前期进行对象的提取,模型的建立,采用面向过程
方式可以直接开始干活。一上来直接写代码,编写因果关系。
从而实现功能。
什么是面向对象的开发方式?
采用面向对象的方式进行开发,更符合人类的思维方式。(面向对象成为主流的原因)
人类就是以“对象”的方式去认识世界的。
所以面向对象更容易让我们接受。
面向对象就是将现实世界分割成不同的单元,然后每一个单元
都实现成对象,然后给一个环境驱动一下,让各个对象之间协
作起来形成一个系统。
对象“张三”
对象“香烟”
对象“打火机”
对象“吸烟的场所”
然后将以上的4个对象组合在一起,就可以模拟一个人的抽烟场景。
其中“张三”对象可以更换为“李四”
其中“香烟”也可以更换品牌。
其中“打火机”也可以更换。
其中“吸烟的场所”也可以更换。
采用面向对象的方式进行开发:
耦合度低,扩展力强。
找一个合适的案例。说明一下面向对象和面向过程的区别?
蛋炒饭:
鸡蛋和米饭完全混合在一起。没有独立对象的概念。
假设客户提出新需求:我只想吃蛋炒饭中的米饭,怎么办?
客户提出需求,软件开发者必须满足这个需求,于是
开始扩展,这个软件的扩展是一场噩梦。(很难扩展,耦合度太高了。)
盖饭:
老板,来一份:鱼香肉丝盖饭
鱼香肉丝是一道菜,可以看成一个独立的对象。
米饭可以看成一个独立的对象。
两个对象准备好之后,只要有一个动作,叫做:“盖”
这样两个对象就组合在一起了。
假设客户提出新需求:我不想吃鱼香肉丝盖饭,想吃西红柿鸡蛋盖饭。
这个扩展就很轻松了。直接把“鱼香肉丝”对象换成“西红柿鸡蛋”对象。
目前先听一下,需要三四年的时候才能彻底领悟面向对象。
面向过程主要关注的是:实现步骤以及整个过程。
面向对象主要关注的是:对象A,对象B,对象C,然后对象ABC组合,或者CBA组合.....
2、当我们采用面向对象的方式贯穿整个系统的话,涉及到三个术语:
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
整个软件开发的过程,都是采用OO进行贯穿的。
实现一个软件的过程:
分析(A) --> 设计(D) --> 编程(P)
在软件公司当中,一般同事与同事之间聊天,有的时候会突然说出来一个英语单词。
这种情况是很常见的。所以一些术语还是要知道的,不然会闹出笑话。
leader 领导/经理/组长
team 团队
PM 项目经理(整个项目的监管人)Project Manager
3、面向对象包括三大特征
封装
继承
多态
任何一个面向对象的编程语言都包括这三个特征
例如:
python也有封装 继承 多态。
java也有封装 继承 多态。
注意:java只是面向对象编程语言中的一种。
除了java之外,还有其它很多很多的编程语言也是面向对象的。
以上三个特征的名字先背会,后面一个一个进行学习。
4、类和对象的概念
面向对象当中最主要“一词”是:对象。
什么是类?
类实际上在现实世界当中是不存在的,是一个抽象的概念。
是一个模板。是我们人类大脑进行“思考、总结、抽象”的一个
结果。(主要是因为人类的大脑不一般才有了类的概念。)
类本质上是现实世界当中某些事物具有共同特征,将这些共同
特征提取出来形成的概念就是一个“类”,“类”就是一个模板。
明星是一个类
什么是对象?
对象是实际存在的个体。(真实存在的个体)
宋小宝就是一个对象
姚明就是一个对象
刘德华就是一个对象
....
宋小宝、姚明、刘德华这3个对象都属于“明星”这个类。
在java语言中,要想得到“对象”,必须先定义“类”,“对象”是通过“类”
这个模板创造出来的。
类就是一个模板:类中描述的是所有对象的“共同特征信息”
对象就是通过类创建出的个体。
这几个术语你需要自己能够阐述出来:
类:不存在的,人类大脑思考总结一个模板(这个模板当中描述了共同特征。)
对象:实际存在的个体。
实例:对象还有另一个名字叫做实例。
实例化:通过类这个模板创建对象的过程,叫做:实例化。
抽象:多个对象具有共同特征,进行思考总结抽取共同特征的过程。
类 --【实例化】--> 对象(实例)
对象 --【抽象】--> 类
类是一个模板,是描述共同特征的一个模板,那么共同特征包括什么呢?
潘长江对象:
名字:潘长江
身高:165cm
打篮球:非专业的,自己玩儿呢,无所谓了
学习:考试80分
姚明对象:
名字:姚明
身高:240cm
打篮球:NBA专业球员,打篮球非常棒
学习:考试100分
共同特征包括哪些?
名字、身高都属于名词(状态特征)
打篮球、学习都属于动词(动作特征)
类 = 属性 + 方法
属性来源于:状态
方法来源于:动作
public class 明星类{
//属性-->状态,多见于名词
名字属性;
身高属性;
//方法-->动作,多见于动词
打篮球方法(){
}
学习方法(){
}
}
理想同学、未来同学,他们俩有没有共同特征呢?
有共同特征,就可以抽象一个类模板出来。
可以定义一个学生类(Student)
public class Student {
// 属性
// 姓名
// 性别
// 身高
// 方法
public .... sing(){
}
public .... dance(){
}
public .... study(){
}
....
}
5、思考:“java软件工程师”在开发中起到的一个作用是什么?
我们为什么要做软件开发?
说的大一些是为了人民服务。解决现实生活当中的问题。
软件开发既然是为了解决现实世界当中的问题,那么首先
java软件必须能够模拟现实世界。
其实软件是一个虚拟的世界。
这个虚拟的世界需要和现实世界一一对应,这才叫模拟。
6、类的定义
6.1、怎么定义一个类,语法格式是什么?
[修饰符列表] class 类名 {
//类体 = 属性 + 方法
// 属性在代码上以“变量”的形式存在(描述状态)
// 方法描述动作/行为(以“方法”的形式存在)
}
注意:修饰符列表可以省略。
6.2、为什么属性是“以”变量的形式存在的?是因为属性对应数据,数据存放到变量
假设我们要描述一个学生:
学生包括哪些属性:
学号: 110
姓名:"张三"(带双引号的字符串)
性别:'男' (true/false)
住址:"深圳宝安区"
答案:是因为属性对应的是“数据”,数据在程序中只能放到变量中。
结论:属性其实就是变量。
变量的分类还记得吗?
变量根据出现位置进行划分:
方法体当中声明的变量:局部变量。
方法体外声明的变量:成员变量。(这里的成员变量就是“属性”)
6.3、请大家观察“学生对象1”和“学生对象2”的共同特征,然后再利用java语言
将该“学生类”表述/表达出来。(这里只表达属性,不表达方法.)
变量有一个特点:必须先声明再赋值才能访问,成员变量可以不用
在方法体以外的变量(成员变量)
成员变量被分为 类变量和实例变量两种.
类变量
有static修饰符的,由static修饰的变量即静态变量,其实质上就是一个全局变量。
如果某个内容是被所有对象所共享,那么该内容就应该用静态修饰;没有被静态修饰的内容,其实是属于对象的特殊描述。
不同的对象的实例变量将被分配不同的内存空间, 如果类中的成员变量有类变量,那么所有对象的这个类变量都分配给相同的一处内存,改变其中一个对象的这个类变量会影响其他对象的这个类变量,也就是说对象共享类变量。
实例变量
定义成员变量时没有 static 修饰符的就是实例变量.
静态变量:属于类,他是一个类级 变量
成员变量:属于对象,他是对象级别的变量。
静态变量:存放在方法区的静态区
成员变量:存放于堆内存
静态变量:随着类的加载而创建,随着jvm的退出而销毁。
成员变量:只有new对象才会创建,随着对象的销毁而销毁。
静态变量:既可以通过类名调用,也可以通过对象名调。
成员变量:只可以通过对象名调用。
年龄:int
学号:int 类型
姓名:String
性别;char或者boolean
住址:String
定义XueSheng类,编写成员变量作为属性
public class XueSheng{.//这个程序编译之后,会生成xuesheng.class字节码文件
//
int xuehao;
String xiaoming;
int nianling;
boolean xingbie;
String zhuzhi;
}//类的定义,通过一个类可以创建多个对象
对象的创建和使用
语法:new 类名();//new是一个运算符,专门负责对象的创建
类是模板,通过一个类,是可以创建多个对象的
类名是一种引用数据类型
类型(引用类型) 变量名 = new 类名();//和int i = 10一个道理
java中所有的“类”都属于引用数据类型。//这句就解释了变量名前面是类名
定义变量必须指定类型
对象的个数没有限制,只要有模板类就行
数据类型包含两种:基本和引用
7、关于编译的过程
按说应该先编译XueSheng.java,然后再编译XueShengTest.java
但是对于编译器来说,编译XueShengTest.java文件的时候,会自动
找XueSheng.class,如果没有,会自动编译XueSheng.java文件,生成
XueSheng.class文件。
第一种方式:
javac XueSheng.java
javac XueShengTest.java
第二种方式:
javac XueShengTest.java
第三种方式:
javac *.java
8、在语法级别上是怎么完成对象创建的呢?
类名 变量名 = new 类名();
这样就完成了对象的创建。
//变量名前面到底是类型还是类名啊
局部变量存储在栈内存中
在Java中,new操作符的本意是分配内存,new一个类就是把这个类实例化为对象。
程序执行到new操作符时,会根据new后面的类型分配相应的内存空间。接着调用构造函数,填充对象的各个域,这一步叫做对象的初始化。构造方法返回后,一个对象创建完毕,就可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
对于 XueSheng s = new XueSheng(); 和 int i = 100; 的区别:
i是变量名
int是变量的数据类型
100是具体的数据。
s是变量名(s不能叫做对象。s只是一个变量名字。)
XueSheng是变量s的数据类型(引用数据类型)
new XueSheng() 这是一个对象。(学生类创建出来的学生对象。)
9、什么是实例变量?
对象又被称为实例。
实例变量实际上就是:对象级别的变量。
public class 明星类{
double height;
}
身高这个属性所有的明星对象都有,但是每一个对象都有“自己的身高值”。
假设创建10个明星对象,height变量应该有10份。
所以这种变量被称为对象级别的变量。属于实例变量。
实例变量在访问的时候,是不是必须先创建对象?
是
成员变量中的实例变量,必须先创建对象,通过“引用”来访问
怎么访问实例变量?
system.out.println(引用.对象)
10、对象和引用的区别?
对象是通过new出来的,在堆内存中存储。
引用是:但凡是变量,并且该变量中保存了内存地址指向了堆内存当中的对象的。
1、画内存图注意事项:
第一:大家在内存图上不要体现出代码。内存上应该主要体现“数据”。
第二:大家画图的时候,图上的图形应该有先后顺序,先画什么,再
画什么,必须是有顺序的,而不是想起来这个画这个,想起来那个画那个。
程序代码是有执行顺序的,程序执行到哪里你就画哪里就行了。
2、为什么要画内存图(非常重要)?
第一:有了内存图,程序不运行,我也知道结果。(可以推算出结果)
第二:有了内存图,有助于你调试程序。
画内存图是对Java运行机制的一种理解。不知道运行机制,以后复杂的
程序出现错误之后你是不会调试的,调不明白。
3、程序在什么情况下会出现空指针异常呢?
空引用 访问 "对象相关"的数据时,会出现空指针异常。
垃圾回收器主要针对堆内存。
4、方法在调用的时候参数是如何传递的?
实际上,在java语言中,方法调用时参数传递,和类型无关,都是将变量中保存
的那个“值”传过去,这个“值”可能是一个数字100,也可能是一个java对象的内存
地址:0x1234
记住这句话:不管是哪一种数据类型的传递,都是将“变量中保存的那个值复制一份传递过去。”
5、构造方法。(用来创建对象的)
5.1、当一个类中没有提供任何构造方法,系统默认提供一个无参数的构造方法。
这个无参数的构造方法叫做缺省构造器。
5.2、当一个类中手动的提供了构造方法,那么系统将不再默认提供无参数构造方法。
建议将无参数构造方法手动的写出来,这样一定不会出问题。
5.3、无参数构造方法和有参数的构造方法都可以调用。(方法重载)
Student x = new Student();
Student y = new Student(123);
5.4、构造方法支持方法重载吗?
构造方法是支持方法重载的。
在一个类当中构造方法可以有多个。
并且所有的构造方法名字都是一样的。
方法重载特点:
在同一个类中,方法名相同,参数列表不同。
5.5、对于实例变量来说,只要你在构造方法中没有手动给它赋值,
统一都会默认赋值。默认赋系统值。
*构造方法
构造方法需要掌握的知识点:
- 构造方法有什么作用?
构造方法的主要作用就是创建对象。构造方法的主要作用就是为对象成员变量赋初始值,总是与new运算符一起使用在创建对象的语句中——也就是说,只要你new一个对象出来,就会相应地调用这个类的构造方法。有参数的构造方法可以对对象进行初始化,但建议写了有参的构造方法后再写一个无参的空的构造方法,便于创建一个对象而不给它的成员变量赋初值。要注意,自己写了有参的构造方法,编译器是不会再补充一个缺省构造方法的。
- 构造方法怎么定义,语法是什么?
1.语法:
【public】方法名=类名([参数列表]){
//方法体
}
2.特点:
1.构造方法方法名与类名一致;
2.构造方法不能有返回值;
3.构造方法只能通过new来完成调用;
对比普通方法:对象名.属性 对象名.方法
4.允许有多个构造方法,但参数列表不能相同-----重载
- 构造方法怎么调用,使用哪个运算符?
4.什么是缺省构造器?
无参数的构造方法
5.怎么防止缺省构造器丢失?
建议把无参构造方法手动写出来
6.实例变量在类加载是初始化吗?实例变量在什么时候初始化?
实例变量是在构造方法执行的过程中完成初始化的,完成赋值的
编译器检测到该方法名“studen”发现这个名字和类名不一致,会认为这是一个普通方法,应该有返回值,但是没有写返回值类型,所以报错了
6、封装
6.1、面向对象的三大特征:
封装
继承
多态
有了封装,才有继承,有了继承,才能说多态。
6.2、面向对象的首要特征:封装 。什么是封装?有什么用?
现实生活中有很多现实的例子都是封装的,例如:
手机,电视机,笔记本电脑,照相机,这些都是外部有一个坚硬的壳儿。
封装起来,保护内部的部件。保证内部的部件是安全的。另外封装了之后,
对于我们使用者来说,我们是看不见内部的复杂结构的,我们也不需要关心
内部有多么复杂,我们只需要操作外部壳儿上的几个按钮就可以完成操作。
那么封装,你觉得有什么用呢?
封装的作用有两个:
第一个作用:保证内部结构的安全。
第二个作用:屏蔽复杂,暴露简单。
在代码级别上,封装有什么用?
一个类体当中的数据,假设封装之后,对于代码的调用人员来说,
不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问了。
另外,类体中安全级别较高的数据封装起来,外部人员不能随意访问,
来保证数据的安全性。
6.3、怎么进行封装,代码怎么实现?
第一步:属性私有化(使用private关键字进行修饰。)
被这个关键字修饰之后,该数据只能在本类中访问,出了这个类,age属性就无法访问了
第二步:对外提供简单的操作入口。
外部程序通过调用以下的代码来完成访问
1、封装的代码实现两步:
但是我感觉我好像还是没有很懂set get方法是怎么操作的啊
第一步:属性私有化
第二步:1个属性对外提供一个set和get方法。外部程序只能通过set方法修改,只能通过get方法读取,
可以在set方法中设立关卡来保证数据的安全性。
在强调一下:
set和get方法都是实例方法,不能带static。
不带static的方法称为实例方法,实例方法的调用必须先new对象。
set和get方法写的时候有严格的规范要求:(大家要按照规矩来)
set方法长这个样子:
public void set+属性名首字母大写(1个参数){
xxx = 1个参数;
}
get方法长这个样子:
public 返回值类型 get+属性名首字母大写(无参){
return xxx;
}
2、static关键字(可以定义静态代码块)
2.1、static修饰的统一都是静态的,都是类相关的,不需要new对象。直接采用“类名.”访问。
2.2、当一个属性是类级别的属性,所有对象的这个属性的值是一样的,建议定义为静态变量。
2.3、不带static,是实例方法(对象方法,对象级别的方法)要先new对象然后再调用
为什么说方法也要new对象呢,对象不就是一个对象吗
2.4、静态变量存储在方法区
Java一共有三个变量,局部变量放在栈里,实例变量放在堆里
如果这个类型的所有对象的某个属性值都是一
样的,不建议定义为实例变量,浪费内存空间
建议定义为类级别特征,定义为静态变量
静态代码块
static{
Java语句;
Java语句;
}
在类加载时执行,并且只执行一次
一个类中可以编写多个静态代码块
静态代码块在类加载时执行,并且在main方法执行之前执行
静态代码块的作用:不是那么常用(不是每一个类当中都要写的东西)
静态代码块这种语法机制实际上是sun公司给我们Java程序员的一个特殊的时刻/时机,这个时机叫做:类加载时机
主要是类加载了,请记录一下类加载的日志信息,这些记录日志的代码就可以写到静态代码块中
静态代码块1和静态代码块2是有先后顺序的
静态代码块和静态变量是有先后顺序的
实例语句块不会在类加载时执行
实例语句块语法:{
}
主要是构造方法执行,必然在构造方法执行之前,自动执行实例语句块
1、this
1.1、this是一个关键字,是一个变量,是一个引用,保存当前对象的内存地址指向自身。
1.2、this可以使用在实例方法中,也可以使用在构造方法中。(
1.3、this出现在实例方法中其实代表的是当前对象。(谁调用这个实例方法,this就是谁)(严格意义上来说,this代表的就是"当前对象“)
1.4、this不能使用在静态方法中。(静态方法无对象)
1.5、this. 大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。
1.6、this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的
构造方法,目的是代码复用。
1.7.this存储在堆内存当中对象的内部
1.8 this.大部分情况下可以省略,默认访问”当前对象“的name
养成好习惯,以后写代码都要封装,属性私有化,对外提供setter and getter
2、总结所有的变量怎么访问,总结所有的方法怎么访问!!!!
总结一下到目前为止我们在一个类中都接触过什么了。
如果方法中直接访问了实例变量,该方法必须是实例方法
通过当前的构造方法去调用另一个本来的构造方法,可以使用以下的语法
this(实际参数列表)
通过一个构造方法1去调用构造方法2,可以做到代码复用。
但需要注意的是:构造方法1和构造方法2,都是在同一个类当中
这个语法只能放在构造器中的第一行(对this()的调用)
1.常规调用
使用局部变量:局部变量名
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)
2.当方法的局部变量和类中的成员变量重名的时候,根据“就近原则”,优先使用局部变量,
想要访问类中的成员变量可以使用this关键词
格式:this.实例变量名 (谁调用的方法,谁就是this)
3.区分重名的三种变量的访问:
(1)局部变量: 直接写成员变量名
(2)本类的成员变量: this.成员变量名
(3)父类的成员变量: super.成员变量名
4.注意:无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
5.当在某个变量前加上private修饰词时,该变量在所属类中不受影响,
但在其他类中不能够随意访问,需要设置getter/setter进行访问
6.this关键字(访问本类内容)的三种典型用法:
(1)在本类的成员方法中访问本类中的成员变量
(2)在本类的成员方法中调用本类的另一个成员方法
(3)在本类的构造方法中调用本类的另一个构造方法
在用法(3)中要注意:
①this()和super()特点相同,在构造方法中有且只有一个,还必须是构造方法中的第一个语句
②因为this()和super()相同的的特点,所以它们不能在一个构造方法中同时使用
7.super关键字(访问父类内容)的三种典型用法:
(1)在子类成员方法中访问父类的成员变量
(2)在子类成员方法中调用父类的成员方法
(3)在子类构造方法中调用父类的构造方法
8.使用staic关键字修饰的,无论是静态变量还是静态方法都推荐使用类名称调用:有static关键字,不需要创建对象,
直接就能通过类名称调用它(类名称.静态方法名(参数)/静态变量名),在本类中使用时可以不加类名称
注意事项:
①静态(方法)不能直接访问非静态(变量) --->因为在内存中是【先】有的静态内容,【后】有的非静态内容
②静态方法当中不能使用this --->因为this代表当前调用方法的对象,而调用静态方法不需要对象。
③根据类名称访问静态成员变量,这个过程跟对象没有任何关系,只和类相关。
9.在父子类的继承关系中(多态写法同样适用)
(1)如果成员变量重名,则创建子类对象时,访问成员变量有两种情况:
①直接通过子类对象访问成员变量:创建对象时等号左边是谁,就优先用谁的,没有则向上找(编译看左边,运行还看左边)
②间接通过成员方法访问成员变量:该方法属于谁,就优先用谁的,没有则向上找(就近原则)
(2)访问重名的成员方法时,new的是谁,就优先用谁的,没有则向上找。(编译看左边,运行看右边)
11.接口中静态方法的调用通过接口名称(与类中的类似),但是不能通过实现类或是实现类的对象来调用静态方法(定义在类中
的静态方法能通过对象来调用)--->因为一个实现类可能对接多个接口,静态方法会产生冲突
格式:接口.静态方法名(参数)
12.接口的默认方法可以被实现类直接调用,接口的私有方法不能被实现类调用
13.当直接父类中定义的方法和所实现的接口中定义的方法发生冲突时,优先使用直接父类中的方法。
3、继承extends
3.1、什么是继承,有什么用?
继承:在现实世界当中也是存在的,例如:父亲很有钱,儿子不用努力也很有钱。
继承的作用:
基本作用:子类继承父类,代码可以得到复用。(这个不是重要的作用,是基本作用。)
主要(重要)作用:因为有了继承关系,才有了后期的方法覆盖和多态机制。
3.2、继承的相关特性
① B类继承A类,则称A类为超类(superclass)、父类、基类,
B类则称为子类(subclass)、派生类、扩展类。
class A{}
class B extends A{}
我们平时聊天说的比较多的是:父类和子类。
superclass 父类
subclass 子类
② java 中的继承只支持单继承,不支持多继承,C++中支持多继承,
这也是 java 体现简单性的一点,换句话说,java 中不允许这样写代码:
class B extends A,C{ } 这是错误的。
c++更接近现实一些,因为儿子同时继承母亲和父亲的特征
③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,
例如:class C extends B,class B extends A,也就是说,C 直接继承 B,
其实 C 还间接继承 A。
④ java 中规定,子类继承父类,除构造方法不能继承之外,剩下都可以继承。
但是私有的属性无法在子类中直接访问。(父类中private修饰的不能在子类中
直接访问。可以通过间接的手段来访问。)
⑤ java 中的类没有显示的继承任何类,则默认继承 Object类,Object类是
java 语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有
Object类型中所有的特征。
⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它
们之间的耦合度非常高,Account 类发生改变之后会马上影响到 CreditAccount 类
1、继承extends
1.1、测试:子类继承父类之后,能使用子类对象调用父类方法吗?
可以,因为子类继承了父类之后,这个方法就属于子类了。
当然可以使用子类对象来调用。
1.2、在实际开发中,满足什么条件的时候,我可以使用继承呢?
凡是采用“is a”能描述的,都可以继承。
例如:
Cat is a Animal:猫是一个动物
Dog is a Animal:狗是一个动物
CreditAccount is a Account:信用卡账户是一个银行账户
....
假设以后的开发中有一个A类,有一个B类,A类和B类确实也有重复的代码,
那么他们两个之间就可以继承吗?不一定,还是要看一看它们之间是否能够
使用is a来描述。
class Customer{
String name; // 名字
// setter and getter
}
class Product{
String name; // 名字
// setter and getter
}
class Product extends Customer{
}
以上的继承就属于很失败的。因为:Product is a Customer,是有违伦理的。
1.3、任何一个类,没有显示继承任何类,默认继承Object,那么Object类当中有
哪些方法呢?老祖宗为我们提供了哪些方法?
以后慢慢的大家一定要适应看JDK的源代码(多看看牛人写的程序自己才会变成牛人。)
先模仿后超越。
java为什么比较好学呢?
是因为Java内置了一套庞大的类库,程序员不需要从0开始写代码,程序员可以
基于这套庞大的类库进行“二次”开发。(开发速度较快,因为JDK内置的这套库
实现了很多基础的功能。)
例如:String是SUN编写的字符串类、System是SUN编写的系统类。
这些类都可以拿来直接使用。
JDK源代码在什么位置?
C:\Program Files\Java\jdk-13.0.2\lib\src.zip
你现在能看懂以下代码了吗?
System.out.println("Hello World!");
System.out 中,out后面没有小括号,说明out是变量名。
另外System是一个类名,直接使用类名System.out,说明out是一个静态变量。
System.out 返回一个对象,然后采用“对象.”的方式访问println()方法。
我们研究了一下Object类当中有很多方法,大部分看不懂,其中有一个叫做toString()
的,我们进行了测试,发现:
System.out.println(引用);
当直接输出一个“引用”的时候,println()方法会先自动调用“引用.toString()”,然后
输出toString()方法的执行结果。
2、方法覆盖
2.1、什么时候考虑使用方法覆盖?
父类中的方法无法满足子类的业务需求,子类有必要对继承过来的方法进行覆盖。
2.2、什么条件满足的时候构成方法覆盖?
第一:有继承关系的两个类
第二:具有相同方法名、返回值类型、形式参数列表
第三:访问权限不能更低。
第四:抛出异常不能更多。
//直接复制父类的方法完了修改就行了
2.3、关于Object类中toString()方法的覆盖?
toString()方法存在的作用就是:将java对象转换成字符串形式。
大多数的java类toString()方法都是需要覆盖的。
因为Object类中提供的
toString()方法输出的是一个java对象的内存地址。
至于toString()方法具体怎么进行覆盖?
格式可以自己定义,或者听需求的。(听项目要求的。)
//噢所以你就经常看到在类的末尾有个重新tostring方法哈哈
在打印输出的时候会用到
2.4、方法重载和方法覆盖有什么区别?
方法重载发生在同一个类当中。
方法覆盖是发生在具有继承关系的父子类之间。
方法重载是一个类中,方法名相同,参数列表不同。
方法覆盖是具有继承关系的父子类,并且重写之后的方法必须和之前的方法一致:
方法名一致、参数列表一致、返回值类型一致。
继承和实现都存在的话,代码应该怎么写?
Entends 关键字在前
Implements 关键字在后
能插拔的就是接口,内存条插到主板上,他们之间有接口,内存条可以更换
接口通常提取的是行为动作
3、多态的基础语法
3.1、向上转型和向下转型的概念。
向上转型:子--->父 (upcasting)
又被称为自动类型转换:Animal a = new Cat();
向下转型:父--->子 (downcasting)
又被称为强制类型转换:Cat c = (Cat)a; 需要添加强制类型转换符。
什么时候需要向下转型?
需要调用或者执行子类对象中特有的方法。
必须进行向下转型,才可以调用。
向下转型有风险吗?
容易出现ClassCastException(类型转换异常)
怎么避免这个风险?
instanceof运算符,可以在程序运行阶段动态的判断某个引用指向的对象
是否为某一种类型。
养成好习惯,向下转型之前一定要使用instanceof运算符进行判断。
不管是向上转型还是向下转型,首先他们之间必须有继承关系,这样编译器就不会报错。
3.2、什么是多态。
多种形态,多种状态,编译和运行有两个不同的状态。
编译期叫做静态绑定。
运行期叫做动态绑定。
Animal a = new Cat();
// 编译的时候编译器发现a的类型是Animal,所以编译器会去Animal类中找move()方法
// 找到了,绑定,编译通过。但是运行的时候和底层堆内存当中的实际对象有关
// 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。
a.move();
多态的典型代码:父类型的引用指向子类型的对象。(java中允许这样写代码!!!)
3.3、什么时候必须进行向下转型?
调用子类对象上特有的方法时。
1、多态在开发中有什么作用?
非常重要:五颗星。。。。(多态你会天天用,到处用!!!!)
多态在开发中的作用是:
降低程序的耦合度,提高程序的扩展力。
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
}
以上的代码中表示:Master和Dog以及Cat的关系很紧密(耦合度高)。导致扩展力很差。
public class Master{
public void feed(Pet pet){
pet.eat();
}
}
以上的代表中表示:Master和Dog以及Cat的关系就脱离了,Master关注的是Pet类。
//O就是说又把下面给抽象一下
这样Master和Dog以及Cat的耦合度就降低了,提高了软件的扩展性。
面向对象的三大特征:
封装、继承、多态
真的是一环扣一环。
有了封装,有了这种整体的概念之后。
对象和对象之间产生了继承。
有了继承之后,才有了方法的覆盖和多态。
这里提到了一个软件开发原则:
七大原则最基本的原则:OCP(对扩展开放,对修改关闭)
目的是:降低程序耦合度,提高程序扩展力。
面向抽象编程,不建议面向具体编程。
多态指的是:
父类型引用指向子类型对象
包括编译阶段和运行阶段
编译阶段:绑定父类的方法
运行阶段:动态绑定子类型对象的方法
2、解释之前遗留的问题
私有方法无法覆盖。
方法覆盖只是针对于“实例方法”,“静态方法覆盖”没有意义。(这是因为方法覆盖通常和多态联合起来)
总结两句话:
私有不能覆盖。
静态不谈覆盖。
在方法覆盖中,关于方法的返回值类型。
什么条件满足之后,会构成方法的覆盖呢?
1、发生具有继承关系的两个类之间。
2、父类中的方法和子类重写之后的方法:
具有相同的方法名、相同的形式参数列表、相同的返回值类型。
Instanceof(运行阶段动态判断)
Instanceof可以在运行阶段动态判断引用指向的对象的类型
Instanceof的语法:引用 instanceof 类型
Instanceof运算符的运算结果只能是:true/false
c是一个引用,c变量保存了内存地址指向了堆中的对象
假设(c instanceof Cat)为true表示:
c引用指向的堆内存中的Java对象是一个Cat
假设(c instanceof Cat)为false表示
c引用指向的堆内存中的Java对象不是一个Cat
学习了多态机制之后:
“相同的返回值类型”可以修改一下吗?
对于返回值类型是基本数据类型来说,必须一致。
对于返回值类型是引用数据类型来说,重写之后返回值类型可以变的更小(但意义不大,实际开发中没人这样写。)。
3、super关键字
super能出现在实例方法和构造方法中。
super的语法是:“super.”、“super()”
super不能使用在静态方法中。
super. 大部分情况下是可以省略的。
super.什么时候不能省略呢?
父类和子类中有同名属性,或者说有同样的方法,
想在子类中访问父类的,super. 不能省略。
super() 只能出现在构造方法第一行,通过当前的构造方法去调用“父类”中
的构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
super的使用:
super.属性名 【访问父类的属性】
super.方法名(实参) 【访问父类的方法】
super(实参) 【调用父类的构造方法】
工具的使用
1、使用集成开发工具eclipse
1.1、java的集成开发工具很多,包括:eclipse、Intellij IDEA、netbeans.....
eclipse:
IBM开发的。eclipse翻译为:日食。寓意吞并SUN公司(SUN是太阳。)
最终没有成功,SUN公司在2009年的时候被oracle甲骨文公司收购。
eclipse在以前的开发中使用非常多,但是由于IDEA工具的出现,让eclipse
的用户大大减少,目前eclipse占市场份额30%。IDEA占市场份额60%,
剩下10%是其他的开发工具。
Intellij IDEA:
提示功能比eclipse强大。更好用。
1.2、什么是集成开发工具?
集成开发工具又称为集成开发环境,把开发中需要的东西全部集成在一起,
包括编写代码时大量的代码提示,及时的编译,程序员编写代码之后,集成
开发工具自动编译,有语法错误的时候集成开发工具会马上标红色。运行的
时候也不需要命令,直接使用鼠标操作即可。总之集成开发工具就是为了提高
开发速度。另外集成开发工具会为程序员生成很多代码,有很多代码不需要写。
及时编译
语法错误及时提醒
代码提示功能
代码自动生成功能
方便的运行
.....
1.3、eclipse的安装:
我的eclipse是一个解压版的。直接解压就能用。
使用当前的这个eclipse的时候,需要计算机上已经安装了JDK,并且bin目录已经配置到path当中。
解压之后:eclipse.exe 是启动eclipse开发工具的。
1.4、eclipse工具的使用
* 第一次打开eclipse的时候,会让你选择工作区,工作区就是java代码存放的位置。
默认位置:C:\Users\Administrator\eclipse-workspace
你可以修改成其他位置,没问题。
我这里改一下:D:\course\JavaProjects\02-JavaSE\eclipsecode
选择工作区的窗口左下角有一个复选框:
这个复选框选中表示下一次再打开eclipse的时候默认进入这个工作区。不再询问。
我这里就不选中了。(让他每一次询问。)
* 打开之后,会呈现一个:welcome,(直接关闭即可)
* 关闭welcome之后,默认的布局方式:javaee方式,我们目前是javase,怎么切换
布局方式到javase呢?
点击右上角倒数第二个小图标,打开一个窗口,选择java。
* 我把这个javase布局中所有没有用的窗口全部关闭:
只留下:package explorer
一不小心把:package explorer关闭了怎么办?
可以再打开:window菜单 --> show view--> package explorer
* 一个布局打乱了,能重置吗?手机恢复出厂设置....
window菜单 --> Perspective --> reset.....
* 在eclipse的workspace工作区当中以project(工程)为单位。所以要编写
java代码,必须先新建工程。在工程上编写代码:
怎么创建工程?
在package explorer窗口的空白位置右键 --> new --> java project
新建工程(java project)的时候:
需要指定:
工程的名字:我这里起名javase
选择JRE,当前eclipse默认选择的是JRE11.(我电脑上没有,这个应该是eclipse自带的。)
JRE(java的运行环境。)
目前为止:大家只要指定工程名字就行,别的不用修改。
直接finish,就新建工程完成了。
注意:最后一步finish的时候,会提醒你是否创建java文件,可以创建,也可以不创建。
* 怎么删除工程?
工程上右键--> delete --> 弹出窗口之后,选中复选框表示彻底删除(硬盘上也删了。)
* 编写第一个HelloWorld程序
在src上点击右键--> new --> Class :
填写上类名:HelloWorld
在下面有一个选中创建main方法。选中表示自动创建main方法。
finish完成。
* 出现了兼容问题:
eclipse(2018-12的版本),不支持JDK11以及更高版本。
我这里先这样处理一下:下载一个低版本的JDK,选择JDK8.
* 安装了JDK8之后,再重新在eclipse中创建java project。
怎么在eclipse当中指定使用某个JRE/JDK呢?
在新建工程的窗口上有一个:Configure jres....
弹出的窗口中:add
add之后选择:standard vm
然后next
在弹出的窗口中点击:Directory
目录选中这个即可:C:\Program Files\Java\jdk1.8.0_101
别的位置不用动。
finish.
完成的过程中:你要记得把jdk8的对勾打上。
apply and close...
* 一会我给大家分享一个高版本的eclipse。能够让eclipse支持高版本的JDK。
* eclipse设置字体:
window菜单--->最后一个-->窗口上输入font-->选中color and font
--> basic --> 最后一个双击。
* eclipse是实时编译的,有语法错误会报红。
* 注意:eclipse有的时候是必须保存之后才会编译的。要时刻ctrl + s
* main方法怎么生成?
main,然后alt + /
* System.out.println()怎么生成?
sysout ,然后atl + /
* 怎么运行:
在有main方法的程序上右键 --> run as --> java application..
* 怎么生成构造方法
在空白处右键 --> source --> generate constructor
* 怎么生成set和get方法
在空白处右键 --> source --> generate setter and getter
* eclipse默认情况下,当你“点”的时候都会有提示。
1、final关键字
final是Java语言中的一个关键字,表示最终的,不可变的,可以修饰变量
1.1、final修饰的类无法继承。
1.2、final修饰的方法无法覆盖。
1.3、final修饰的变量只能赋一次值。
1.4、final修饰的引用一旦指向某个对象,则不能再重新指向其它对象,但该引用
指向的对象内部的数据是可以修改的。
1.5、final修饰的实例变量必须手动初始化,不能采用系统默认值。
1.6、final修饰的实例变量一般和static联合使用,称为常量。
常量名建议全部大写,每个单词之间采用下划线衔接
public static final double PI = 3.1415926;
实际上常量和静态变量一样,区别在于:常量的值不能变
常量和静态变量,都是储存在方法区,并且都是在类加载时初始化
常量一般都是公开的,不用封装,因为你本来就改不了
实例变量如果没有手动赋值的话,系统会赋默认值
final修饰的实例变量,系统不管赋默认值,要求程序员必须手动赋值
实例变量在构造方法执行的过程中赋值,new的时候赋值
2、抽象类和接口以及抽象类和接口的区别。
抽象类-类-对象
抽象类无法实例化,无法创建对象
抽象类是类与类之间有共同特征,将这些具有共同特征的类再进一步抽象形成了抽象类
由于类本身是不存在的,所以抽象类无法创建对象,所以抽象类是用来被子类继承的
抽象类还可以再进一步抽象
抽象类也属于引用数据类型
【修饰符列表】 abstract class 类名{
类体;
}
final和abstract不能联合使用,这两个关键字是对立的
抽象类的子类可以是抽象类
抽象方法表示没有实现的方法,没有方法体的方法
public abstract void dosome;
特点:没有方法体,以分号结尾,前面修饰符列表中有abstract关键字
抽象类中不一定有抽象方法
抽象方法必须出现在抽象类中
2.1、抽象类
第一:抽象类怎么定义?在class前添加abstract关键字就行了。
第二:抽象类是无法实例化的,无法创建对象的,所以抽象类是用来被子类继承的。
第三:final和abstract不能联合使用,这两个关键字是对立的。
第四:抽象类的子类可以是抽象类。也可以是非抽象类。
第五:抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是供子类使用的。
第六:抽象类中不一定有抽象方法,抽象方法必须出现在抽象类中。
第七:抽象方法怎么定义?
public abstract void doSome();
第八(*****五颗星):一个非抽象的类,继承抽象类,必须将抽象类中的抽象方法进行覆盖/重写/实现。
把abstract删了,把;改成{
这是Java语法上强行规定的,不然编译器就报错了
如果Bird是抽象类的话,那么这个Animal中继承过来的抽象类也可以不用重写
abstract class Bird extends Animal{
到目前为止,只是学习了抽象类的基础语法,一个类到底声明为抽象还是非抽象,
这个以后慢慢来吧。写代码多的时候,自然就理解了。
面向抽象编程,不要面向具体编程,降低程序的耦合度,提高程序的扩展力
面试题(判断题):java语言中凡是没有方法体的方法都是抽象方法。
不对,错误的。
Object类中就有很多方法都没有方法体,都是以“;”结尾的,但他们
都不是抽象方法,例如:
public native int hashCode();
这个方法底层调用了C++写的动态链接库程序。
前面修饰符列表中没有:abstract。有一个native。表示调用JVM本地程序。
2.2、接口的基础语法。
1、接口是一种“引用数据类型”。
2、接口是完全抽象的。
3、接口怎么定义:[修饰符列表] interface 接口名{}
4、接口支持多继承。
5、接口中只有常量+抽象方法。
6、接口中所有的元素都是public修饰的
7、接口中抽象方法的public abstract可以省略。
8、接口中常量的public static final可以省略。
9、接口中方法不能有方法体。
2.3、接口在开发中的作用。
注意:接口在开发中的作用,类似于多态在开发中的作用。
多态:面向抽象编程,不要面向具体编程。降低程序的耦合度。提高程序的扩展力。
/*
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
//假设又要养其它的宠物,那么这个时候需要再加1个方法。(需要修改代码了)
//这样扩展力太差了,违背了OCP原则(对扩展开放,对修改关闭。)
}
*/
public class Master{
public void feed(Animal a){
// 面向Animal父类编程,父类是比子类更抽象的。
//所以我们叫做面向抽象编程,不要面向具体编程。
//这样程序的扩展力就强。
}这样可以把狗也传过来,猫也传过来
}
能插拔的就是接口
接口在开发中的作用?
接口是不是完全抽象的?是。
而我们以后正好要求:面向抽象编程。
面向抽象编程这句话以后可以修改为:面向接口编程。//因为接口就是纯抽象的
有了接口就有了可插拔。可插拔表示扩展力很强。不是焊接死的。
主板和内存条之间有插槽,这个插槽就是接口,内存条坏了,可以重新
买一个换下来。这叫做高扩展性。(低耦合度。)
接口在现实世界中是不是到处都是呢?
螺栓和螺母之间有接口
灯泡和灯口之间有接口
笔记本电脑和键盘之间有接口(usb接口,usb接口是不是某个计算机协会制定的协议/规范。)
接口有什么用?扩展性好。可插拔。
接口是一个抽象的概念。
分析:
中午去饭馆吃饭,这个过程中有接口吗?
接口是抽象的。
菜单是一个接口。(菜单上有一个抽象的照片:西红柿炒鸡蛋)
谁面向接口调用。(顾客面向菜单点菜,调用接口。)
谁负责实现这个接口。(后台的厨师负责把西红柿鸡蛋做好!是接口的实现者。)
这个接口有什么用呢?
这个饭馆的“菜单”,让“顾客”和“后厨”解耦合了。
顾客不用找后厨,后厨不用找顾客。他们之间完全依靠这个抽象的菜单沟通。
public interface FoodMeau{//菜单接口
void shizichaojidan();
void yuxiangrousi();
}
public class ChinaCooker{
总结一句话:三个字“解耦合”
面向接口编程,可以降低程序的耦合度,提高程序的扩展力。符合OCP开发原则。
接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度。)
接口可以解耦合,解开的是谁和谁的耦合!!!
任何一个接口都有调用者和实现者。
接口可以将调用者和实现者解耦合。
调用者面向接口调用。
实现者面向接口编写实现。
以后进行大项目的开发,一般都是将项目分离成一个模块一个模块的,
模块和模块之间采用接口衔接。降低耦合度。
1.4、类型和类型之间的关系:
is a(继承)、has a(关联)、like a(实现)
is a:
Cat is a Animal(猫是一个动物)
凡是能够满足is a的表示“继承关系”
A extends B
has a:
I have a Pen(我有一支笔)
凡是能够满足has a关系的表示“关联关系”
关联关系通常以“属性”的形式存在。
A{
B b;
}
like a:
Cooker like a FoodMenu(厨师像一个菜单一样)
凡是能够满足like a关系的表示“实现关系”
实现关系通常是:类实现接口。
A implements B
1.5、抽象类和接口有什么区别?
在这里我们只说一下抽象类和接口在语法上的区别。
至于以后抽象类和接口应该怎么进行选择,通过后面的项目去体会/学习。
抽象类是半抽象的。
接口是完全抽象的。
抽象类中有构造方法。
接口中没有构造方法。
接口和接口之间支持多继承。
类和类之间只能单继承。
一个类可以同时实现多个接口。
一个抽象类只能继承一个类(单继承)。
接口中只允许出现常量和抽象方法。
这里先透露一个信息:
以后接口使用的比抽象类多。一般抽象类使用的还是少。
接口一般都是对“行为”的抽象。
2、package和import机制
package是Java中的包机制,作用是为了方便程序的管理,不同功能的类分别存放在不停的包下(按照功能划分的,不同的软件包具有不同的功能
2.1、package
第一:package出现在java源文件第一行。(package是一个关键字,后面加包名)一般都采用公司域名倒叙的方式,具有全球唯一性
第二:带有包名怎么编译?javac -d . xxx.java
第三:怎么运行?java 完整类名
包名命名规范:
公司域名倒叙+项目名+模块名+功能名
对于带有package 的Java程序怎么编译?怎么运行?
采用之前的编译和运行不行了,因为类名不再是Hello,而是包名加hello
dos命令窗口Java后面跟的还是一个类的名字
编译:
javac -d .HelloWorld.java
javac 负责编译的命令
-d 带包编译
. 代表变异之后生成的东西放到当前目录下(点代表当前目录)
HelloWorld.java 被编译的Java文件名
补充:以后说类名的时候,如果带着包名描述,表示完整类名。
如果没有带包,描述的话,表示简类名。
java.util.Scanner 完整类名。
Scanner 简类名
2.2、import
将需要的类引入
import什么时候不需要?
java.lang不需要。
A类使用B类
同包下不需要。
其它一律都需要。
怎么用?
import 完整类名;
import 包名.*;
import java.util.Scanner; // 完整类名。
// 同学的疑问:这样是不是效率比较低。
// 这个效率不低,因为编译器在编译的时候,会自动把*变成具体的类名。
import java.util.*;
// 想省懒劲你不能太省了。
import java.*; 这是不允许的,因为在java语言中规定,这里的*只代表某些类的名字。
写在package和类的声明之间