------- android培训、java培训、期待与您交流! ----------
方法详解
方法存在所属性。
★ 一旦将一个方法定义在一个类里,如果用static修饰了,这个方法属于该类本身,否则属于这个类的实例.
有static修饰,属于类;没有static修饰,属于对象。
★ 方法不能独立执行,必须要有调用者.(如:类.方法、对象.方法)
方法必须由属主调用。谁的方法,谁调用。
没有static的方法,属于对象,由对象调用。
有static的方法,属于类,由类调用。
★ 方法不能独立定义,只能定义在类里.
方法要么属于一个类(有static),要么属于一个对象(无static)
static在Java中的作用: 它只是标志,有static的修饰的东西,就属于类本身;没有static修饰的,就属于对象。
调用方法时,总是需要主调(主语调用者),如果方法有static修饰,要用类做主调。
如果方法没有static修饰,要用对象做主调。
在有些时候,可以省略主调——
如果在没有static修饰的方法中调用另一个方法,默认可以省略this.前缀。
如果在没static修饰的方法中调用另一个没static的方法,默认可以省略this.前缀。
如果在没static修饰的方法中调用另一个有static方法,默认可以省略 类名.前缀。
如果在有static修饰的方法中调用另一个有static方法,默认可以省略 类名.前缀。
如果在有static修饰的方法中调用另一个没static方法——这种调用是不允许的。
★ 形参个数可变的参数。
如果在形参类型的后面添加...,表明该参数个数可以是0~N个。即调用时,可传入多个参数值。
个数可变的参数,本质就是数组!
String ... , 完全相当于 String[]
调用方法时,定义为形参类型...比定义数组类型的参数更方便。
形参个数可变的参数的限制: 必须位于形参列表的最后。
——因此一个方法中,最多只能有一个形参个数可变的参数。
★ Java方法的传参机制。
Java只支持一种传参模式: 值传递。
值传递的含义是:当我们传入参数时,实际上并不是把参数本身传入,而是只传入该参数的副本(copy)。
因此当我们在方法中对参数进行任何修改时,对参数本书并不会有任何影响。
★ 递归方法
所谓递归:就是指,在方法里再次调用自身。
递归,相当于一个隐式的循环。递归,也要有一个结束点。
比如有一个数列: f(1) = 2; f(2)=5;
f(n) = f(n+2) - 2 * f(n+1);
计算f(10)的值。
【注意:】递归一定要有结束点。
可以考虑对 f(n) = f(n+2) - 2 * f(n+1) 公式进行变换。定义一个新的N, 让N = n + 2.
公式可改为: f(N-2) = f(N) - 2 * f(N-1)
f(N) = 2 * f(N-1) + f(N-2)
★ 方法重载
口诀: 2同1不同。
同一个类中、方法名相同,形参列表不同(只考虑形参的类型与顺序)。
修饰符不同不算!返回值类型不同,也不算。
Java调用方法时,要确定一个方法,需要3个东西:
1. 调用者
2. 方法名。
3. 参数列表。
▲ 变量详解
↗ 类变量(有static修饰),属于类,用于描述类本身的状态
成员变量
↗ ↘ 实例变量,属于各个实例,用于描述实例的状态
变量
↗ 方法局部变量: 在方法中声明的变量
↘
局部变量 → 代码块的局部变量, 在代码块中声明的变量。
↘ 形参
类变量,用描述类的状态;实例变量,用于描述实例的状态。
如果要访问类变量(获取值, 也包括对它赋值),必须指定类作为主调。
如果要访问实例变量(获取值, 也包括对它赋值),必须指定的对象作为主调。
Java程序的. ,有点类似于汉语的 "的".
★ 成员变量可以不指定初始值.
如果程序员没有为成员变量指定初始值,系统会为之分配默认的初始值,规则为,
与动态初始化数组时,数组元素的初始化规则完全相同。
类变量,并不是属于对象,而是属于类本身,当系统初始化类时,就会为类变量分配内存、并指定初始值。
垃圾语法:【Java允许通过对象来访问类变量、也可调用类方法】
以后你们编程时,永远不准通过对象来访问类变量、也不准通过对象来调用类方法。应该用类名。
但以后,如果你在面试、考试...遇到有人通过对象来访问类变量、通过对象来调用类方法,
首先你先用把对象换成类名——这才是本质。
成员变量的作用域:
类变量:从类加载、并初始化开始有效, 直到该类被销毁时无效。
如果是官方JVM,JVM不退出,类信息就不会被销毁。
尽量少用static修饰的变量。
实例变量:有多少个对象,就有多少个实例变量。每个对象都会持有自己的实例变量。
从对象加载、并初始化开始有效, 直到该对象被销毁时无效。
只要一个对象没有引用变量指向它,它就变成垃圾,垃圾回收器将会在接下来时间里回收它。
★ 局部变量
1. 局部变量必须由于程序员显式赋值。
如果程序员没有赋值,该局部变量不能被使用。
2. 局部变量的作用域很短, 所有局部变量都保存在各自的方法栈区中。
形参:方法结束,就失效。
方法局部变量:从声明它开始有效,方法结束,就失效。
代码块局部变量:从声明它开始有效,代码块结束,就失效。
总则:优先使用作用域更小的变量,好处:
1. 节省内存。
2. 更符合程序“高内聚、低耦合”的原则。
▲ 封装
面向对象有3大特征: 封装、继承、多态。
★ 什么是封装(合理隐藏、合理暴露)
1. 要类内部的实现细节隐藏起来。
2. 将一些操作方法暴露出来。
封装,可以避免直接访问对象的内部细节,从而造成破坏。
通过合理的暴露,可以简化对象的操作。
★ Java的封装,靠的修饰符。
private : 类访问权限。
如果一个成员(field、方法、内部类、构造器)用private修饰,表明该成员只能在当前类中被访问。
【彻底隐藏】
默认 : 包访问权限。
如果一个成员(field、方法、内部类、构造器)不用访问控制符修饰,
表明该成员只能在当前类或当前包中被访问。
【部分隐藏】
protected: 子类访问权限
如果一个成员(field、方法、内部类、构造器)用protected访问控制符修饰,
表明该成员可以在当前类、当前包、该类的子类中被访问。
【部分暴露】
public: 公开访问权限
如果一个成员(field、方法、内部类、构造器)用public访问控制符修饰,
表明该成员可以在任意地方被访问。
【彻底暴露】
★ 包
主要用于解决类名冲突的问题。
世界上无数公司都会定义类,势必造成类名重复。
为了解决类名重复的问题,Java要求在类的前面增加一个“前缀”——这就是所谓的包。
Java建议,包名,用公司的 域名倒写.项目名 —— 包名应该是所有字母小写。
要一个类加包,要做如下两件事情:
- 在源代码中使用package定义包。
- 把生成的class文件放在对应的文件结构下。
如果一个类位于指定包下,那么该类的完整类名应该 包名+类名, 光写类名是错的。
以后用该类时,就需要写包名+类名
为了避免在源代码中总要写包名+类名,就可用import来导入包。
import有两种格式:
import java.util.*; *只能代表类,用于表示导入指定包的所有类。
import 包名.类名 —— 只导入一个类。
Java源代码默认会 import java.lang.*
▲ 包
解决命名空间问题。
要为一个类定义包:
1. 要在源代码中添加package 包名;
2. 将生成class文件放在包对应的文件结构下。
可以在编译Java程序时,增加一个-d 选项,编译器将会为我们自动创建文件结构、并将class文件放入指定的文件结构下。
一个类有了包之后,我们要注意:
类名 = [包名 + 类名]
[包名 + 类名]才是完整的类名。
为了避免在编写Java程序时,总需要写包名,可用import来导入指定类,或指定包的所有类。
import - 可以让不写包名。
import语句中的*只能代表任意类。
★ 静态导入
import static - 可以不写类名。
import static可用于导入指定类的指定static Field,或static方法。
也可用于导入指定类的全部static修饰成员。
import static语句中的*只能代表指定类的静态成员。
import的作用是在源代码中省略写包名。
import static的作用是在源代码中省略写类名。
▲ 封装
1. 把内部实现细节进行隐藏,合理隐藏。
2. 把操作方法进行暴露, 合理暴露。
private 类访问权限(只能在当前类中被访问) , 彻底隐藏。
默认 包访问权限(只能在当前类、当前包中被方法), 部分隐藏。
proteced 子类访问权限(可以在当前类、当前包、子类中被访问)、部分暴露。
public 公开访问权限(在任意地方被访问) , 彻底暴露。
javadoc - 生成API文档——就是所写类的使用说明书。
默认只提取public、protect修饰的类、方法、Field、构造器等成员之前(在成员体内无效)的文档注释。
为什么只提取public、protect修饰的成员之前的文档注释呢?
因为所有的使用说明书都只介绍暴露出来的东西。 Java程序中只有用proteced 、public修饰的才算暴露,所以javadoc默认只提取它们之前的文档注释。
当你查API文档时,如果没有看到public、private、protect等修饰符,API文档中成员是public修饰。
建议:
1. 将所有field用private修饰。
这就是将该field彻底隐藏在该类里面。
2. 为每个field提供public修饰getter和setter方法,
允许程序通过getter方法来访问该field的值,并通过setter方法去修改该field的值。
3. 如果只需要在当前类使用的、为其他方法提供支持的工具方法,也应该使用private修饰。
4. 如果有些方法,希望被子类重写,该方法应该声明为protected。
▲ 构造器
构造器的作用: 用于初始化对象。
必须通过new 构造器来调用它。
所有类,都有构造器!
如果我们为类写了构造器,自然就有构造器。
如果我们没有写构造器, 系统会自动提供一个无参数的构造器。
★ 构造器重载
方法重载: 2同1不同
构造器重载与方法重载几乎是相似的:构造器名必然相同;形参列表不同。
示例: Wolf.java
this关键词有两个作用:
1. this引用 —— 如果在构造器中,代表构造器正在初始化的对象。
如果在方法中,代表正在调用该方法的对象。
this引用总是代表该类的实例。
2. this调用:
只能用在构造器、而且必须是构造器中第一条代码。
this调用总是调用当前类中重载的构造器。this调用到底调用哪个构造器,取决于传入的参数值。
this调用更好! 因此它可以直接复用已有的构造器。
1. 代码更简洁。 2. 更有利于以后维护。提高了可维护性。
▲ 继承
面向对象的3大特征: 封装、继承、多态
理解继承:
1. Java的继承,并不是现实生活中的继承。
Java的继承是一种类与类之间关系,是一种“由一般到特殊”的关系。子类对象一种特殊的父类实例。
《Thinking In Java》, “is a” 关系。
父类 - 大类 ;子类 - 小类。
2. Java的继承,是单继承。 extends后最多只有一个类。
每个类,只能有一个直接父类。但实际上能有很多的间接的父类。
示例:Animal 、 Bird 、Sparrow
如果你没有显式指定extends ,默认是extends Object。
"所有类都是Object的子类"
当子类extends父类之后,就可以自动从父类那里“获取”如下东西(这就是为啥叫继承):
1. field。
2. 方法。
★ 重写(覆盖 override)父类的方法
当子类从父类那里继承得到某个方法,但又不适用子类的行为,此时就要重写父类的方法。
方法重写: 2同2小1大
2同:方法名相同、形参列表相同。
2小:返回值类型相同或更小(要么类型相同,要么返回值类型是子类)
声明抛出的异常类型相同或更小。
1大:访问控制权限必须相同或更大。
如果是方法重写,建议在方法前增加【@Override】修饰。
★ super
super有两个作用:
A super限定:
强制指定访问从父类继承得到的field、调用从父类继承得到方法。
super.Field
super.方法名
super限定的作用:
如果当前类中定义了与父类同名的field、重写了父类的方法
——如果在该类中直接访问该field、调用方法,默认是访问当前类的field、调用当前类的方法。
B super调用
super调用是显式调用父类的构造器。 到底调用哪个构造器,取决于传入的参数。
this调用是当前类中重载的构造器。 到底调用哪个构造器,取决于传入的参数。
super调用只能在构造器用,而且必须位于第一行。
this调用与super调用不能同时出现。
【规则:】 子类构造器【总】会调用父类的构造器。只调用一次!
1. 如果子类构造器中,没有使用super调用,子类构造器会自动调用父类无参数的构造器。
2. 如果子类构造器中有使用super调用,根据传入的参数显示调用父类对应的构造器。
【注意】: 子类构造器总会调用父类的构造器。
当父类没有无参数的构造器时,子类的构造器中【必须显式】地用super调用父类有参数的构造器。
否则:子类构造器会自动(隐式)调用父类无参数的构造器——必然导致找不到构造器的错误。
【体会】
Plant → Apple → RedFuji
总结: 无论你创建哪个对象,系统最先调用的总是Object类的无参数构造器。
▲ 多态
变态:当做同一件事情时,某个个体表现成“变异”的行为特征,就是变态。
多态的定义:同一个类型的变量,调用同一个的方法(做同一件事情),呈现出多种行为,这就是多态。
对于一个引用变量来说,可以认为有两个类型:
1. 编译时类型。声明该变量时所用的类型,就是编译时类型。
对于编译器来讲,编译器只管变量的编译时类型,与运行时类型无关。
2. 运行时类型(实际类型)。该变量实际所指向的对象的类型,就是运行时类型。
★强转
有一个新的运算符: 强制类型转换。 ()
限制: 强制类型转换(),只能在两个类型具有继承关系才可转换,否则编译时就会报错。
必须运行时类型真正是要强转的类型,才可以强转成功;否则会引发ClassCastException
★ instanceof 运算符
变量 instanceof 类型,
当该变量所引用的对象,是后面的类、或子类的实例时,就会返回true。否则返回false。
限制: instanceof,只能在两个类型具有继承关系才可判断,否则编译时就会报错