------- android培训、java培训、期待与您交流! ----------
面向对象
类、对象
定义类
[修饰符] class 类名
{
0~N个Field定义
0~N个方法定义
0~N个构造器定义
0~N个初始化块
}
Field定义的语法:
[修饰符] 类型 field名 [= 默认值];
方法定义
[修饰符] 返回值类型 方法名(形参列表)
{
执行性的代码
}
构造器定义
[修饰符] 构造器名(形参列表)
{
执行性的代码
}
初始化块
[修饰符] {
执行性的代码
}
执行性代码(赋值、输出、循环、分支),只有3个位置可以放。其他地方不能放代码。
实例初始化块(没static),会被还原到每个构造器的前面。
定义实例field时指定的初始值, 也会被变成一条赋值语句,被还原到每个构造器的前面。
实例初始化块 —— 每次创建对象之前,会先执行实例初始化块,再执行构造器。
类初始化块(没static)
定义类field时指定的初始值, 也会被变成一条赋值语句,被还原到类初始化块中
类初始化块 —— 一个JVM,类只加载、初始化一次,类将一直长驻堆内存。
类初始化块,只会在类初始化的时候执行,因此运行一次Java程序,类初始化块只会执行一次。
有了类,类可干什么?
A。 可定义变量。
B。 可创建对象。
C。 可访问static的Field
D。 可调用static修饰的方法
有了对象之后,对象可干什么?
A。 可访问实例Field。
B。 可调用实例方法。
构造器:初始化对象。
编程的角度来,你要创建对象,new 构造器();——只要我调用任何构造器,总会得到一个对象。
你调用不同的构造器,得到的对象,被初始化的Field是不同的。
如果你要调用实例方法、或访问实例Field,你需要先有对象。
为了先有对象,必须用new 任何一个构造器();
▲ 包装类
包装类的作用:Java语言中,一切都是对象,但是有例外:8个基本数据类型不是对象,因此在很多时候非常不方便。
为此,Java提供为8个基本类型提供了对应的包装类:
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean
包装类如何使用?
JDK1.5 , 新增了2个功能:自动装箱、自动拆箱。
自动装箱: 当我们把一个基本类型的值(20),赋值给引用变量时候,系统可以自动将它“包装”为相应的包装类的实例
程序需要对象时,如果给的只是一个基本类型的值,系统会将它自动装箱为包装类的实例
达到的效果:有了自动装箱之后,基本类型的值可以当成对象用——其实是【假相】。
自动拆箱: 当我们需要一个基本类型的值时,但实际上传入的包装类的对象。系统会自动把对象“剥”开,得到它的值。
达到的效果:有了自动拆箱之后,包装类的对象可当成基本类型的值用——其实是【假相】。
自动装箱
基本类型的值 ←→ 包装类的实例
自动拆箱
事实上,包装类比基本类型更好用——基本类型能做的事情,包装类也能做。
但包装类能做的,基本类型不一定能做,比如要赋一个null值。
★ 包装类额外功能:
将字符串,转换相应的基本类型的值。
每个包装类,都提供了static修饰的parseXxx(String),用于将字符串转为相应的基本类型的值。
所有基本类型的值,都可通过 + "" 转换为String。
▲ 对象的方法
Object的方法。
一切类都是Object的子类,因此,任意对象都可作为Object的实例。
任意Java对象,都可以调用Object定义的方法。
- getClass() :返回该对象的类。
- toString():
- hashCode():集合里讲。
- equals(Object obj)
toString()
——该方法对程序效果几乎没有任何的作用!
当需要输出一个对象时,或需要把对象当成String使用时,实际上系统会自动调用该对象toString()所返回的字符串。
Object默认实现了toString()方法,
总是返回 类名@hashCode()返回值
在很多时候,我们需要去重写toString()方法,该方法返回的字符串应该能描述该对象的内部状态(field值)。
equals()
Java首先提供了==来判断两个引用变量是否相等。
== 要求两个引用变量必须指向同一个对象才算相等。
但equals()就不同了,也用于判断两个对象是否相等。
默认情况下,你调用的equals()方法是Object提供了,Object所提供的equals()方法的判断标准,与==的判断标准是完全一样。
可以这样说, Object提供的equals()几乎不能直接用于判断两个对象是否相等。
如果你要根据自己的标准来判断两个对象是否相等,就需要重写equals()方法。
Java在提供了String类,已经重写equals()方法,
标准是:只要两个字符串包含相同的字符序列,这两个字符串通过equals()比较就会返回true.
因此:如果以后我们要判断两个String所包含的字符序列是否相等,应该通过equals()进行比较。
▲ static
static的作用是“标志”,有static修饰的是属于类;没有static属于对象。
static可修饰哪些东西?
局部变量不能用static修饰,局部变量只在方法中有效,根本不可能属于类、实例之类,因此局部变量不能用static修饰。
static只能修饰类中定义的成员:
1. field —— 类变量(静态变量)
2. 方法 —— 类方法(静态方法)
3. 构造器 —— 只有构造器不能用static!
4. 初始化块 —— 类初始化块 (静态初始化)
5. 内部类 —— 静态内部类。
所有用static修饰的,都属于类。
关于static,有一个重要原则:【static修饰的成员,不能访问非static成员】
▲ final
final可修饰类、方法、变量(一切变量, 类变量、实例变量、局部变量)。
final与abstract是互斥,永远不可能同时出现。
当final修饰变量时,总则是:该变量被赋值之后,再也不能重新赋值。
★ final修饰实例变量:
对于普通的实例变量,程序员可以不指定初始值。如果程序员不指定,系统会为之分配默认的初始值。
final修饰实例变量【必须】由程序员指定初始值,可以(而且只)在3个地方指定初始值:
1. 构造器 —— 这个才是本质。
2. 初始化块。
3. 定义该field指定初始值。
——但最多、而且必须在一个地方指定初始值。
★ final修饰类变量:
final修饰类变量【必须】由程序员指定初始值,可以(而且只)在2个地方指定初始值:
1. 类初始化块(静态初始化)。 ——这个才是本质
2. 定义该field指定初始值。
★ final修饰局部变量
局部变量,不使用final修饰,就需要由程序员来指定初始值。
用final修饰,还是由程序员指定初始值。
只是,现在使用final修饰之后,局部变量只能赋一次值。
★ final修饰的“宏替换”的变量
所谓“宏替换”,就是“查找、替换”。
如果一个变量(不管是类变量、实例变量、局部变量),满足如下3个条件:
1. 用final修饰。
2. 定义时就指定了初始值。
3. 并且该初始值在编译时就可以确定。
【典型的,只要用到了变量,该初始值就不能在编译时确定】
这个变量就“彻底”消失了,该变量不存在!
String类:
字符串池的东西。
只要程序中用到了任何“字符串直接量”,该直接量就会被放入一个“房间”(池、Pool),下次如果再用到该直接量时,就直接从池中取出来用。
★ final方法,
让该方法不能被它子类重写。
final修饰一个方法的好处:不让它被子类重写,避免了该方法被子类破坏。
final与protected很少(有可能)同时修饰一个方法:
—— protected修饰方法,可以在子类中被方法,因此通常是希望被子类重写。 而final又不允许被重写,因此通常很少同时出现。
final与private放在一起修饰方法,没有任何意义。
—— private修饰的方法本来只能在当前类中访问,因此该方法不可能被子类重写,所以final修饰没有意义。
★ final类
final方法只是保护单个的方法不被破坏!
final类用于保护整个类都不会被破坏——final类干脆不允许派生子类。
子类继承父类 父类派生子类
Java里已经包含了String\包装类等大量的final类。
▲ abstract
abstract与final互斥。
abstract可以修饰类、方法。
abstract修饰类, 我们叫抽象类。
abstract修饰方法, 我们叫抽象方法。
抽象类与普通类的区别: 【有得有失】。
得到:得到可拥有抽象方法的能力——但并不代表一定要有抽象方法。
但如果一个类包含了抽象方法,该类必须定义成抽象类。
失去:创建对象的能力。抽象类不能创建对象。
抽象方法:
- 用abstract修饰。
- 只有方法签名,没有方法体。
抽象类的构造器,并非用于创建对象;但主要用于被子类的构造器所调用。
例子: Aniaml、AnimalTest
抽象类的作用,正是用于被子类继承。
【当一个类继承了抽象类之后,要么实现父类所有的抽象方法;要么它自己也是抽象类。】
抽象类的作用是什么?
抽象类可与模板模式结合使用。
考虑如下场景: 当我们完成某件事情,实现这件事情的大部分算法都可以确定下来(可用代码编写出来)。
但这个算法有一个点或小部分,可能存在变化,暂时无法确定——此时就考虑用模板模式。
定义方法,该方法实现所有现在能确定的算法,将暂时无法的部分定义成抽象方法 —— 这就相当一个模板。
这些抽象方法,等到该模板的子类来实现。
例子:SpeedMeter
▲ 接口
它也代表一种引用类型。
从某个角度来看, 接口相当于一个彻底抽象的类。
抽象类:有得有失,主要体现为可拥有抽象方法。
接口只能拥有抽象方法 —— 接口是一种彻底抽象。
★ 定义接口的语法:
[修饰符] interface 接口名 extends 父接口1,父接口2...
{
0~N个field —— 只能是public static final修饰的field。
0~N个方法 —— 只能是public abstract方法。
0~N个内部类|接口|枚举 —— 只能是public static修饰。
}
接口名一般用形容词。接口名与类名的命名规范是相同:每个单词的首字母大写。
接口只能定义3个成员(构造器和初始化块)。 类中可以定义5个成员。
接口定义的是多个类共同的行为规范,这些行为是与外部交流的通道,这就意味着接口里通常是定义一组public的方法。
【接口体现了规范与实现分离的设计。】
【注意】: 接口体现的是一种规范!
规范应该公开,供大家来遵守,因此你们发现接口中成员都是public修饰。
设计接口比设计类难得多!接口体现的是一种规范!
因此接口中方法,需要公开供很多人使用,且不能经常发生变化!!
从写代码的角度来看,写接口比写类更简单。
★ 接口的作用:
1. 可以定义变量, 通常都是将它的实现类的实例复制该该变量。
2. 可通过接口来调用静态Field。
3. 接口可用于被实现。
从逻辑上看,实现接口,其实就相当于继承了该接口。
——同样会从接口中继承得到 public static final修饰的field、抽象方法。
Java是单继承,每个类最多只能有一个直接父类。
——这种单继承,虽然简单,但不够灵活。
Java一个类,可以同时实现多个接口——这样就弥补单继承的不足。
【当一个类实现了接口之后,要么实现该接口所有的抽象方法;要么它自己也是抽象类。】