- Java程序的三个阶段
- Type
- Class
- Runtime
- Java类的3个结构
- Field
- Constructor
- Method
project(工程) > (src) > package(包) > class(类) > object(对象)> 成员(变量,函数和内部类)
一个类中可以有成员变量、方法,还可以有内部类。内部类实际上是它所在类的成员。内部类最重要的特点就是能够访问外部类的所有成员
面向对象编程三大特性
封装,继承,多态
Java中的变量:
1.成员变量(实例变量,属性)
2.本地变量(局部变量)
3.类变量(静态属性)
byte 字节 就是2个16进制数 00到FF 8位
1024 byte = 1k b
Java基本类型占用的字节数:
1字节: byte , boolean
2字节: char,short
4字节: int , float
8字节: long , double
附录:
编码:
数字都是一个1字节
GBK: 中文2字节
UTF-8: 中文通常3字节,在拓展B区之后的是4字节
int默认10进制,数字前面加0b表示2进制,0x表示16进制
final关键字
- 可以用来修饰一个类,方法,局部变量,成员变量
类与对象
普通变量
对象变量(管理者)
- 类是规范,对象是实体
- 对象 = 属性(数据)+函数(操作) = 成员变量+成员函数
- 封装:把数据和对数据的操作放在一起(外部的操作保护内部的数据)
- 定义类
- 创建对象
new VendingMachine();
VendingMachine v = new VendingMachine();
对象变量是对象的管理者
运算符.
- 成员变量和成员函数
- 函数要通过对象来调用
- this是成员函数固有的本地变量,他表示调用这个函数的那个对象
- 在成员函数内部可以直接调用自己(this)的其他成员函数
- 定义在函数内部的是本地变量,生存期和作用域都在函数内部
- 成员变量的生存期是对象的生存期,作用域是类内部的成员函数
- 对象初始化
- java会给未初始化的成员变量赋0值(广义,boolean给false,对象变量给None等)
- 构造函数(不能有返回类型)
- 如果有一个成员函数的名字和类的名字完全相同,构造对象时候被自动调用,这个函数则是构造函数
- 不能有返回类型
- 创建对象先进构造函数的头,在去定义成员变量,再进构造函数体
- 构造函数可以有多个,只要参数表不同即可(可以接受参数,也可以不接受参数)。通过this()可以调用其他构造函数(只能使用一次)。还可以根据创建对象时给的参数来选择调用哪个构造函数。(称为重载)
- 重载
一个类里的同名但参数表不同的函数构成了重载关系
对象交互
类的首字母大写
- 对象的识别
- 对象交互
多个对象可组成一个对象
tip(%占位符,%d整数%f小数)
- 封闭的访问属性
- 所有的成员都可以设定访问属性
- private 成员为类私有,只有成员函数和成员变量可以访问
私有是针对类而不是针对对象,即同一类的其他对象都可以访问
- 开放的访问属性
- public表示任何人都可以访问他
- 没有public或者private限制的,我们称为friendly,即同一个包内的可以访问。
- protect在继承中再提
- class是public表示任何地方都可以用该类的定义来定义一个变量
编译单元(.java文件):一个编译单元最多只能有一个class是public
-
包(管理机制)
- 在一个目录底下的所有编译单元(源代码文件),包的名字就是目录的名字。
- 如果不import其他包,想要用里面的类就得给全名,比如display.Display。import display.*不推荐,防止和本地包的类重名
- 包的里面还可以包含包,如java.util.Scanner
-
类变量
public class Display{
private static int step = 1;
}
- d1.step = d2.step = Display.step
- 可通过对象访问类变量,但是类变量不属于对象
- 类函数(static函数)
属于类的函数,可以访问其他类函数
public class Display{
public static viod main = {
};
}
static成员的初始化和对象的创建没关系
对象容器
-
泛型容器类
- 容器的两个类型
- 容器的类型(ArrayList)
- 元素的类型(String)
- ArrayList < String > (ArrayList of String)
- 创建一个该类对象notes后可用的操作
- notes.size() 查看有多少条
- notes.get(index) 获得相应索引的元素
- notes.add(location,element) 相应位置加元素
- notes.remove(index) 返回remove的元素
- notes.toArray(a) 将内容填充到数组a中
- 创建一个该类对象notes后可用的操作
- 可使用for-each循环
- 容器的两个类型
-
对象数组
对象不存在则为null
- String[] 里面的元素是String类的管理者(和基础类型数组的区别)
- 可定义String a = null
- length()可获得数组的长度
- for-each循环,以下代码是可实现的(和基础类型数组的区别)
//对字符串数组a而言 String[] a = new String[10]; for (String k : a){ k = "good"; }
-
集合容器
- HashSet< String >
- 无顺序,元素不能重复
- toString()方法使得该容器可以直接输出
class Value{ public String toString(){ return ""+i;} }
-
Hash表
- HashMap<Interger,String>
private HashMap<Interger,String> coinnames = new HashMap<Interger,String>(); coinnames.put(key,value) coinnames.keySet() //得到key表 coinnames.keySet().size() coinnames.get(index)
继承(Inherited)
基于已有的设计创造新的设计,就是面向对象程序设计的继承
代码复制是代码质量不良的表现,不好维护
- 基础派生出其他类的那个类叫做父类(超类,基类),派生出来的叫子类。
Java用关键字extends来表示这种继承/派生关系
class ThisClass extends SuperClass{//…} - 子类的对象对可以看做是父类的对象。
- Java只允许单继承,即一个类只能有一个父类
- 父类所有的成员都会被子类继承,都是存在的,都是可能可以用的(还要考虑访问权限)
public:所有人都能访问
protected:包内和包外的子类可以访问
缺省:包内可以访问
private:只有类自己可以访问
- public的成员直接成为子类的public的成员,protected的成员也直接成为子类的protected的成员。Java的protected的意思是包内和子类可访问,所以它比缺省的访问属性要宽一些。而对于父类的缺省的未定义访问属性的成员来说,他们是在父类所在的包内可见,如果子类不属于父类的包,那么在子类里面,这些缺省属性的成员和private的成员是一样的:不可见。父类的private的成员在子类里仍然是存在的,只是子类中不能直接访问。我们不可以在子类中重新定义继承得到的成员的访问属性。如果我们试图重新定义一个在父类中已经存在的成员变量,那么我们是在定义一个与父类的成员变量完全无关的变量,在子类中我们可以访问这个定义在子类中的变量,在父类的方法中访问父类的那个。尽管它们同名但是互不影响。
- 子类通过super()来调用父类的构造函数,从而构造自己的成员变量。
构造子类对象时,先进构造函数头,再进父类的构造函数初始化,再进入定义初始化,再去做构造函数的剩下部分。
可以理解为:
父类的定义初始化和构造初始化做完后,再做子类的定义和构造初始化
没有super()会默认去找父类中没有参数的构造器,如果有super(),就根据super()中的参数来寻找父类的构造函数。
-
在构造一个子类的对象时,父类的构造方法也是会被调用的,而且父类的构造方法在子类的构造方法之前被调用。在程序运行过程中,子类对象的一部分空间存放的是父类对象。因为子类从父类得到继承,在子类对象初始化过程中可能会使用到父类的成员。所以父类的空间正是要先被初始化的,然后子类的空间才得到初始化。在这个过程中,如果父类的构造方法需要参数,如何传递参数就很重要了。
-
子类如果有函数和父类同名,使用super.func()来调用父类的那个函数(父类这个函数是可访问时)
-
父类item和子类DVD
//Item.java
package database;
public class Item {
private String title;
private int playingTime;
private boolean gotIt;
private String comment;
public Item(String title, int playingTime, boolean gotIt, String comment) {
this.title = title;
this.playingTime = playingTime;
this.gotIt = gotIt;
this.comment = comment;
}
// public void setTitle(String title) {
// this.title = title;
// }
public void print() {
System.out.print(title+" ");
}
public static void main(String[] args){
}
}
//DVD.java
package database;
public class DVD extends Item {
private String director;
public DVD(String title,String director,int playingTime, boolean gotIt, String comment) {
super(title,playingTime,gotIt,comment);
this.director = director;
}
public void print() {
System.out.print("DVD: ");
super.print();
System.out.print(director);
}
public static void main(String[] args){
DVD dvd = new DVD("lovelyy","wjj",120,false,"...");
dvd.print();
}
}
多态
- 子类和子类型
- 类定义了类型
- 子类定义了子类型
- 子类的对象可以被当做父类的对象来使用
- 赋值给父类的变量
- 传递给需要父类对象的函数
- 放进存放父类对象的容器里
- 多态变量(声明(静态)类型,动态类型)
- java的对象变量是多态的,它们能保存不止一种类型的对象
- 它们可以保存的是声明类型的对象,或者声明类型的子类的对象
- 当把子类的对象赋给父类的变量的时候,就发生了向上造型
- 造型cast
- 子类的对象可以赋值给父类的变量(向上造型)
注意!java中不存在对象对对象的赋值,是对象的管理者同时管理(或者说管理权限的变化) - 父类的对象不能直接赋值给子类的变量(除非Person p = (Person)obj这样)
- 子类的对象可以赋值给父类的变量(向上造型)
- 用括号围起来的类型放在值的前面称为造型
- 对象本身没有发生任何变化,所以不是“类型转换(int i = (int)10.2)”,要区分(虽然英语的单词都是cast)!
- 运行时有机制来检查这样的转化是否合理(ClassCastException)
- 向上造型
- 拿一个子类的对象,当做父类对象来用
对于DVD对象dvd,Item类型变量i
i = dvd - 向上造型是默认的,不需要运算符
- 向上造型是安全的
- 拿一个子类的对象,当做父类对象来用
- 向下造型例子
对于DVD变量d,Item类对象v
d = (DVD) item;
需要v被指向一个DVD这个子类对象。如果没有指向,那在编译时时没问题的,但是运行时会产生错误
-
多态
- 函数调用的绑定(对多态变量而言(如item))
- 当通过对变量对象调用函数时,调用哪个函数这件事情叫做绑定
- 静态绑定:根据变量的声明类型来决定
- 动态绑定:根据变量的动态类型来决定(java都是动态绑定)
- 在成员函数中调用其他成员函数也是通过this这个对象变量来调用的(看做动态绑定)
- 当通过对变量对象调用函数时,调用哪个函数这件事情叫做绑定
- 覆盖(override)
- 子类和父类存在名称和参数表完全相同的函数,这一对函数构成覆盖关系
- 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理的对象所属的类的函数
- 函数调用的绑定(对多态变量而言(如item))
-
Object类
java是单根结构,所有的类都是Object类的子类,Object类是root类- Object类的函数
Obeject o = new Object();
o. 来查看有哪些函数- toString() (如果不覆盖(override),默认Object类的toString()会输出package.Class@e76cbf7)
如果对一个对象进行字符串加法,会寻找是否有这个方法,如果有就能进行字符串的加法 - equals()(默认来查看是否管理的是同一个对象)
可覆盖(override)来设置该函数为:查看某个成员变量是否相等
@override public boolean equals(Object obj){ CD cc = (CD)obj; return artist.equals(cc.artist); }
- toString() (如果不覆盖(override),默认Object类的toString()会输出package.Class@e76cbf7)
- @Override表示(为了告诉编译器)以下部分的函数,是覆盖了父类的函数。和父类的函数具有完全相同的函数签名(函数原型):函数的名字和函数的参数表都相同,而且都是public(权限也不能变)
- Object类的函数
-
例子:dome的新媒体类型
- 代码的可拓展性,与可维护性不同(可维护性是易于修改,可拓展性是易于增加)
- 子类的底下还可以再派生子类,生成更深的继承关系
设计原则
- 代码复制问题
编写函数方法来解决 - 封装
通过封装来降低耦合(通过接口来解耦)- 类和类之间的关系称为耦合
高耦合的表现:两类都有大量的代码和出口相关,大量使用另外一个类的成员变量 - 耦合越低越好
- 类和类之间的关系称为耦合
String是一个immutable(不可修改)的对象,当需要很多复杂的字符串操作来产生一个结果字符串时,为防止系统开销过大,可使用StringBuffer对象,这是一个可以不断修改的对象。最后用toString()产生一个String对象就可以
- 可拓展性
- 通过接口来实现聚合
- 通过容器来实现灵活性
- Hash表
- 框架加数据
- 以框架+数据来提高可拓展性
- 命令的解析是否可以脱离if-else
- 定义一个Handler来处理命令
- 用Hash表来保存命令和Handler之间的关系
- 城堡游戏
- 以框架+数据来提高可拓展性
//Game(Main).java
package