第0周 数组和对象的使用
0.1 数组
int[] numbers = new int[100];
所有数据都是相同类型
数组大小一旦确定无法改变(例如int[100],就只能是100个元素)
[] 名字 = new [元素个数];
元素个数必须给出,必须是整数,可以是变量;
每个元素可以当作一个那个类型的变量;
通过下标访问每个元素,注意下标从0开始,最大下标为[元素个数]-1;
编译器不检查下标是否合法,但是如果下标不合法运行会报错,导致程序终止;
for ( cnt>0)
{int[] numbers = new int[cnt];for ( int i=0; i
{
numbers[i]=in.nextInt();
sum+=numbers[i];
}double average = sum/cnt;
}
0.2 对象
包裹类型
将一个基本数据类型的数据转换成对象的形式,使它们可以像对象一样参与运算和传递。
注意大小写。
用处:可以方便的使用函数(如Integer.MAX_VALUE)
字符串
String s = new String("a string");
in. next(); 读入一个单词(以空格 \t 回车划分)
赋值
String a, String b
b = a;
是让b和a共同管理了原来a管理的字符串;
比较
相等
不能用 == 来比较
== 只能比较是不是同一个字符串
要比较两个字符串的内容用.equals
s.quals("bye");
true, 意味着字符串的内容是"bye"
大小
String s1 = "abc";
String s2= "abb";
System.out.println(s1.compareTo(s2));
1,s1更大(比较unicode编码)
.charAt
返回字符串某个下标对应的字符,下标从0开始;
.indexOf
String s1 = "0123A56789";
System.out.println(s1.indexOf('A');//4
System.out.println(s1.indexOf('A56');//4
System.out.println(s1.indexOf('3');//3
String s1 = "0123A56389";
如何找第二个3?
System.out.println(s1.indexOf('3'), loc+1);//7
得到子串
substring
String s1 = "0123456789"
System.out.println(s1.subString(2));//23456789
System.out.println(s1.subString(2,4));//[2,4),23
第1周 类与对象
1.1 用类制造对象
对象:实体,需要被创建,可以为我们做事情
类:规范,根据类的定义来创建对象
对象 = 属性+服务
数据:属性或状态
操作:函数
1.2 定义类
创建对象
new VedningMachine();
VendingMachine v = new VendingMachine();
(同一个类可以创建多个对象,例如v1,v2...)
让对象做事
.运算符
v.insertMoney(10);
v.getFood();
1.3 成员变量和成员函数
成员变量
类定义了对象中所具有的变量,这些变量称作成员变量
每个对象有自己的变量,和同一个类的其他对象是分开的
函数与成员变量
函数通过对象来调用
v.insertMoney()
这次调用临时建立了insertMoney和v之间的联系,让insertMoney内部的成员变量指得失v的成员变量
这种联系是靠我们见不到的"this" 建立的。this是成员函数的一个特殊的固有的本地变量,它表达了调用这个函数的那个对象。
public classVendingMachine{int price = 80;intbalance;inttotoal;void setPrice(intprice)
{this.price = price //this.price 在setPrice里this.price指离它最近的price,也就是参数的price. price是指成员变量,值为80的price
}
...
}
调用函数
成员函数内部直接调用自己(this)的其他函数
成员函数外部通过 对象.运算符 来调用某个对象的函数
本地变量
定义在函数内部的变量是本地变量
成员变量和本地变量生存期和作用域不同。本地变量定义生存期和作用域都是函数内部。成员变脸的生存期是对象的生存期,作用域是类内部的成员函数。
1.4 对象初始化
默认给成员变量零值;
函数重载
一个类可以有多个构造函数,只要它们参数表不同。
创建对象的时候给出不同的参数值,就会自动调用不同对构造函数。
通过this()还可以调用其他构造函数。
一个类里同名但是参数表不同的函数构成了重载关系。
VendingMachine() //构造函数
{
total= 0;
}
VendingMachine(int price) //重载
{this(); //调用那个没有参数的构造函数。但是这样只能用在函数的开始,且只能用一次。
this.price =price;
}
第2周 对象交互
2.1 对象交互
2.2 访问属性
封装,就是把数据和对这些数据的操作放在一起,并且用这些操作把数据掩盖起来,是面向对象的基本概念之一,也是最核心的概念。
我们有一个非常直截了当的手段来保证在类的设计的时候做到封装:
所有的成员变量必须是private的,这样就避免别人任意使用你的内部数据;
所有public的函数,只是用来实现这个类的对象或类自己要提供的服务的,而不是用来直接访问数据的。除非对数据的访问就是这个类及对象的服务。简单地说,给每个成员变量提供一对用于读写的get/set函数也是不合适的设计。
Private
private关键字只能用于成员变量/成员函数。private的变量和函数只能在类的内部访问。
只有两个地方能用private的东西:
成员函数(比如构造函数,main函数…)
成员变量的定义可以用已经定义的成员变量
public classDisplay {private int value = 0;private int limit = value;//可以使用已经定义的成员变量
...
注意:同一个类不同对象可以互相访问别人的私有的成员变量。私有的限制是对类而不是对对象。
Public
其他地方可以用
public类:
源代码文件名必须和public类名字相同。
Friendly
如果没有public和private => friendly
和它位于同一个包的其他类可以访问。
Protected
2.3 包
包:类点管理机制
用文件夹结构管理包
包名中的点代表文件夹层次
2.4 类变量
类变量
static
不属于任何一个对象,属于类。
如何访问:
可以从类访问,也可以从对象访问。就只有这么一个变量,每个对象都可以访问,一旦一个对象里修改了,在别的对象里再调用它它的值也是已经修改的。
类函数
属于类的函数。
类函数里只能访问类函数、类变量,不能使用对象的东西。
Static成员的初始化和对象的创建没有关系。它只能在类的装载的时候初始化一次。
第3周 对象容器
3.1 顺序容器
容器类
private ArrayList notes = new ArrayList();
用来存放String的ArrayList,是一个泛型类,是一个容器类。
容器类是用来存放对象的,可以存放任意数量的对象。
容器类定义的时候需要两个类型
容器的类型 e.g.ArrayList
元素的类型(在容器里放什么东西) e.g.String
ArrayList可以直接用System.out.println();直接输出。
3.2 对象数组
对象数组中的每个元素都是对象的管理者,而非对象本身。
当创建一个对象数组后,对象还不存在,还要把每个对象创建出来,然后里面的东西才有用。
容器类可以用for-each循环。
v=a[0],指v和a[0]共同管理a[0]所管理的对象。
3.3 集合容器 Set
就是数学当中“集合”的概念
没有重复的元素
没有顺序
Set可以直接用System.out.println();直接输出。
只要有了public String to String(){ },就可以用System.out.println()输出对象。ArrayList和Set里都实现了toString,因此才能用System.out.println()输出。
3.4 Hash表
Hash表,有的地方翻译为散列表。
传统意义上的Hash表,是能以int做值,将数据存放起来的数据结构。Java的Hash表可以以任何实现了hash()函数的类的对象做值来存放对象。
第4周 继承
4.1 继承
面向对象程序设计语言有三大特性:封装、继承和多态性。
基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是public还是private。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。显然,通过继承来定义新的类,远比从头开始写一个新的类要简单快捷和方便。继承是支持代码重用的重要手段之一。
我们把用来做基础派生其它类的那个类叫做父类、超类或者基类,而派生出来的新类叫做子类。Java用关键字extends表示这种继承/派生关系:
继承表达了一种is-a关系,就是说,子类的对象可以被看作是父类的对象。比如鸡是从鸟派生出来的,因此任何一只都可以被称作是一只鸟。但是反过来不行,有些鸟是鸡,但并不是所有的鸟都是鸡。
Java的继承只允许单继承,即一个类只能有一个父类。
4.2 子类父类关系
子类从父类那里得到了什么:所有的东西,所有的父类的成员,包括变量和方法,都成为了子类的成员,除了构造方法。
构造方法是父类所独有的,因为它们的名字就是类的名字,所以父类的构造方法在子类中不存在。除此之外,子类继承得到了父类所有的成员。
但是得到不等于可以随便使用。每个成员有不同的访问属性,子类继承得到了父类所有的成员,但是不同的访问属性使得子类在使用这些成员时有所不同:有些父类的成员直接成为子类的对外的界面,有些则被深深地隐藏起来,即使子类自己也不能直接访问。下表列出了不同访问属性的父类成员在子类中的访问属性:
父类成员访问属性
在父类中的含义
在子类中的含义
public
对所有人开放
对所有人开放
protected
只有包内其它类、自己和子类可以访问
只有包内其它类、自己和子类可以访问
缺省
只有包内其它类可以访问
如果子类与父类在同一个包内:只有包内其它类可以访问
否则:相当于private,不能访问
private
只有自己可以访问
不能访问
public的成员直接成为子类的public的成员,protected的成员也直接成为子类的protected的成员。Java的protected的意思是包内和子类可访问,所以它比缺省的访问属性要宽一些。而对于父类的缺省的未定义访问属性的成员来说,他们是在父类所在的包内可见,如果子类不属于父类的包,那么在子类里面,这些缺省属性的成员和private的成员是一样的:不可见。父类的private的成员在子类里仍然是存在的,只是子类中不能直接访问。我们不可以在子类中重新定义继承得到的成员的访问属性。如果我们试图重新定义一个在父类中已经存在的成员变量,那么我们是在定义一个与父类的成员变量完全无关的变量,在子类中我们可以访问这个定义在子类中的变量,在父类的方法中访问父类的那个。尽管它们同名但是互不影响。
在构造一个子类的对象时,父类的构造方法也是会被调用的,而且父类的构造方法在子类的构造方法之前被调用。在程序运行过程中,子类对象的一部分空间存放的是父类对象。因为子类从父类得到继承,在子类对象初始化过程中可能会使用到父类的成员。所以父类的空间正是要先被初始化的,然后子类的空间才得到初始化。在这个过程中,如果父类的构造方法需要参数,如何传递参数就很重要了。
第5周 多态
5.1 多态变量和向上造型
类定义了类型,DVD类所创建的对象的类型就是DVD。类可以有子类,所以由那些类定义的类型可以有子类型。在DoME的例子中,DVD类型就是Item类型的子类型。
子类型类似于类的层次,类型也构成了类型层次。子类所定义的类型是其超类的类型的子类型。
当把一个对象赋值给一个变量时,对象的类型必须与变量的类型相匹配,如:
Car myCar = new Car();
是一个有效的赋值,因为Car类型的对象被赋值给声明为保存Car类型对象的变量。但是由于引入 了继承,这里的类型规则就得叙述得更完整些:
一个变量可以保存其所声明的类型或该类型的任何子类型。
对象变量可以保存其声明的类型的对象,或该类型的任何子类型的对象。
Java中保存对象类型的变量是多态变量。“多态”这个术语(字面意思是许多形态)是指一个变量可以保存不同类型(即其声明的类型或任何子类型)的对象。
子类和子类型
类定义了类型
子类定义了子类型
子类的对象可以被当作父类的对象来使用
赋值给父类变量
传递给需要父类对象的函数
放进存放父类对象的容器里
5.2 多态
多态变量
Java的对象变量是多态的,它们能保存不止一种类型的对象。
它们可以保存的是声明类型的对象,或者声明类型的子类的对象。
当把子类的对象赋给父类的变量的时候,就发生了向上造型。
造型 cast
造型:把一个类型的对象赋给另一个类型的变量。
子类的对象可以赋值给父类的变量
注意:Java中不存在对象对对象的赋值!而是让两个对象的管理者去管理同一个对象。(大部分oop都是这样)
父类对象不能赋值给子类变量,可以用造型
Vechicle v;
Car c= newCar();
v= c; //可以
c = v; //编译错误
c = (Car) v; //可以。这是造型,只有当v这个变量实际管理的是car对象才行。
造型是用括号围起类型放在值的前面
对象本身并没有发生任何变化,所以不是类型转换
运行时有机制来检查这样的转化是否合理
ClassCastException
如果子类的方法覆盖了父类的方法,我们也说父类的那个方法在子类有了新的版本或者新的实现。覆盖的新版本具有与老版本相同的方法签名:相同的方法名称和参数表。因此,对于外界来说,子类并没有增加新的方法,仍然是在父类中定义过的那个方法。不同的是,这是一个新版本,所以通过子类的对象调用这个方法,执行的是子类自己的方法。
覆盖关系并不说明父类中的方法已经不存在了,而是当通过一个子类的对象调用这个方法时,子类中的方法取代了父类的方法,父类的这个方法被“覆盖”起来而看不见了。而当通过父类的对象调用这个方法时,实际上执行的仍然是父类中的这个方法。注意我们这里说的是对象而不是变量,因为一个类型为父类的变量有可能实际指向的是一个子类的对象。
当调用一个方法时,究竟应该调用哪个方法,这件事情叫做绑定。绑定表明了调用一个方法的时候,我们使用的是哪个方法。绑定有两种:一种是早绑定,又称静态绑定,这种绑定在编译的时候就确定了;另一种是晚绑定,即动态绑定。动态绑定在运行的时候根据变量当时实际所指的对象的类型动态决定调用的方法。Java缺省使用动态绑定。
函数调用的绑定
当通过对象变量调用函数的时候,调用哪个函数这件事叫做绑定
静态绑定:根据变量的声明类型来决定
动态绑定:根据变量的动态类型来决定(动态类型:运行的时候才知道)
在成员函数中调用其他成员函数也是通过this这个对象变量来调用的
Java默认所有绑定都是动态的。所有成员函数的绑定都应该看成是动态的。
覆盖override
子类和父类种存在名称和参数完全相同的函数,这一对函数构成覆盖关系。
通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理的对象所属的类的函数。
5.3 类型系统
单根结构:所有的类都是继承自Object
第6周 设计原则
6.1 城堡游戏
6.2 消除代码复制
代码复制是设计不良的表现
消除代码复制的两个基本手段,就是函数和父类。
6.3 封装
对于类的设计来说,有两个核心术语:耦合和聚合。
耦合这个词指的是类和类之间的联系。之前的章节中提到过,程序设计的目标是一系列通 过定义明确的接口通信来协同工作的类。耦合度反映了这些类联系的紧密度。我们努力要获得 低的耦合度,或者叫作松耦合(loose coupling)。
耦合度决定修改应用程序的容易程度。在一个紧耦合的结构中,对一个类的修改也会导致 对其他一些类的修改。这是要努力避免的,否则,一点小小的改变就可能使整个应用程序发生 改变。另外,要想找到所有需要修改的地方,并一一加以修改,却是一件既困难又费时的事情。 另一方面,在一个松耦合的系统中,常常可以修改一个类,但同时不会修改其他类,而且 整个程序还可以正常运作。
聚合与程序中一个单独的单元所承担的任务的数量和种类相对应有关,它是针对类或方法 这样大小的程序单元而言的理想情况下,一个代码单元应该负责一个聚合的任务(也就是说,一个任务可以被看作是 一个逻辑单元)。一个方法应该实现一个逻辑操作,而一个类应该代表一定类型的实体。聚合 理论背后的要点是重用:如果一个方法或类是只负责一件定义明确的事情,那么就很有可能在 另外不同的上下文环境中使用。遵循这个理论的一个额外的好处是,当程序某部分的代码需要 改变时,在某个代码单元中很可能会找到所有需要改变的相关代码段。
当需要反复修改String时候,用StringBuffer对象。
6.4 可扩展性
6.5 框架加数据
第7周 抽象与接口
7.1 抽象
在第一周就有一个Shape类的例子。这个类有很多的子类,每个子类也都实现了父类的方法。实际上父类Shape只是一个抽象的概念而并没有实际的意义。如果请你画一个圆,你知道该怎么画;如果请你画一个矩形,你也知道该怎么画。但是如果我说:“请画一个形状,句号”。你该怎么画?同样,我们可以定义Circle类和Rectangle类的draw(),但是Shape类的draw()呢?
Shape类表达的是一种概念,一种共同属性的抽象集合,我们并不希望任何Shape类的对象会被创建出来。那么,我们就应该把这个Shape类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以存在抽象方法。抽象方法也是使用abstract关键字来修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体。
如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。
抽象函数:表达概念而无法实现具体代码的函数
抽象类:表达概念而无法构造出实体的类
带有abstract修饰符的函数/类
抽象类不能制造对象,但是可以定义变量
实现抽象函数
继承抽象类的子类必须覆盖父类中的抽象函数(实现)
否则子类自己就成为了抽象类
7.2 数据与表现分离:细胞自动机
7.3 接口:狐狸与兔子
实现接口
类用extends,接口用implements
类可以实现很多接口
接口可以继承接口,但是不能继承类
接口不能实现接口
面向接口的编程方式
设计程序时先定义接口,再实现类
任何需要在函数间传入传出的一定是接口而不是具体的任何类
优点:适合多人合作
缺点:代码量变大,臃肿
第8周 控制反转与MVC模式
8.1 控制反转
8.2 MVC设计模式