文章目录
一、面向对象的编程基础
1.1 程序(program)
1.1.1 理解程序
A program is a sequence of instructions that specifies how to perform a computation. 程序是一系列的指令,来告诉计算机如何进行运算
程序是为实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。它由序列组成,告诉计算机如何完成一个具体的任务,是软件开发人员根据用户需求开发的、用程序设计语言描述的适合计算机执行的指令(语句)序列。
1.1.2 程序!=自然语言
程序不是自然语言,自然语言存在歧义,而程序中不能存在歧义。由于现在的计算机还不能理解人类的自然语言,所以还不能用自然语言编写计算机程序。
1.1.3 人与计算机的对话
人与计算机的对话方式可以分为三种:
- 人学习计算机的语言:机器语言
- 计算机学习人的语言:自然语言
- 学习第三方语言:高级程序设计语言
通常意义上的程序是由高级语言编写的为进行某活动或过程所规定的途径。
1.1.4 程序分类
一般分为系统程序和应用程序两大类:
- 系统软件:
用于实现计算机系统的管理、调度、监视和服务等功能,其目的是方便用户,提高计算机使用效率,扩充系统的功能。 - 应用软件:
针对用户的需要,为解决各种实际问题而编制的计算机应用程序。
1.1.5 程序内容
- 对数据的描述:
在程序中要指定数据的类型和数据的组织形式,即数据结构(data structure)。 - 对操作的描述:
即操作步骤,也就是算法(algorithm)或者行为。
实际上,一个程序除子以上两个主要的要素外,还应当来用程序设计方法进行设计,并且用一种计算机语言来表示。
1.1.6 程序编写原则
- 低耦合,可维护
- 可扩展,可伸缩
- 可复用
- 安全性
1.1.7 程序执行过程
编写、编译、上载、运行
1.2 程序设计语言
1.2.1 程序设计语言发展阶段
1.2.1.1高级语言
C、C++、Java、C#、Basic、Pascal…
1.2.1.2 脚本语言
JavaScript、Python、Ruby、PHP、Asp.Net、Perl、.…
1.2.1.3 语言区别和联系
-
C/C++、Java、.Net(C)以及其它语言
-
C/C++:程序性能高、支持底层应用·主要用于系统级软件、资源受限环境软件
- 典型应用:通用软件、主机游戏、与硬件相关底层应用等
-
Java:跨平台,更好的互操作性,主要用于太规模企业级应用软件,随着硬件的发展,其跨平台的特性使得其在嵌大式领域(如手机软件应用也日益广泛
- 典型应用:电信、银行等行业管理信息系统、Android应用、人工智能、大数据分析
-
.Net:开发、部署效率高,成本低。主要用于中小规模企业级应用软件
- 典型应用:部门级信息系统、桌面应用软件
-
ios平台上的语言:Objective-C、Swift
-
其它脚本语言也有其应用环境,如PHP、Python、Js等结论
-
C结构体,C++结构体 和 C++类的区别及联系
-
区别:
C的结构体不能添加成员函数,不能继承和派生;
C++的结构体和类,都能添加成员函数,能够继承和派生,具有多态性;
C++的结构体和类的区别仅仅是默认情况下外部对类成员的访问权限的不同,结构体默认是pubilc,C++中类默认是private; -
联系:
结构体也可以被认为是一种特殊的类,它不存在在何函数,构造和析构函数也没有,而且是一个公共的类
-
-
C语言、C++和Java对比
C是面向过程的语言。C++和Java都是面向对象的。在C中没有类或者对象的概念,C中对包含复杂属性的主体采用struct封装;
Java和C++都是面向对象语言,C++兼容C,而且对C中的结构体做了扩展,但是Java中彻底抛弃了struct的概念;
Java和C++程序的共同点都需要抽象出类,都具有封装、继承和多态的三大特征;
C和C++主要用在在中间件和底层,Java主要用在应用层,Java更注重于面向对象的思想(为了完全面向对象,可以适当的牺牲效率),而C++更注重于效率(为了更好的效率,可以适当的牺牲面向对象),所以C++相比Java在语法上更复杂一些。
1.2.2 面向机器语言—low level language
1.2.2.1 机器语言
使用高低电压来表示0和1两种状态,这样计算机就可以使用二进制数来存储和处理信息了
机器语言直接由计算机的指令组成,可以被计算机直接执行
1.2.2.2 汇编语言
使用一些简单的容易记忆的符号来代替二进制指令,比机器语言更容易读懂,更容易编写
汇编语言抽象层次很低,程序员需要考虑大量的机器细节。
机器语言与汇编语言都是面向机器的语言,需要针对不同的硬件环境编写不同的代码,因此这两种语言被称为低级语言
1.2.3 面向过程语言—high level language
随着计算机硬件功能的提高,在20世纪60年代出现了面向过程的程序设计语言,如C语言和Fortran语言
面向过程的语言比低级语言更加接近人类的自然语言,因此被称为高级语言
使用面向过程的程序设计语言,不用再考虑机器指令的细节,只需要按照语言的语法规则去编写代码
面向过程的程序由若干个过程或函数模块组成,每个模块的目标就是完成某一个任务
因为计算机只能识别0、1代码,因此使用高级语言编写的程序需要通过某种机制将其转变成机器码,计算机才能识别
将高级语言编写的源文件转化成机器码通常有两种方式:编译方式和解释方式
(1)编译方式(Compilation)
针对当前的处理器,将源文件全部翻译成机器指令,称为目标程序,再将目标程序交给计算机执行
(2)解释方式(Interpretation)
此种方式并不产生整个的目标程序,而是根据当前的处理器,边解释边执行,解释一句,执行一句
无论哪种高级语言,都必须提供相应的编译器或者解释器
Java语言编写的程序使用的是编译与解释相结合的方式来运行的
JVW中提供的JIT(即时编译方式)将字节码直接转化成高性能的本地机器码,即JIT使得Java程序既能跨平台又能高速运行
1.2.4 面向对象编程—high level language
随着计算机硬件设备功能的进一步提高,使得面向对象的编程成为可能。
面向对象的基本思想是,从现实世界中客观存在的事物出发来构造软件系统,并在系统的构造中尽可能运用人类的自然思维方式。
面向对象更加符合人的思维模式,编写的程序更加健壮和强大,也能够解决更加复杂的问题,并且面向对象编程鼓励创造性的程序设计。
1.3 理解面向对象
1.3.1 面向对象(Object Oriented)
面向对象是一种软件开发方法
-面向对象的分析与设计(00A&00D)是用客观世界中描述事物的方法,来描述程序中要解决的问题
万物皆对象(万事万物,都是对象)
程序便是成堆的对象,彼此通过消息传递,请求其他对象进行工作
第一个面向对象的语言:Simula-67
第一个成功的面向对象的语言:Smalltalk
目前主流面向对象的语言:C++,JAVA,C#
1.3.3 案例:敬老院的奶奶们
1.3.4 案例:小汽车
现实生活中的对象(对现实世界建立对象模型)
计算机中的对象原型
class Car {
String color;
String brand;
String model;
int door_number;
int speed;
void brake() { … }
void speedUp() {…};
void slowDown() { … }
}
类是对象共性的的描述,包括属性和行为
如果将对象比作汽车,那么类就是汽车的设计图纸。所以面向对象程序设计的重点是类的设计,而不是对象的设计。
1.3.5 面向对象的设计思路
面向对象的基本思想是:从现实世界中客观存在的事物出发来构造软件系统,并在系统的构造中尽可能运用人类的自然思维方式。
面向对象更加强调运用人类在日常生活的逻辑思维中经常采用的思想方法与原则,如抽象、芬类,森承、聚谷、多态等。
人在思考的时候,首先眼睛里看到的是一个一个的对象。
旨在在计算机程序中模拟现实世界中的概念,在 OOP 中,现实世界的所有事物全都被视为对象,能够在计算机程序中用类似的实体模拟现实世界中的实体,设计和实现软件系统的方法。
面向对象其实是现实世界模型的自然延伸。现实世界中任何实体都可以看作是对象,都归结为某一类事物,都是某一类事件的实例。万物对象程序由类组成:对相同类型的对象进行分类、抽象后,得出共同的特性而形成了类。例如Student Teacher和Person类。
将数据及对数据的操作行为放在一起,作为一个相互依存、不可分割的整体——对象。对象是细粒度的。
对象之间通过消息(方法)相互作用,完成系统功能。
1.3.6 案例:饲养动物
设计应用程序,模拟现实世界中,动物园 里饲养员喂养动物的场景
Animal类
Animal子类Dog类
Animal子类Cat类
食物Food类
Food类子类Bone
Food类子类Fish
饲养员Feeder类
测试类
1.3.7 案例:把大象装进冰箱
步骤:打开冰箱;将大象装进去;关闭冰箱
1、先按照名词提炼问题领域中的对象
2、对对象进行描述,明确对象中应该具备的属性和功能,抽象出类,设计类,编写类
3、通过new的方式可以创建该事物的具体对象
4、通过该对象调用它以后的功能。
package 把大象装进冰箱;
/**
* 大象类
*
* @author gwr
* @date 2019-06-04 21:12
*/
public class Elephant {
private double weight;
private double height;
private char sex;
public Elephant() {};
public Elephant(double weight, double height, char sex) {
this.weight = weight;
this.height = height;
this.sex = sex;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Elephant{" +
"weight=" + weight +
", height=" + height +
", sex=" + sex +
'}';
}
}
package 把大象装进冰箱;
/**
* 冰箱类
*
* @author gwr
* @date 2019-06-04 21:15
*/
public class Refrigerator {
private double brand;
private String model;
private String color;
public Refrigerator(){}
public Refrigerator(double brand, String model, String color) {
this.brand = brand;
this.model = model;
this.color = color;
}
void open() {
System.out.println("打开冰箱");
}
void in(Elephant e) {
System.out.println("储存大象");
}
void close() {
System.out.println("关闭冰箱");
}
}
package 把大象装进冰箱;
/**
* 测试冰箱成大象
*
* @author gwr
* @date 2019-06-04 21:41
*/
public class EleRefTest {
public static void main(String[] args) {
Elephant e = new Elephant();
Refrigerator r = new Refrigerator();
r.open();
r.in(e);
r.close();
}
}
程序输出
打开冰箱
储存大象
关闭冰箱
1.4 面向对象与面向过程设计思路的对比
面向对象和面向过程的思想有着本质上的区别
- 面向过程的思维:
确定第一步先做什么,第二步做什么,第三步做什么。。。自顶向下的功能分解法 - 面向对象的思维:
- 第一步:明确问题域,分析这个问题里面有哪些类和对象
- 第二步:分析这些类和对象应该具有哪些属性和方法。
- 第三步:分析类和类之间具体有什么关系。
“面向过程”是一种以过程为中心的编程思想,强调的是功能行为。
“面向过程”只是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程在这一系列工作的执行中,强调的是工作的执行。“面向过程”不支持丰富的“面向对象”特性(比如继承、多态)
面向对象更加重视软件的可维护,可扩展,可复用等特性。
面向对象编程的三个特性
- 封装
面向对象编程的核心思想就是将数据和数据的操作封装在一起,通过抽象,即从具体的实例中抽取共同的性质形成一般的概念,比如类的概念 - 继承
- 多态
- 一种是操作名称的多态,即方法的重载。
- 另一种是指同一个操作被不同对象调用时可能产生不同的行为。
面向对象的核心思想和概念包括:抽象、封装、 接口、多态和继承,灵活运用这些理论武器,就 会使得软件系统象用积木搭起来的系统一样,可 以方便地进行组装、拆卸和重用。
运用面向对象思维来构建可维护、可重用和可扩 展的软件系统
面向对象思维方式是一种更符合人们思考习惯的思想
面向过程思维方式中更多的体现的是执行者(自己做事情),面向对象中更多的体现是指挥者(指挥对象做事情)。
面向对象思维方式将复杂的问题简单化。
1.4.1 案例:制作年夜饭
面向过程:
做什么?怎么做?准备材料,按步骤由自己做
面向对象:
采购员(姑姑)买肉
采购员(妈妈)买菜
采购员(你)买鸡蛋和作料
厨师(爸爸)烹饪
厨师(婶婶)烤甜品
package 年夜饭;
/**
* Person类
*
* @author gwr
* @date 2019-06-04 19:02
*/
public abstract class Person {
private String name;
private char sex;
public Person(String name, char sex) {
super();
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
package 年夜饭;
/**
* 采购员类
*
* @author gwr
* @date 2019-06-04 22:08
*/
public class Buyer extends Person {
private String toBuy;
public Buyer(String name, char sex, String toBuy) {
super(name, sex);
this.toBuy = toBuy;
}
public String getToBuy() {
return toBuy;
}
public void setToBuy(String toBuy) {
this.toBuy = toBuy;
}
@Override
public String toString() {
return super.toString() +
"Buyer{" +
"toBuy='" + toBuy + '\'' +
'}';
}
}
package 年夜饭;
/**
* 厨师类
*
* @author gwr
* @date 2019-06-04 22:13
*/
public class Cook extends Person {
private String toCook;
public Cook(String name, char sex, String toCook) {
super(name, sex);
this.toCook = toCook;
}
public String getToCook() {
return toCook;
}
public void setToCook(String toCook) {
this.toCook = toCook;
}
@Override
public String toString() {
return super.toString() +
"Cook{" +
"toCook='" + toCook + '\'' +
'}';
}
}
package 年夜饭;
/**
* 协同制作年夜饭
*
* @author gwr
* @date 2019-06-04 22:16
*/
public class WorkTogether {
public static void main(String[] args) {
Buyer 姑姑 = new Buyer("姑姑", 'F', "买肉");
Buyer 妈妈 = new Buyer("妈妈", 'F', "买菜");
Buyer 我 = new Buyer("我", 'F', "买鸡蛋和作料");
Cook 爸爸 = new Cook("爸爸", 'M', "烹饪");
Cook 婶婶 = new Cook("婶婶", 'F', "烤甜品");
System.out.println(姑姑);
System.out.println(妈妈);
System.out.println(我);
System.out.println(爸爸);
System.out.println(婶婶);
}
}
程序输出
Person{name=‘姑姑’, sex=F}Buyer{toBuy=‘买肉’}
Person{name=‘妈妈’, sex=F}Buyer{toBuy=‘买菜’}
Person{name=‘我’, sex=F}Buyer{toBuy=‘买鸡蛋和作料’}
Person{name=‘爸爸’, sex=M}Cook{toCook=‘烹饪’}
Person{name=‘婶婶’, sex=F}Cook{toCook=‘烤甜品’}
1.4.2 案例:定义窗体
面向过程(C)
在一个结构体中定义窗口的大小,位置,颜色,背景等属性·对窗口操作的函数与窗口本身的定义没有任何尖系,如HideWindow·MoveWindow,MinimizeWindow.这些函数都需要接受一个代表要被操作的窗口参数,是一种谓语与宾语的尖系。
面向对象(Java andC++)(Window.java)
定义窗口时,除了要指定在面向过程中规定的那些属性,如大小,位置,颜色,背景等外,还要指定该窗口可能具有的动作,如隐藏,移动,最小化等。这些函数被调用时,都是以某个窗口要隐藏,某个窗口要移动的语法格式来使用的·这是一种主语与谓语的关系。
Java中所有的数据和函数都隶属于类(记得别忘了写main函数)
/**
* 窗口类
*
* @author gwr
* @date 2019-06-03 21:58
*/
public class Window {
/**
* 定义窗口属性:
*
* 大小,位置,颜色,背景
*/
private int size;
private int x;
private int y;
private String color;
private String background;
/**
* 定义窗口方法
*/
public void windowMove() {
System.out.println("moving");
}
public void windowsHide() {
System.out.println("hideing");
}
public static void main(String[] args) {
//TODO Auto-generated method stub
Window androidWindow = new Window();
Window macWindow = new Window();
androidWindow.windowMove();
androidWindow.windowsHide();
macWindow.windowMove();
macWindow.windowsHide();
}
}
程序输出:
1.5 认识Java
1.5.1 Java语言的发展
Java是一种咖啡的名称,中文译名为爪哇,为这种新的语言起名为Java,其寓意是为世人端上一杯热咖啡
Java的发展史——JDK版本发展
1996年,Java JDK1.0正式发表;
1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入JAVA技术;
1996年9月,约8.3万个网页应用了JAVA技术来制作;
1999年6月,SUN公司发布Java的三个版本:标准版、企业版和微型版
2009年04月20日,甲骨文74亿美元收购Sun。取得java的版权。
目前最高版本JDK 1.8
Java2的三个体系
J2SE(Java 2 Software Development Kit, Standard Edition)
J2EE(Java 2 Software Development Kit, Enterprise Edition)
J2ME(Java 2 Software Development Kit, Micro Edition)
2005年,Java 10周年大会正式为J2SE,J2ME,J2EE重新命名
老版本名称 | 新版本名称 |
---|---|
J2SE | Java SE |
J2ME | Java ME |
J2EE | Java EE |
/**
* helloworld
*
* @author gwr
* @date 2019-06-04 18:20
*/
public class HelloWorld/*public修饰的类的名称必须与Java文件同名!*/ {
//main方法四要素必不可少
public static void main/*main方法时Java程序执行的入口点*/(String[] args) {
System.out.println("Hello world!");/*从控制台输出信息*/
}/*{和}一一对应,缺一不可*/
}
1.5.2 Java关键字
类别 | 关键字(共53个) | 个数 |
---|---|---|
量 | true false null this super | 5 |
运算 | new instanceof | 2 |
类型 | boolean byte char short int long float double void class interface enum | 12 |
控制 | if else switch case default for do while continue break return | 11 |
修饰 | private protected public abstract static final synchronized stricfp native transient volatile | 11 |
声明 | package import extends implements | 4 |
异常 | try catch finally throws throw | 5 |
调试 | assert | 1 |
保留 | const goto | 2 |
1.5.3 Java标识符
1.5.3.1 标识符
用于识别不同实体的由若干符号组成的一个名字
标识符的一个最基本的要求
把组成标识符的符号分成两部分
开头的符号:字母、下划线、$
其余的符号:字母、下划线、$、数字
标识符用于类、方法、变量的名字
以名字为中心,名字一般按照不同的主题(包)进行分类管理
1.5.3.2 用户自定义标识符应该满足的条件
对:满足标识符的最基本要求
好:见名知义
美:遵循风格
注:绝对不能与关键字重名;最好不要与系统已定义的标识符重名,以免产生意想不到的麻烦。
1.5.3.3 Java程序设计中涉及的标识符
项目名:即要开发的系统名,要反映项目的整体
文件名:系统中包含的各种文件,一源文件为主,用于存储类的实现代码。一般由类名确定(public)
类名(接口、枚举):每个单词第一个字母大写,其余字母小写
对象名:又称实例名,属于变量范畴
变量名:用于存储数据,分为成员变量和局部变量。成员变量第一个单词全部小写,后面与类名风格一致。局部变量采用小写形式,没有特殊要求
方法名:又称函数,实现对数据的操作,参数属于局部变量,没有局部方法。一般采用动词,动宾词组,名介等形式。
1.5.4 Java语言数据类型
1.5.4.1 数制
十进制、八进制或十六进制数据的表示方法:
以1-9开头的数为十进制数
以0开头的数为八进制数
以0x开头的数为十六进制数
1.5.4.2 数据类型
数据类型转换:
自动类型转换
强制类型转换
Java数据类型类
1.5.4.3 内存如何存放数据
数据各式各样,要先根据数据的需求(即类型)为它申请一块合适的空间
简单数据类型直接保存在栈中
引用数据类型的内容保存在堆中,指向它的指针值保存在栈中
二、封装数据为类
2.1 从对象抽象出“类”
类是模子,是对象的类型,确定对象将会拥有的特征(属性)和行为(方法)
2.1.1 案例:职员
package object;
/**
* Person类
*
* @author gwr
* @date 2019-06-04 19:02
*/
public class Person {
private String name;
private int id;
private char sex;
private int age;
public Person() {
super();
System.out.println("Person类构造函数");
}
public Person(String name, int id, char sex, int age) {
super();
this.name = name;
this.id = id;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id=" + id +
", sex=" + sex +
", age=" + age +
'}';
}
}
package object;
/**
* 地址类
*
* @author gwr
* @date 2019-06-04 19:05
*/
public class Address {
private String addName;
private String addId;
private String city;
private String district;
public Address() {
super();
System.out.println("Address类构造函数");
}
public Address (String addName, String addId, String city,
String district) {
super();
this.addName = addName;
this.addId = addId;
this.city = city;
this.district = district;
System.out.println("Address类构造函数");
}
public String getAddName() {
return addName;
}
public void setAddName(String addName) {
this.addName = addName;
}
public String getAddId() {
return addId;
}
public void setAddId(String addId) {
this.addId = addId;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
@Override
public String toString() {
return "Address{" +
"addName='" + addName + '\'' +
", addId='" + addId + '\'' +
", city='" + city + '\'' +
", district='" + district + '\'' +
'}';
}
}
package object;
/**
* Employee类
*
* @author gwr
* @date 2019-06-04 19:25
*/
public class Employee extends Person {//is
private double salary;
private final int workId;
private static int counter = 0;
private Address homeAddress;//has
private Address comAddress;//has
public Employee() {
super();
this.workId = ++counter;
System.out.println("Employee类构造函数");
}
public Employee(String name, int id, char sex, int age) {
super(name, id, sex, age);
this.workId = ++counter;
System.out.println("Employee类构造函数");
}
public Employee(String name, int id, char sex, int age, double salary,
Address homeAddress, Address comAddress) {
super(name, id, sex, age);
this.salary = salary;
this.workId = ++counter;
this.homeAddress = homeAddress;
this.comAddress = comAddress;
System.out.println("Employee类构造函数");
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getWorkId() {
return workId;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
public Address getComAddress() {
return comAddress;
}
public void setComAddress(Address comAddress) {
this.comAddress = comAddress;
}
@Override
public String toString() {
return super.toString() + "\n" +
"Employee{" +
"salary=" + salary +
", workId=" + workId +
", homeAddress=" + homeAddress +
", comAddress=" + comAddress +
'}';
}
}
package object;
/**
* Manager类
*
* @author gwr
* @date 2019-06-04 19:37
*/
public class Manager extends Employee {
private String department;
public Manager () {
super();
System.out.println("Manager类构造函数");
}
public Manager (String name, int id, char sex, int age, double salary,
Address homeAddress, Address comAddress) {
super(name, id, sex, age, salary, homeAddress, comAddress);
System.out.println("Manager类构造函数");
}
public Manager (String name, int id, char sex, int age, double salary,
Address homeAddress, Address comAddress,
String department) {
super(name, id, sex, age, salary, homeAddress, comAddress);
this.department = department;
System.out.println("Manager类构造函数");
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return super.toString() + "\n" +
"Manager{" +
"department='" + department + '\'' +
'}';
}
}
package object;
/**
* Deirector类
*
* @author gwr
* @date 2019-06-04 19:39
*/
public class Deirector extends Manager {
private int carAllowance;
public Deirector() {
super();
System.out.println("Deirector类构造函数");
}
public Deirector (String name, int id, char sex, int age, double salary,
Address homeAddress, Address comAddress,
String department) {
super(name, id, sex, age, salary, homeAddress, comAddress, department);
System.out.println("Deirector类构造函数");
}
public Deirector (String name, int id, char sex, int age, double salary,
Address homeAddress, Address comAddress,
String department, int carAllowance) {
super(name, id, sex, age, salary, homeAddress, comAddress, department);
this.carAllowance = carAllowance;
System.out.println("Deirector类构造函数");
}
public int getCarAllowance() {
return carAllowance;
}
public void setCarAllowance(int carAllowance) {
this.carAllowance = carAllowance;
}
@Override
public String toString() {
return super.toString() + "\n" +
"Deirector{" +
"carAllowance=" + carAllowance +
'}';
}
}
package object;
import java.util.ArrayList;
/**
* Company类
*
* @author gwr
* @date 2019-06-04 19:44
*/
public class Company {
private int id;
private String comName;
private Address address;
private ArrayList<Employee> employees;
public Company() {
super();
System.out.println("Company类构造函数");
}
public Company(int id, String comName, Address address,
ArrayList<Employee> employees) {
super();
this.id = id;
this.comName = comName;
this.address = address;
this.employees = employees;
System.out.println("Company类构造函数");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getComName() {
return comName;
}
public void setComName(String comName) {
this.comName = comName;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public ArrayList<Employee> getEmployees() {
return employees;
}
public void setEmployees(ArrayList<Employee> employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Company{" +
"id=" + id +
", comName='" + comName + '\'' +
", address=" + address +
", employees=" + employees +
'}';
}
}
package object;
import java.util.ArrayList;
import java.util.List;
/**
* 测试类
*
* @author gwr
* @date 2019-06-04 20:05
*/
public class Test {
public static void main(String[] args) {
System.out.println("First:");
Deirector d = new Deirector();
System.out.println(d);
System.out.println("Second:");
Deirector D = new Deirector("Jack", 1740, '男', 44, 13.14D,
new Address(), new Address(), "nothing", 0);
System.out.println(D);
System.out.println("Third:");
Company c = new Company();
System.out.println(c);
System.out.println("Forth:");
ArrayList<Employee> l = new ArrayList<>();
l.add(d);
l.add(D);
Company C = new Company(233, "破产集团", new Address(), l);
System.out.println(C);
}
}
程序输出
First:
Person类构造函数
Employee类构造函数
Manager类构造函数
Deirector类构造函数
Person{name=‘null’, id=0, sex= , age=0}
Employee{salary=0.0, workId=1, homeAddress=null, comAddress=null}
Manager{department=‘null’}
Deirector{carAllowance=0}
Second:
Address类构造函数
Address类构造函数
Employee类构造函数
Manager类构造函数
Deirector类构造函数
Person{name=‘Jack’, id=1740, sex=男, age=44}
Employee{salary=13.14, workId=2, homeAddress=Address{addName=‘null’, addId=‘null’, city=‘null’, district=‘null’}, comAddress=Address{addName=‘null’, addId=‘null’, city=‘null’, district=‘null’}}
Manager{department=‘nothing’}
Deirector{carAllowance=0}
Third:
Company类构造函数
Company{id=0, comName=‘null’, address=null, employees=null}
Forth:
Address类构造函数
Company类构造函数
Company{id=233, comName=‘破产集团’, address=Address{addName=‘null’, addId=‘null’, city=‘null’, district=‘null’}, employees=[Person{name=‘null’, id=0, sex= , age=0}
Employee{salary=0.0, workId=1, homeAddress=null, comAddress=null}
Manager{department=‘null’}
Deirector{carAllowance=0}, Person{name=‘Jack’, id=1740, sex=男, age=44}
Employee{salary=13.14, workId=2, homeAddress=Address{addName=‘null’, addId=‘null’, city=‘null’, district=‘null’}, comAddress=Address{addName=‘null’, addId=‘null’, city=‘null’, district=‘null’}}
Manager{department=‘nothing’}
Deirector{carAllowance=0}]}
2.1.2 抽象步骤
有两个方面,一方面是它的静态属性,另一方面 是它的动态属性。 反映到 JAVA 里面的类怎么包装它呢?一方面成员变量,另一方面是方法。
2.1.3 深化理解对象
2.1.3.1 日常生活中的对象
在日常生活中,对象就是我们认识世界的 基本单元,它可以是人,也可以是物,还 可以是一件事。
整个世界就是由形形色色的“对象”构成 的(万物皆对象)。
对象是现实世界中的一个实体,其特征是:
- 对象的标示(名称)唯一;
- 对象的状态(属性、数据区)
- 对象的行为(方法、功能)
2.1.3.2 程序中创建对象
必须使用new关键字创建一个对象
使用对象属性(对象名.成员变量)
使用对象方法(对象名.方法名)
同一个类的每个对象有不同的成员变量的存储
空间
同一个类的每个对象共享该类的方法
类是引用类型变量,声明并不为对象分配内存空间,而只是分配一个引用空间;对象的引用类似于指针,是32位的地址空间,它的值指向一个中间的数据结构,它存储有关数据类型的信息以及当前对象所在的堆的地址,而对于对象所在的实际的内存地址是不可操作的,这就保证了安全性。
2.1.3.3 匿名对象
我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象
例如:
- Student stu=new Student();//stu是对象,名字是stu
- new Student();∥这个也是一个对象,但是没有名字,称为匿名对象
- new Student().show();匿名对象方法调用匿名对象用完了之后就变成垃圾了,因为这个对象没有被栈内存中的变量指向,所有会被gc回收
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
我们经常将匿名对象作为实参传递给一个函数调用。
2.1.4 深化理解类
类:在软件中,类,就是一个模板,它定义了一类事物的状态和行为。
类是对现实世界的抽象,因此类是一种抽象的复合数据类型。
类的真正意义就是在描述事物。
属性和功能统称为事物中的成员。事物的成员分为两种:成员属性和成员功能。
成员属性在代码中的体现就是成员变量成员功能在代码中的体现就是成员方法
2.1.5 案例:小王减秤
小王本来体重70Kg,经过减肥,体重降到45Kg, 试从这个问题领域中识别对象、类、属性、行为、 状态,和状态变化
package 小王减秤;
/**
* Person类
*
* @author gwr
* @date 2019-06-04 19:02
*/
public class Person {
private String name;
private int weight;
public Person() {
super();
System.out.println("Person类构造函数");
}
public Person(String name, int weight) {
super();
this.name = name;
this.weight = weight;
}
public int getWeight() {
return weight;
}
public void loseWeight(int newWeight) {
weight = newWeight;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", weight=" + weight +
'}';
}
}
package 小王减秤;
/**
* 小王减肥测试类
*
* @author gwr
* @date 2019-06-04 21:51
*/
public class TestWeight {
public static void main(String[] args) {
Person p = new Person("小王", 70);
System.out.println(p);
p.loseWeight(45);
System.out.println(p);
}
}
Person{name=‘小王’, weight=70}
Person{name=‘小王’, weight=45}
案例:大扫除
package 大扫除;
/**
* Employee类
*
* @author gwr
* @date 2019-06-04 19:25
*/
public class Employee {
private String name;
private final int id;
private static int count = 0;
public Employee(String name) {
super();
this.name = name;
this.id = ++count;
}
public void 擦玻璃() {
System.out.println(this.toString()+"擦玻璃");
}
public void 扫地() {
System.out.println(this.toString()+"扫地");
}
public void 拖地() {
System.out.println(this.toString()+"拖地");
}
public void 倒垃圾() {
System.out.println(this.toString()+"倒垃圾");
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
package 大扫除;
/**
* 大扫除测试类
*
* @author gwr
* @date 2019-06-04 22:00
*/
public class TestEmployee {
public static void main(String[] args) {
Employee tom = new Employee("Tom");
Employee jack = new Employee("Jack");
Employee jean = new Employee("Jean");
Employee mary = new Employee("Mary");
tom.擦玻璃();
jack.扫地();
jean.拖地();
mary.倒垃圾();
}
}
程序输出
Employee{name=‘Tom’, id=1}擦玻璃
Employee{name=‘Jack’, id=2}扫地
Employee{name=‘Jean’, id=3}拖地
Employee{name=‘Mary’, id=4}倒垃圾
2.1.6 类与对象的关系
类和对象之间是抽象和具体的关系。类是创建对象的模板,对象是类的具体实例。
类(class)是总称,对象是个体,因此对象(object)也叫实例(instance)。
2.1.7 深化理解抽象
抽象的过程就是分析的过程,分析中摒弃 细节,提取共性、由复杂到简洁
2.1.8 案例:学生
package stu;
/**
* Student类
*
* @author gwr
* @date 2019-06-04 20:41
*/
public class Student {
private String name;
private char sex;
private String birthday;
private int mathScore;
private int engScore;
public Student() {
super();
}
public Student(String name, char sex, String birthday) {
this.name = name;
this.sex = sex;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getEngScore() {
return engScore;
}
public void setEngScore(int engScore) {
this.engScore = engScore;
}
public double getAverScore() {
return (mathScore + engScore) / 2.0;
}
public int getMaxScore() {
int max;
if (mathScore > engScore)
max = mathScore;
else
max = engScore;
return max;
}
@Override
public String toString() {
return "姓名" + name + ";性别" + sex + ";出生年月;" + birthday;
}
}
package stu;
/**
* 学生测试类
*
* @author gwr
* @date 2019-06-04 20:48
*/
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("Jack", 'M', "19881111");
System.out.println(s1);
s1.setBirthday("1988/11/11");
System.out.println(s1);
s1.setMathScore(59);
s1.setEngScore(61);
System.out.println("math"+s1.getMathScore());
System.out.println("english"+s1.getEngScore());
System.out.println("average"+s1.getAverScore());
System.out.println("max"+s1.getMaxScore());
}
}
程序输出
姓名Jack;性别M;出生年月;19881111
姓名Jack;性别M;出生年月;1988/11/11
math59
english61
average60.0
max61
2.1.9 如何理解消息
对象提供的服务是由对象的方法来实现的,因此发送消息实际上也就是调用一个对象的方法。例如:遥控器向电视机发送“开机”消息,意味着遥控器对象调用电视机对象的开机方法。
2.1.10 类的设计原则
- 取有意义的名字。
- 尽量将数据设计为私有属性。
- 尽量对变量进行初始化。
- 类的功能尽量单一。(类是细粒度的)
2.1.11 属性和方法
2.1.11.1 属性和方法阐述
对象的特征:属性(attribute/instance variable/data field)每个对象的每个属性都拥有特定值
对象的动作:方法
2.1.11.2 属性
在类中表示对象或实体拥有的特性时称为属性
事物的特性,在类中表示为变量
每个对象的每个属性都拥有其特有的值
属性名称由类的所有实例共享
2.1.11.3 方法
对象执行的操作称为方法
操作的实际实现
方法指定操作对象数据的方式
如何执行所请求的操作的规范
在得到操作请求时指定如何做的算法
2.1.11.4 实例
收银员布莱尼 {
属性:姓名(布莱尼),职衔(收银员),年龄(35),体重(60kg)
方法:收款,打印账单,刷卡
}
顾客朱丽叶 {
属性:姓名(朱丽叶),年龄(28),体重(52kg)
方法:购买商品
}
尼古拉斯·凯奇驾驶的这辆法拉利F360 Spider {
属性:品牌(法拉利),型号(F360 Spider),颜色(黄色),价格(380万元)
方法:发动,停止,加速
}
小狗 {
属性:颜色(白色)
方法:叫,跑,吃
}
投影仪 {
属性:颜色(黑色),品牌(BENQ)
方法:投影
}
学生张三 {
属性:姓名(张三),年龄(17)
方法:学习
}
桌子 {
属性:材质(木质)
方法:支撑物品
}
灯泡 {
属性:类型(白炽灯)
方法:开,关,变亮,变暗
}
2.1.12 案例:组装电脑
在网上查询具体每一个硬件的参数和报价;
实体店询价;
询价结束后,根据具体的结果分析出自己比较满意的某品牌报价;
到某品牌店里进行组装,组装时需要进行现场监督。
假如我们需要买组装机,这时应该找一个懂电脑硬件的人,让他帮我们查看参数和报价,并进行询价和杀价,以及现场组装监督。而我们自己并不需要亲历亲为具体怎么做,只要告诉这个人我们想要的具体需求即可。
公共父类Engineer
- 网络管理工程师(类)
- 上网查看参数和报价
- 电话查询
- 电话杀价
- 监督
- 组装工程师(类)
- 组装电脑
- Agent类(测试类)(产生对象,协作完成)
面向对象思维方式是一种更符合人们思考习惯的思想
面向过程思维方式中更多的体现的是执行者(自己做事情),面向对象中更多的体现是指挥者(指挥对象做事情)。
面向对象思维方式将复杂的问题简单化。
面向对象编程:一组对象互相配合通过沟通完成特定功能
做软件苦苦追求的一种境界是可重用性(reusable),可扩展性。
如果是面向过程,一般情况是属性和方法它们是分开的,他们不是聚合的关系,不是合在一起的,这样要复用起来比较麻烦,复用的层次只是局限于方法这个层次上,
而面向对象则不同,它是把属性和方法综合在一个里面。所以面向对象和面向过程相比,前者更加容易让我们达到可重用性。
2.2 类间关系
2.2.1五种类间关系
2.2.1.1 关联关系(Association)
类A与类B的实例之间存在特定的对应关系。
关联指的是类之间的特定对应关系,在UML中用带实线的箭头表示。
按照类之间的数量对比,关联可分为以下三种:
一对一关联:例如假定一个家庭教师只教一个学生,一个学生只有一个家庭教师,那么家庭教师和学生之间是一对一关联。
一对多关联:例如假定一个足球队员只能加入一个球队,一个球队可以包含多个队员,那么球队和队员之间是一对多关联。
多对多关联:例如假定一个足球队员可以加入多个球队,一个球队可以包含多个队员,那么球队和队员之间是多对多关联。
2.2.1.2 依赖关系(Dependency)
类A访问类B提供的服务。
依赖指的是类之间的调用关系,在UML中用带虚线的箭头表示。如果类A访问类B的属性或方法,或者类A负责实例化类B,那么可以说类A依赖类B。
例如:把大象装进冰箱
例如:在面板中绘图
2.2.1.3 聚集关系(Aggregation)
类A为整体类,类B为局部类,类A的对象由类B的对象组合而成。
聚集指的是整体与部分之间的关系,在UML中用带实线的菱形箭头表示。例如:台灯和灯泡之间就是聚集关系。
组合:组合是一种用多个简单子系统来组装出复杂系统的有效手段。
2.2.1.4 泛化关系(Generalization)
类A继承类B。
泛化指的是类之间的继承关系
Shape
Circle
Line
Rectangle
2.2.1.5 实现关系(Realization)
类A实现了B接口。
实现指的是类与接口之间的关系。
在UML中用带虚线的三角形箭头表示,这里的接口指的是接口类型,接口名字用斜体字表示,接口中的方法都是抽象方法,也采用斜体字表示。
2.2.2 案例:客户和订单的关联关系
package CusOrd;
import java.util.HashSet;
import java.util.Set;
/**
* 客户类
*
* @author gwr
* @date 2019-06-05 19:17
*/
public class Customer {
/**
* 所有与Customer对象关联的Order对象
*/
private Set<Order> orders = new HashSet<>();
public Set getOrders() {
return this.orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}
}
package CusOrd;
/**
* 订单类
*
* @author gwr
* @date 2019-06-05 19:17
*/
public class Order {
/**
* 与Order对象关联的Customer对象
*/
private Customer customer;
public Customer getCustomer() {
return this.customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
2.2.3 案例:狗逮耗子的依赖关系
package 狗拿耗子;
/**
* 老鼠类
*
* @author gwr
* @date 2019-06-05 19:25
*/
public class Mouse {
private String name;
private double height;
private double weight;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public void scream() {
System.out.println("被狗咬了!");
}
}
package 狗拿耗子;
/**
* 狗类
*
* @author gwr
* @date 2019-06-05 19:25
*/
public class Dog {
/**狗毛颜色**/
private int furcolor;
/**狗的高度**/
private float height;
/**狗的体重**/
private float weight;
public Dog() {}
public Dog(int furcolor, float height, float weight) {
super();
this.furcolor = furcolor;
this.height = height;
this.weight = weight;
}
public void catchMouse (Mouse mouse) {
mouse.scream();
}
public static void main(String[] args) {
Dog d = new Dog();
Mouse m = new Mouse();
d.catchMouse(m);
}
}
2.2.4 思考题
列举一些现实生活中的例子,来说明什么是依赖关系、什么是聚集关系,以及什么是关联关系。
依赖关系:人依赖食物;电视机依赖电;理发师依赖剪刀和吹风机;鱼依赖水。
聚集关系:电脑由显示器、主机和键盘等聚集而成。
关联关系:公司和员工;银行和客户;老公和老婆。
2.3 类的设计
2.3.1 类的设计原则
取有意义的名字
尽量将数据设计为私有属性
尽量对变量进行初始化
类的功能尽量单一(原子、细粒度)
2.3.2 源文件基本结构
一个基本的Java程序的三大件
- 包的声明:指定类所在的位置
- 类的导入:用到其他位置中的类
- 类的定义:核心部分
Java源文件的基本语法
[<包声明>]
[<导入声明>]
<类声明>+
举例
package shipping.reports;
import shipping.domain.*;
import java.io.Writer;
import java.util.List;
/**
* 源文件布局展示
*
* @author gwr
* @date 2019-06-06 8:29
*/
public class VehicleCapacityReport {
private List vehicles;
public void generateReport(Writer output) {}
}
Java允许在一个Java源文件中编写多个类,但其中的多个类至多只能有一个类使用public修饰。
package 源文件;
/**
* 一个类放在一个源文件中
*
* @author gwr
* @date 2019-06-06 8:34
*/
public class Student {
/**成员属性:学号、姓名、性别、年龄**/
private String studentId;
private String studentName;
private String studentSex;
private int studentAge;
/**
* 构造函数
*/
public Student() {
super();
}
}
package 源文件;
/**
* 多个类放在一个源文件中
*
* @author gwr
* @date 2019-06-06 8:36
*/
public class ClassTest {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("HelloWorld!");
}
}
class Test1{
}
class Test2{
}
2.3.3 定义类
2.3.3.1 定义一个类的步骤
- 定义类名(每个单词的第一个字母大写,其余的小写)
- 编写类的属性
- 编写类的方法
2.3.3.2 类的定义格式
类修饰符 class 类名 extends 基类
implements 接口列表
{
[数据成员定义]
[成员方法定义]
}
2.3.3.3 类的定义说明
关键字class表示类定义的开始
类名要符合标识符的命名规范
修饰符分为访问控制符和类型说明符
2.3.4 符号
2.3.4.1 访问控制符
类的访问控制符有两个,一个是public,即公共类,另一个就是默认,即没有访问控制符。
- 一个类被定义为公共类,就表示它能够被其它所有的类访问和引用。
- 在一个Java源程序中只能有一个public类,这个类一般含有main方法。
- 不用public定义的类,其只能被同一个包中定义的类访问和引用。
- 在一个Java程序中可以定义多个这样的类。
2.3.4.2 类型说明符
类的类型说明符主要有两个:final abstract
2.3.5 成员变量的定义
成员变量的定义格式:
-[修饰符]变量的数据类型变量名[=初始值]
修饰符主要有四种,分别是:
① public、
② private、
③ protected、
④默认。
2.3.6 成员方法的定义
2.3.6.1 方法的定义格式
修饰符 返回值类型 方法名(形参说明)
throws例 外名1,例外名2…
{
局部变量声明;
执行语句组;
}
2.3.6.2 成员方法的定义说明
常用的修饰符为public、private、protected、static、final等
返回值类型:方法一般需要有一个返回值表示执行结果,也可以无返回值(用void表示)。返回值类型可以是Java类型系统中的所有类型。有返回值的方法使用return语句将值返回给调用者。
2.4 特殊点强调
2.4.1 案例:return的理解
package understand_return;
/**
* return退出方法
* 结束方法,无输出
*
* @author gwr
* @date 2019-06-06 8:54
*/
class Dog{
String name;
public void bark(int a) {
if (a == 0) {
System.out.println("你好");
} else if (a == 1) {
return;
}
System.out.println("我很好");
}
}
public class FangFa1 {
public static void main(String[] args) {
Dog d = new Dog();
d.bark(1);
}
}
2.4.2 案例:toString()方法
在java中,所有对象都有默认的toString()这个方法
创建类时没有定义toString()方法,输出对象时会输出对象的哈希码值(对象的内存地址)它通常只是为了方便输出,比如System.out.println(xx),(xx是对象),括号里面的”xx”如果不是String类型的话,就自动调用xx的toString()方法
它只是sun公司(0racle)开发java时为了方便所有类的字符串操作而特意加入的一个方法
package toString方法研究;
/**
* Desk类
*
* @author gwr
* @date 2019-06-06 9:01
*/
public class Desk {
private String colcr;
private int length;
private int width;
private int height;
public Desk() {
super();
}
public Desk(String colcr, int length, int width, int height) {
super();
this.colcr = colcr;
this.length = length;
this.width = width;
this.height = height;
}
public String getColcr() {
return colcr;
}
public void setColcr(String colcr) {
this.colcr = colcr;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void print() {
System.out.println("printDesk{" +
"colcr='" + colcr + '\'' +
", length=" + length +
", width=" + width +
", height=" + height +
'}');
}
public static void main(String[] args) {
//test phrase 1
Desk d1 = new Desk();
d1.print();
d1.setColcr("red");
d1.setHeight(40);
d1.setLength(20);
d1.setWidth(20);
d1.print();
//test phrase2
Desk d2 = new Desk("red", 30, 30, 30);
d2.print();
System.out.println(d2.toString());
System.out.println(d2);
}
}
程序输出
printDesk{colcr=‘null’, length=0, width=0, height=0}
printDesk{colcr=‘red’, length=20, width=20, height=40}
printDesk{colcr=‘red’, length=30, width=30, height=30}
toString方法研究.Desk@7eda2dbb
toString方法研究.Desk@7eda2dbb
2.4.3 案例:教育机构
设计程序满足以下四点:某教育机构在北京、杭州等地都有分公司,在不同分公司,你会感受到相同的环境和教学氛围。
A中信的默认值是“杭州中心”
编写A中心的toString(),输出该中心的描述信息
编写测试类
package 教育机构;
/**
* 教育机构A
*
* @author gwr
* @date 2019-06-06 9:17
*/
public class A {
/**A中心的属性(成员变量)**/
/**中心的全称,默认值为“杭州中心”**/
private String schoolName = "杭州中心";
/**教室的数目**/
private int classNum;
/**机房的数目**/
private int labNum;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public int getClassNum() {
return classNum;
}
public void setClassNum(int classNum) {
this.classNum = classNum;
}
public int getLabNum() {
return labNum;
}
public void setLabNum(int labNum) {
this.labNum = labNum;
}
/**
* A培训机构的toString方法
*
* 用于输出类的相关信息
*/
@Override
public String toString() {
return "A{" +
"schoolName='" + schoolName + '\'' +
", classNum=" + classNum +
", labNum=" + labNum +
'}';
}
}
class InitialSchool{
public static void main(String[] args) {
A center = new A();
System.out.println(center);
center.setSchoolName("北京中心");
center.setClassNum(10);
center.setLabNum(10);
System.out.println(center);
System.out.println(center.toString());
}
}
程序输出
A{schoolName=‘杭州中心’, classNum=0, labNum=0}
A{schoolName=‘北京中心’, classNum=10, labNum=10}
A{schoolName=‘北京中心’, classNum=10, labNum=10}
2.5 类的访问机制
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量;
在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。
2.5.1 this关键字
在类的方法定义中使用this关键字代表使用该方法的对象的引用
有时,使用this可以处理方法中成员变量和参数重名的问题
this可以看做一个变量,他的值是当前对象的引用
package this关键字;
/**
* this关键字解读
*
* @author gwr
* @date 2019-06-06 9:27
*/
class Cat{
String name;
char sex;
int age;
public void set(String name, char sex, int age) {
this.name = name;//为了区别两个name用this代表使用该方法的对象c的引用
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
Cat c = new Cat();
c.set("wth", '母', 2);
System.out.println(c);
}
}
2.6 基本类型和引用类型作
2.6.1 基本数据类型作为参数传递(深拷贝)
package 不同数据类型传参;
/**
* 数据类型传参
*
* @author gwr
* @date 2019-06-06 9:33
*/
public class Demo {
public static void main(String[] args) {
int x = 4;
show(x);
System.out.println("x="+x);
}
public static void show(int x) {
x = 5;
}
}
程序输出
x=4
基本类型作为参数传递时,其实就是将基本类型变量×空间中的值复制了一份传递给调用的方法show(),当在show()方法中x接受到了复制的值,再在show()方法中对x变量进行操作,这时只会影响到show中的x。当show方法执行完成,弹栈后,程序又回到main方法执行,main方法中的x值还是原来的值。
2.6.2 引用数据类型作为参数传递(浅拷贝)
package 不同数据类型传参;
/**
* 数据类型传参
*
* @author gwr
* @date 2019-06-06 9:33
*/
public class Demo {
private int x;
public static void main(String[] args) {
Demo d = new Demo();
d.x = 5;
show(d);
System.out.println("x=" + d.x);
}
public static void show(Demo d) {
d.x = 6;
}
}
程序输出
x=6
当引用变量作为参数传递时,这时其实是将引用变量空间中的内存地址(引用)复制了一份传递给了show方法的d引用变量。这时会有两个引用同时指向堆中的同一个对象。当执行show方法中的d.x=6时,会根据d所持有的引用找到堆中的对象,并将其x属性的值改为6。
由于是两个引用指向同一个对象,不管是哪一个引用改变了引用的所指向的对象的中的值,其他引用再次使用都是改变后的值。
2.6.3 进一步理解引用类型变量
对象由两部分组成:对象的实体;对象的引用
案例:Person pl=new Person(“Jack","Male",23);
内存状态变化过程分析
案例:
Person p1=new Person(“Jack”,”Male”,23);
Person p2=p1;
Person p3=new Person(“Jack”,”Male”,23);
2.7 方法的重载
方法的重载是指一个类中可以定义有相同的名字,但参数不同的多个方法,调用时会根据不同的参数表选择对应的方法。
2.7.1 生活中的方法重载
类 | 方法 | 方法参数 | 方法实现 |
---|---|---|---|
司机 | 驾驶 | 轿车 | 启动、行驶 |
司机 | 驾驶 | 巴士 | 等待乘客上车、启动、行驶、到站停车 |
司机 | 驾驶 | 火车 | 正点发车、行驶、到站停车 |
如果用代码实现,我们需要三个方法,这些方法的方法名称相同,参数类型不同。
2.7.2 Java中的方法重载
示例1:java.io.PrintStream类的println方法能够打印数据并换行,根据数据类型的不同,有多种实现方式。
在PrintStream中println(int)、println(char)、println(String)是方法名相同,参数类型不同的,所以是方法重载
/**
* Test类
*
* @author gwr
* @date 2019-06-06 10:04
*/
public class Test {
public static void main(String[] args) {
int i = 0;
char c = 'z';
String s = "hello";
System.out.println(i);
System.out.println(c);
System.out.println(s);
}
}
示例2:java.lang.Math类的max()方法能够从两个数字中取出最大值,它有多种实现方式
运行时,Java虚拟机先判断给定参数的类型,然后决定到底执行哪个max()方法。
在Math中max(int a, int b)、max(float a, float b)、max(long a, long b)、max(double a, double b)是方法名相同,参数类型不同的,所以是方法重载
/**
* Test类
*
* @author gwr
* @date 2019-06-06 10:04
*/
public class Test {
public static void main(String[] args) {
Math.max(1,2);
Math.max(1.0F, 2.0F);
Math.max(1.0, 2);
}
}
2.7.3 构造函数方法重载
2.7.3.1 构造方法
构造方法(constructor)是一类特殊的成员方法。
从功能上讲,它使用new关键字用来对新创建的对象进行初始化的。
从形式上来讲,它有以下特点:
- 它与类同名;
- 它没有任何返回值;
- 除了上述两点外,在语法结构上与一般的方法相同。
2.7.3.2 构造方法重载
Java语言中,每个类都至少有一个构造方法;
构造方法有两大类,构造方法可以重载,并且通常是重载的:
通过调用不同的构造方法来表达对象的多种初始化行为
2.7.3.3 案例:教育机构
-默认情况下,教师来自北京中心,初始化时,只需提供教员姓名
-有时,需要提供所在中心名称及教员姓名
/**
* 教师类
*
* @author gwr
* @date 2019-06-06 10:17
*/
public class Teacher {
/**姓名**/
private String name;
/**所在中心**/
private String school = "北京中心";
public Teacher(String name) {
this.name = name;
}
public Teacher(String name, String school) {
this.name = name;
this.school = school;
}
public String introduction() {
return "Teacher{" +
"name='" + name + '\'' +
", school='" + school + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
class TeacherTest{
public static void main(String[] args) {
Teacher t1 = new Teacher("Mary");
System.out.println(t1.introduction());
Teacher t2 = new Teacher("Jack", "天津中心");
System.out.println(t2.introduction());
}
}
2.7.3.4 不带参数构造方法(默认构造方法)
public Teacher() {
}
Java语言中,每个类都至少有一个构造方法;如果类的定义者没有显式的定义任何构造方法,系统将自动提供一个默认的构造方法:
- 默认构造方法没有参数
- 默认构造方法没有方法体
- 默认的构造方法:Animal(){}
- 所以:不编写构造方法就能用new Xxx()创建类的实例。
无参构造函数创建对象时,成员变量的值被赋予了数据类型的隐含初值。
变量类型 | 默认值 | 变量类型 | 默认值 |
---|---|---|---|
byte | o | short | 0 |
int | o | long | OL |
float | 0.0f | double | 0.0d |
char | \u0000’ | boolean | false |
引用类型 | null |
在Java里,如果一个类没有明显的表明哪一个类是它的父类,0bject类就是它的父类。如果类中没有定义构造函数,编译器会自动创建一个默认的不带参数的构造函数。
如果程序员为类定义了构造函数,Java就不会为该类创建默认的不带参数的构造函数。
注意:如果类中提供的构造函数都不是无参数构造函数,却企图调用无参数构造函数初始化此类的对象,编译时会产生语法错误。
2.7.3.5 带参数构造方法
通过带参数的构造方法,显式地为实例变量赋予初始值
类中有太多的属性及对应的setter方法,在初始化时,很容易就忘记了,造成代码冗余,要简化对象初始化的代码,可以通过调用带参数的构造方法解决。
/**
* 教师类
*
* @author gwr
* @date 2019-06-06 10:17
*/
public class Teacher {
/**姓名**/
private String name;
/**年龄**/
private int age;
/**学历**/
private String education;
/**职位**/
private String position;
public String introduction() {
return "大家好,我是" + name +
",我今年" + age +
"岁,学历是'" + education +
",职位是" + position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEducation() {
return education;
}
public void setEducation(String education) {
this.education = education;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
}
class TeacherTest{
public static void main(String[] args) {
Teacher t = new Teacher();
t.setName("Mary");
t.setAge(99);
t.setEducation("本科");
t.setPosition("老师");
System.out.println(t.introduction());
}
}
可以通过调用带参数的构造方法,简化对象初始化的代码,做到创建对象时,一并完成了对象成员的初始化工作
public Teacher(String name, int age, String education, String position) {
this.name = name;
this.age = age;
this.education = education;
this.position = position;
}
class TeacherTest{
public static void main(String[] args) {
Teacher t = new Teacher("Mary",99,"本科","老师");
System.out.println(t.introduction());
}
}
2.7.3.6 构造函数实例化类对象的格式
- 类名对象名=new构造函数(实际参数)
- New关键字的作用
①为对象分配内存空间。
②引起对象构造方法的调用。
③为对象返回一个引用。
2.7.3.7 辨别构造方法
给定如下Java代码,请指出代码中的错误,并解释原因
public class Sample{
private int x;
//T无参构造函数
public Sample() {
x=1;
}
//T带参构造函数
public Sample(int i) {
x=i;
}
//T不是构造函数
public int Sample(int i) {
x=i;
return x++;
}
//T带参构造函数
private Sample(int i,String s){}
//T带参构造函数
public Sample(String s,inti){}
//F名称与类名不相同
private Sampla(int i) {
x=i++;
}
//T不是构造方法
private void Sampla(int i) {
x=i++;
}
2.8 局部变量和成员变量
自动初始化只用于成员变量,方法体中的局部变量不能被自动初始化,必须赋值后才能使用。
2.8.1 案例:person
package 全局变量和局部变量;
/**
* Person类
*
* @author gwr
* @date 2019-06-06 10:51
*/
public class Person {
private String name;
private String sex;
private int age;
public Person() {
}
public Person(String name, String sex, int age/*方法体中的局部变量不能被自动初始化,
必须赋值后才能使用*/) {
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1);
Person p2 = new Person("Jack", "男", 20);
System.out.println(p2);
int i = 0;//局部变量必须初始化后才能使用
System.out.println(i);
}
}
2.8.2 区别
- 区别一:定义的位置不同
- 定义在类中的变量是成员变量
- 定义在方法中或者}语句里面的变量是局部变
量
- 区别二:在内存中的位置不同
- 成员变量存储在堆内存的对象中
- 局部变量存储在栈内存的方法中
- 区别三:声明周期不同
- 成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失
- 局部变量随着方法的运行而出现在栈中,随着方法的弹栈而消失
- 区别四:初始化不同
- 成员变量因为在堆内存中,所有成员变量具有默认的初始化值
- 局部变量没有默认的初始化值,必须手动的给其赋值才可以使用。
2.8.3 案例:对象的内存图解
package 对象的内存图解;
/**
* Car
*
* @author gwr
* @date 2019-06-06 10:59
*/
public class Car {
String color;
int number;
void run() {
System.out.println(color+":"+number);
}
}
package 对象的内存图解;
/**
* Demo
*
* @author gwr
* @date 2019-06-06 11:00
*/
public class CarDemo {
public static void main(String[] args) {
Car c = new Car();
c.color = "red";
c.number = 4;
c.run();
}
}
2.9 内存管理
2.9.1 内存管理的两种方法
- 一种方法是由程序员在编写程序时显式地释放内存,例如C++。
- 另一种方法是由语言的运行机制自动完成,例如Smalltalk,EiffeI和Java。
2.9.2 JAVA内存管理
2.9.2.1 垃圾自动回收机制
Java虚拟机后台线程负责内存的回收。垃圾强制回收机制:Java系统提供了方法
“System.gc()”和“Runtime.gc()”方法来强制立即回收垃圾(但系统并不保证会立即进行垃圾回收)。
判断一个存储单元是否是垃圾的依据是:该存储单元所对应的对象是否仍被程序所用。
判断一个对象是否仍为程序所用的依据是:是否有引用指向该对象。
Java的垃圾收集器自动扫描对象的动态内存区,对所引用的对象加标记,然后把没有引用的对象作为垃圾收集起来并释放出去。
Java虚拟机可以自动判断并收集到“垃圾”,但一般不会立即释放它们的存储空间。
Java系统自己定义了一套垃圾回收算法,用来提高垃圾回收的效率。
2.9.2.2 Java内存强制回收
System.gc();强制系统回收垃圾内存
Runtime.gc();强制系统回收垃圾内存Java没有提供析构方法,但提供了一个类似的方法:protected void finalize()。
Java虚拟机在回收对象存储单元之前先调用该对象的finalize方法,如果该对象没有定义finalize方法,则java系统先调用该对象默认的finalize方法。
package Java垃圾回收;
/**
* Java垃圾回收
*
* @author gwr
* @date 2019-06-06 11:06
*/
class JavaBook extends Object {
private String name;
JavaBook(String name) {
this.name = name;
}
@Override
protected void finalize() {
System.out.println("Book" + name + "is destroyed!");
}
}
public class JavaFinalize {
public static void main(String[] args) {
JavaBook book = new JavaBook("工科数学分析");
new JavaBook("大学物理");
new JavaBook("下雨了");
System.gc();
/*其实当我们直接调用System.gc()
只会把这次gc请求记录下来,
等到runFinalization=true的时候才会先去执行GC,
runFinalization=true之后会在允许一次system.gc()。
之后在call System.gc()还会重复上面的行为。
*/
//调用这句话使gc立即执行
System.runFinalization();
book = new JavaBook("我在上马原课");
}
}
2.10 类的静态属性和静态方法
2.10.1 程序运行时的内存占用
代码区(code area)存放程序的代码部分
数据区(data area)存放程序的全局数据和静态数据
堆区(heap area)存放程序动态申请的数据
栈区(stack area)存放程序的局部数据和参数
2.10.2 回答问题
问题一:不论产生多少个对象,或不存在任何对象的情况下,某些特定数据的存储空间都只有一份;
-例如:统计出从Person共new出多少个对象?
问题二:某些数据或者函数不要和class object绑在一起。
通过关键字static,便可以处理这两种情况,当你将某个数据成员或某个成员函数声明为static时,它就不再局限于所属的class object上。
Java中把这种代表类范围信息的变量用关键字static修饰。
2.10.3 Static的使用场合
用static修饰的属性(变量)称为静态属性,又叫类变量;用static修饰的方法称为静态方法,又叫类方法(静态方法里,无this);可以用来修饰初始化语句块,这样的语句块常称为静态初始化语句块(要跟非静态初始化语句块区分开来)
2.10.4 案例:统计出从Person共new出多少个对象
理解并掌握Static关键字的用法
类变量概念
类方法概念
适用场合:通过关键字static,便可以处理这两种情况,当你将某个数据成员或某个成员函数声明为static时,它就不再局限于所属的class object上。
即使没有创建该类的具体对象,类中的static类成员也会存在,这时可以通过:
1.类名.静态变量
2.类名.静态方法
package 全局变量和局部变量;
/**
* Person类
*
* @author gwr
* @date 2019-06-06 10:51
*/
public class Person {
private String name;
private String sex;
private int age;
private static int count;
public static int getCount() {
return count;
}
public Person(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
count++;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
Person p1=new Person("张三","男",20);
System.out.print("count="+p1.getCount()+"\t");//1
System.out.print("count="+Person.getCount()+"\n");//1
Person p2=new Person("Tom","M",50);
System.out.print("count="+p2.getCount()+"\t");//2
System.out.print("count="+Person.getCount()+"\n");//2
Person p3=new Person("Mary","F",10);
System.out.print("count="+p3.getCount()+"\n");//3
System.out.println("通过类名和不同对象名访问静态变量count:");
System.out.print("count="+Person.getCount()+"\n");//3
System.out.print("count="+p1.getCount()+"\t");//3
System.out.print("count="+p2.getCount()+"\t");//3
System.out.print("count="+p3.getCount()+"\n");//3l
}
}
程序输出
count=1 count=1
count=2 count=2
count=3
通过类名和不同对象名访问静态变量count:
count=3
count=3 count=3 count=3
2.10.5 案例:TestStudent.java
重点:类变量和类方法;实例变量和实例方法
类变量和类方法
1.类的变量和方法是由关键字static修饰的的。
2.类变量和类方法由该类产生的所有实例共享。
3.调用方式:
·类名\对象名.静态变量
·类名\对象名.静态方法
实例变量和方法
1.每一个实例拥有一份独立拷贝,因此每个实例对象的数据是独立且唯一的。
2.调用方式:
1.对象名.事例变量
2.对象名.事例方法
package stu;
/**
* 学生测试类
*
* @author gwr
* @date 2019-06-04 20:48
*/
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.num);
Student zhang = new Student();
Student guo = new Student();
Student wu = new Student();
System.out.println("zhang.num = "+ zhang.add1());
System.out.println("zhang.number = "+ zhang.add2());
System.out.println("guo.num = "+ guo.add1());
System.out.println("guo.number = "+ guo.add2());
System.out.println("wu.num = "+ wu.add1());
System.out.println("wu.number = "+ wu.add2());
}
}
程序输出
10
zhang.num = 11
zhang.number = 1
guo.num = 12
guo.number = 1
wu.num = 13
wu.number = 1
2.10.6 回答问题
你知道main()为什么要用static修饰的原因了吗?
main()方法中的static可以去掉吗?
静态代码块与非静态代码块的异同点
2.10.7 静态代码块与非静态代码块的异同点
相同点:
1.都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个。
2.一般在代码块中对一些static变量进行赋值。
不同点:
1.静态代码块在非静态代码块之前执行:①静态代码块一〉非静态代码块一〉构造方法
2.静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new一次就执行一次
2.10.8 案例:初始化顺序
package 静态代码块;
/**
* 代码块初始化顺序
*
* @author gwr
* @date 2019-06-06 13:28
*/
public class staticBlock {
private static int counter;
private int cnt;
public staticBlock() {
System.out.println("默认构造方法");
}
/**
* 非静态代码块
*/
{
System.out.println("非静态代码块");
cnt = 4;
counter = 4;
}
/**
* 静态代码块
*/
static {
System.out.println("静态代码块");
counter = 5;
//cnt = 5;
}
/**
* 静态成员方法
*/
public static void test() {
System.out.println("静态成员方法:普通方法中的代码块");
}
/**
* 测试
*/
public static void main(String[] args) {
System.out.println("main函数");
staticBlock s = new staticBlock();
s.test();
}
}
程序输出
静态代码块
main函数
非静态代码块
默认构造方法
静态成员方法:普通方法中的代码块
2.11 总结
需求中提取类,即抽象的过程。
创建一个类就是创建一个新的数据类型,实例化一个类,就得到一个对象。
类的构成有两部分,分别是成员变量和成员方法。
类的成员变量可以是基本类型或数组,也可以是类的对象。
类的成员方法用于处理该类的数据,是用户与对象之间或对象之间的交互接口。
类的设计是细粒度的 – 例如:公司员工拥有地址,包括公司地址和家 庭地址,一般我们会单独编写地址类(Address)
从编程需求出发,不需要的不考虑,所有的属性 和方法,都是在编程中所需要用到的。 – 是你的,打死也要。不是你的,打死也不要
1个工具:抽象Abstract(摒弃细节,提取共性)
2个概念:对象Object(客观存在的实体);类Class(具有相同性质的对象的抽象体)
3个特性:封装Encapsulation;继承Inheritance;多态Polymorphism
4个步骤:分析Analysis(·找出系统中的对象,抽象出类,确定它们所属的不同主题,分析它们之间的关系);设计Design:(·对每个类应该封装的数据及其操作进行详细设计和描述);实现Implementation:(·采用某种编程语言编码(Coding)实现各个类);测试Test:(·由类创建对象,验证其功能和性能是否满足需求)
对象是程序所处理数据的最主要的载体,数据以实例变量的形式存放在对象中。每个对象在生命周期的开始阶段,Java虚拟机都需要为它分配内存,然后对它的实例变量进行初始化。
对象构造顺序:用new语句创建类的对象时,Java虚拟机会从最上层的父类开始,依次执行各个父类以及当前类的构造方法,从而保证来自于对象本身以及从父类中继承的实例变量都被正确地初始化。
对象构造顺序:当子类的构造方法没有通过super语句调用父类的构造方法,那么Java虚拟机会自动先调用父类的默认构造方法。
匿名对象:当一个对象不被程序的任何引用变量引用,对象就变成无用对象,它占用的内存就可以被垃圾回收器回收。
合理地使用内存:每个对象都会占用一定的内存,而内存是有限的资源,为了合理地利用内存,在决定对象的生命周期时,应该遵循以下原则:-当程序不需要再使用一个对象,应该及时清除对这个对象的引用,使它的内存可以被回收。一重用已经存在的对象。程序可通过类的静态工厂方法来获得已经存在的对象,而不是通过new语句来创建新的对象。(Java反射)
静态代码块只能定义在类里面,它独立于任何方法,不能定义在方法里面。
静态代码块里面的变量都是局部变量,只在本块内有效。
静态代码块会在类被加载时自动执行,而无论加载者是JVM还是其他的类。
一个类中允许定义多个静态代码块,执行的顺序根据定义的顺序进行。
静态代码块只能访问类的静态成员,而不允许访问实例成员。
即使没有创建该类的具体对象,类中的static类成员也会存在,这时可以通过:类名.静态变量 ;类名.静态方法。
static方法中不能直接调用非static的域或方法(必须通过对象名引用)。
1.static函数并不需要先产生任何对象,就可以通过类名来调用。
2.non-static数据/函数和对象绑定(原因)。
3.在static函数中“直接”取用non-static数据/函数,会产生语法错误。