面向对象大纲
类与对象
面向对象与面向过程
面向过程和面向对象都是对软件分析、设计和开发的一种思想,它指导着人们以不同的方式去分析、设计和开发软件。早期先有面向过程思想,随着软件规模的扩大,问题复杂性的提高,面向过程的弊端越来越明显的显示出来,出现了面向对象思想并成为目前主流的方式。两者都贯穿于软件分析、设计和开发各个阶段,对应面向对象就分别称为面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)。C语言是一种典型的面向过程语言,Java是一种典型的面向对象语言。
面向过程思想思考问题时,我们首先思考“怎么按步骤实现?”并将步骤对应成方法,一步一步,最终完成。 这个适合简单任务,不需要过多协作的情况下。比如,如何开车?我们很容易就列出实现步骤:
面向过程适合简单、不需要协作的事务,重点关注如何执行。
但是当我们思考比较复杂的设计任务时,比如“如何造车?”,就会发现列出1234这样的步骤,是不可能的。那是因为,造车太复杂,需要很多协作才能完成。此时面向对象思想就应运而生了。
面向对象(Oriented-Object)思想更契合人的思维模式。我们首先思考的是“怎么设计这个事物?” 比如思考造车,我们就会先思考“车怎么设计?”,而不是“怎么按步骤造车的问题”。这就是思维方式的转变。
其次应该思考"应该让谁来实现?",这个"谁"就是对象 , 对象如何实现我们不关注,只关注对象本身。
比如,我们用面向对象思想思考“如何设计车”:
天然的,我们就会从“车由什么组成”开始思考。发现,车由如下对象组成:
为了便于协作,我们找轮胎厂完成制造轮胎的步骤,发动机厂完成制造发动机的步骤;这样,发现大家可以同时进行车的制造,最终进行组装,大大提高了效率。但是,具体到轮胎厂的一个流水线操作,仍然是有步骤的,还是离不开执行者、离不开面向过程思维!
![\]
](https://img-blog.csdnimg.cn/2...
类与对象的概念
我们人认识世界,其实就是面向对象的(此对象可不是男女谈对象的彼对象呀) 。比如现在让大家认识一下“天使”这个新事物,天使大家没见过吧,怎么样认识呢?最好的办法就是,给你们面前摆4个天使,带翅膀的美女,让大家看,看完以后,即使我不说,大家下一次是不是就都认识天使了。
|
图1-1 认识天使 |
但是,看完10个天使后,我们总要总结一下,什么样的东东才算天使?天使是无数的,总有没见过的!所以必须总结抽象,便于认识未知事物!总结的过程就是抽象的过程。小时候,我们学自然数时怎么定义的?像1,2,3,4…这样的数就叫做自然数。 通过抽象,我们发现天使有这样一下特征:
- 带翅膀(带翅膀不一定是天使,还可能是鸟人)
- 女孩(天使掉下来脸着地,也是天使!)
- 善良
- 头上有光环
那么通过这4个具体的天使,我们进行抽象,抽象出了天使的特征,我们也可以归纳一个天使类。 通过这个过程,类就是对象的抽象。
对象:是具体的事物 xiaoming xiaohong
类:是对对象的抽象(抽象 抽出象的部分)Person
先有具体的对象,然后抽象各个对象之间象的部分,归纳出类通过类再认识其他对象。
生活案例
- 类是一个图纸 对象是根据该图纸制造多个实物
- 类是一个模具 对象是使用模具制造的多个铸件(月饼模子 )
- 类是上海大众汽车,对象就是大家购买的一辆辆具体上海大众汽车
类可以看做是一个模版,或者图纸,系统根据类的定义来造出对象。我们要造一个汽车,怎么样造?类就是这个图纸,规定了汽车的详细信息,然后根据图纸将汽车造出来。 |
---|
类:我们叫做class。 对象:我们叫做Object,instance(实例)。以后我们说某个类的对象,某个类的实例。是一样的意思。 |
对象和类的关系:
- 特殊到一般,具体到抽象。
- 类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
- 类是用于描述同一类形的对象的一个抽象的概念,类中定义了这一类对象所应具有的静态和动态属性。
- JDK提供了很多类供编程人员使用,编程人员也可定义自己的类。
自定义类与对象
自定义类
做了关于对象的很多介绍,终于进入代码编写阶段。本节中重点介绍类和对象的基本定义,属性和方法的基本使用方式。
定义类(类的组成)
- 属性 field
- 方法 method
- 构造方法 construtor
- 其他:代码块 静态代码块 内部类
属性(field 成员变量)
属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。
在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。
表4-2 成员变量的默认值 | |
---|---|
数据类型 | 默认值 |
整型 | 0 |
浮点型 | 0.0 |
字符型 | '\u0000' |
布尔型 | false |
所有引用类型 | null |
属性定义格式:
[修饰符] 属性类型 属性名 = [默认值] ;
public class Person{
String name = "张三";
}
说明:
方法
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
方法定义格式:
[修饰符] 方法返回值类型 方法名(形参列表) {
// n条语句
}
public class Person{
//成员变量
String name;
//成员方法
public void study(){
System.out.println("一个程序猿正在努力工作...");
}
}
使用
创建对象
类名 对象名 = new 类名();
Person p1=new Person();
调用类的属性和方法
对象名.成员变量
对象名.成员方法()
p1.name = "李四";
p1.study();
类的实例
一般类中有三种常见的成员:属性field、方法method、构造器constructor。这三种成员都可以定义零个或多个。
编写简单的学生类:
public class Student {
//属性(成员变量)
int id;
String sname;
int age;
//方法
void study(){
System.out.println("我正在学习!");
}
//构造方法
Student(){
}
}
一个典型的IT学生类:
class Computer {
String brand; //品牌
}
public class ITStudent {
// field
int id;
String sname;
int age;
Computer comp;
void study() {
System.out.println("我正在学习!使用我们的电脑,"+comp.brand);
}
ITStudent() {
}
public static void main(String[ ] args) {
Student stu = new Student();
stu.sname = "张三";
Computer comp = new Computer();
comp.brand = "联想";
stu.comp = comp;
stu.study();
}
}
练习题目:
1) 自定义小汽车类并使用
2) 自定义天使类并使用
3) 自定义学生类并使用
成员变量与局部变量的区别
- 声明位置不同 成员变量定义在类中方法外 , 局部变量定义在方法中|语句块中
作用范围不同:成员变量-> 当前类的所有方法 , 局部变量->当前方法
- 不同的方法中即使有同名的局部变量,没有关系,互不影响,建议相同
- 内存存放的位置的:局部变量->栈内存中 , 成员变量->堆内存中
- 默认值问题: 成员变量有默认值 , 局部变量没有默认值
类与类之间的关系
类之间大体分为6种关系:
在设计模式中类与类之间的关系主要有6种:依赖、关联、聚合、组合、继承,实现, 它们之间的耦合度依次增加。
继承关系(Inheritance)
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识。
public class Person {
String name;
int age;
void move(){}
}
//继承
class Student extends Person{
void study(){}
}
class Teacher extends Person{
void teach(){}
}
实现关系
实现指的是一个class类实现interface接口(可以是多个)的功能,实现是类与接口之间最常见的关系。在Java中此类关系通过关键字implements明确标识。
interface Vehicle{
void move();
}
class Ship implements Vehicle{
void move(){
System.out.println("水里移动..");
}
}
class Ship Car Vehicle{
void move(){
System.out.println("陆地跑..");
}
}
依赖关系(Dependency)
简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是类B的变化会影响到类A。比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。表现在代码层面,为类B作为参数被类A在某个method方法中使用。
public class Person {
public void drive(Car car){} //方法参数
}
class car{}
关联关系(Association)
关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。关联可以是单向、双向的。表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。
public class Person {
public Address address; //关联关系
public void setAddress (Address address){
this.address= address;
}
public Address getAddress (){
return address;
}
}
class Address{}
聚合关系(Aggregation)
单向,关联关系的一种,与关联关系之间的区别是语义上的,关联的两个对象通常是平等的,聚合则一般不平等,有一种整体和局部的感觉,实现上区别不大。表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
public class Team {
public Person person;
public Team(Person person){
this.person = person;
}
}
Class由Student组成,其生命周期不同,整体不存在了,部分依然存在,当前Team解散了,人还在,还可以加入别的组。
组合关系(Composition)
单向,是一种强依赖的特殊聚合关系
public class Person {
public Head head;
public Body body;
public Person(){
head = new Head();
body = new Body();
}
}
Head,Body,Arm和Leg组合成People,其生命周期相同,如果整体不存在了,部分也将消亡。
内存分析
Java中的对象和数组是通过引用对其操作的.
- 引用可以理解为一种受限的指针
- 引用只能进行赋值运算。
- 引用就是一个变量或对象的别名(引用的本质是一个对象);指针是一个段内存空间的地址(指向存储一个变 量值的空间或一个对象的空间)
- java中的引用 存储堆中对象的地址
内存划分 :
栈:
• 存放:局部变量
• 先进后出,自下而上存储
• 方法执行完毕,自动释放空间
堆:
• 存放new出来的对象
• 需要垃圾回收器来回收
• 无序,根据对象的地址区分
方法区:
• 存放:类的信息(代码)、 static变量、字符串常量等.
class Student{
String name;
Birthday birthday;
}
class Birthday{
int year;
int month;
int day;
}
public static void main(String[] args){
Student s=new Student();
s.name="zhangsan";
s.birthday = new Birthday();
s.birthday.year=2010;
s.birthday.month=10;
}
课后练习:
1)自定义一个实体类,并测试
2)手动实现成员运行期的内存分析图帮助大家理解
3)手动记录运行过程,内存发生行为步骤
例: 第一步 :程序运行,加载类信息到内存中
第二步:栈中为main方法开辟栈帧...
第三步:new关键字创建对象,在堆中为对象开启空间...
...
经典案例
有一个人走进商店,他对服务员说:我想要一个东西,这个东西呢,它是圆形的,是甜甜的,上面有奶油,并且有一些水果在上面,可以插蜡烛... 他繁复得叙述的这个什么东西,究竟是什么呢?其实我不说大家也猜得到:他想要一个生日蛋糕。
现实中你只需要说,服务员来个蛋糕,服务员把单子交给了面点师,服务员说”好咧,1 小时后来取”,面点师一步步按流程制作蛋糕,最终蛋糕做的如何,就看面点师的了
分析:根据客户的需要,我们来制作蛋糕。
首选要有一个制作蛋糕的菜谱( 类 ),里面当然要有制作这个蛋糕需要么原材料( 成员属性) 。
public class Cake {
public String shape;// 蛋糕的形状
public int cream;// 奶油的量
public int eggs; // 鸡蛋的量
public int water;// 水的量
public String bakeTime;// 烤制时间
public String others;// 其他配料
}
其次还要有一个蛋糕师(类),它不仅仅有自己的名字等( 成员属性),还要有一个能力就是会做蛋糕( 成员方法)。
class Baker{
String name; //名字
public Cake makeCake(){
Cake cake =new Cake();
cake.shape ="麻将型";
cake.cream =50;
cake.water =500;
cake.eggs =5;
cake.bakeTime="2016-03-21";
cake.others="黄油butter 糖sugar";
return cake;
}
}
好了,现在你可以取蛋糕了~
public static void main(String[] args){
Baker baker=new Baker();
baker.name = "胡歌";
Cake cake=baker.makeCake();
}
构造方法(构造器 constructor)
构造器也叫构造方法(constructor),用于对象的初始化。构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
声明格式
[修饰符] 类名(形参列表){
//n条语句
}
public Dog(){}
构造器4个要点:
- 构造器的方法名必须和类名一致!
- 构造器虽然有返回值,但是不能定义返回类型(返回值的类型肯定是本类),不能在构造器里调用return。
- 通过new关键字调用!!
- 如果我们没有定义构造器,则系统会自动定义一个无参的构造方法。如果已定义则编译器不会添加无参数构造方法!
- 与普通方法一样,构造方法也可以重载
- 修饰符 final abstract static不能用来修饰构造器
作用
初始化对象信息的,不是用于创建对象的
空构造
没有参数构造器叫做无参构造
- 一个类中,如果没有显式|手动 加入 任意构造器 javac 编译后 自动加入空构造
- 一旦加入构造器 ,javac 不会加入空构造器。
class Dog{
String color;
String name;
//空构造
//public Dog(){} 默认提供
}
重载
一个类中可以存在多个构造器
- 方法重载: 两同三不同 同一个类方法名相同,形参类型 个数 顺序不同
- 构造器重载: 只看形参即可 形参类型 个数 顺序不同。调用时按“就近最优原则”
class Dog{
String color;
String name;
//空构造
Dog(){}
public Dog(String name,String color){
this.name=name;
this.color=color;
}
public static void main(String[ ] args) {
Dog d1 = new Dog();
Dog d2 = new Dog("二狗子", "白色");
Dog d3 = new Dog("三狗子", "土色");
}
}
this关键字
this 即”自己”,代表对象本身,谁调用代表谁。在成员方法中或构造器中隐式的传递。作用如下:
- this.属性避免属性和形参、局部变量同名,发生就近原则
- this([实参列表]): 构造器的首行调用其他构造器。
class Web{
//网址
public String url;
public Web(){
System.out.println("构造器");
}
public Web(String url){
this(); //this()构造器的调用
this.url =url;//this.属性 区分同名问题
}
//赋值
public void setUrl(String url){
this.url =url;
}
/**
属性与形参 同名,发生就近原则
public Web(String url){
url =url;
}
//二者不同名
public Web(String u){
url =u;
}*/
}
注意: 静态方法中无 this。
成员方法分析与应用场景
成员的是属于对象的,根据一系列对象分析抽取的共性定义在模板类中的成员位置。
class Person{
String name; //成员变量
//成员方法
void eat(){
}
}
在外部想要使用类中的成员,必须跟随这个类的对象使用。
如果是根据对象分析出的功能,把它定义在类中的成员方法中。
如果不想跟随对象使用,那就定义成静态方法,非成员方法。
static关键字
凡是静态的都是属于类的,与对象无关的,先于对象存在的。可用于修饰属性、方法、块。
在类中,用static声明的成员变量为静态成员变量 ,或者叫做: 类属性,类变量.
- 它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化,
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
- 可以使用”对象.类属性”来调用。不过,一般都是用“类名.类属性”
- static变量置于方法区中!
用static声明的方法为静态方法
- 不需要对象,就可以调用(类名.方法名)
- 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可直接访问非static的成员。但是可以通过对象使用。
- 静态方法不能以任何方式引用this和super关键字
class StaticDemo01 {
static int id;//静态变量
int age; //成员变量
public static void main(String[] args) {
//静态的内容可以直接使用
System.out.println("id1="+id); //id1=0
System.out.println("id2="+StaticDemo01.id); //id2=0
test();
//通过对象使用成员
StaticDemo01 sd=new StaticDemo01();
System.out.println("age="+sd.age);//age=0
}
/*
* 静态方法
*/
public static void test(){
id++;
}
/*
* 成员方法 使用静态和非静态的内容
*/
public void test2(){
//非静态的方法中可以直接使用成员内容,可以通过对象使用
age++;
id++;
}
}
注意:
- 静态内容中只能直接使用静态内容,通过对象使用成员内容
态方法**
- 不需要对象,就可以调用(类名.方法名)
- 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可直接访问非static的成员。但是可以通过对象使用。
- 静态方法不能以任何方式引用this和super关键字
class StaticDemo01 {
static int id;//静态变量
int age; //成员变量
public static void main(String[] args) {
//静态的内容可以直接使用
System.out.println("id1="+id); //id1=0
System.out.println("id2="+StaticDemo01.id); //id2=0
test();
//通过对象使用成员
StaticDemo01 sd=new StaticDemo01();
System.out.println("age="+sd.age);//age=0
}
/*
* 静态方法
*/
public static void test(){
id++;
}
/*
* 成员方法 使用静态和非静态的内容
*/
public void test2(){
//非静态的方法中可以直接使用成员内容,可以通过对象使用
age++;
id++;
}
}
注意:
- 静态内容中只能直接使用静态内容,通过对象使用成员内容
- 成员内容中可以直接使用静态内容,可以直接使用成员内容,也可以通过对象使用
看视频学习更轻松:学习视频